root/src/dps8/threadz.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. lock_simh
  2. unlock_simh
  3. lock_libuv
  4. unlock_libuv
  5. test_libuv_lock
  6. get_rmw_lock
  7. lock_rmw
  8. lock_mem_rd
  9. lock_mem_wr
  10. unlock_rmw
  11. unlock_mem
  12. unlock_mem_force
  13. lock_ptr
  14. unlock_ptr
  15. lock_scu
  16. unlock_scu
  17. lock_iom
  18. unlock_iom
  19. lock_tst
  20. unlock_tst
  21. test_tst_lock
  22. rtsched_thread
  23. pthread_create_with_cpu_policy
  24. createCPUThread
  25. stopCPUThread
  26. cpuRunningWait
  27. sleepCPU
  28. wakeCPU
  29. createIOMThread
  30. iomInterruptWait
  31. iomInterruptDone
  32. iomDoneWait
  33. setIOMInterrupt
  34. iomRdyWait
  35. createChnThread
  36. chnConnectWait
  37. chnConnectDone
  38. setChnConnect
  39. chnRdyWait
  40. initThreadz
  41. setSignals

   1 /*
   2  * vim: filetype=c:tabstop=4:ai:expandtab
   3  * SPDX-License-Identifier: ICU
   4  * scspell-id: fe96c073-f62f-11ec-bf37-80ee73e9b8e7
   5  *
   6  * ---------------------------------------------------------------------------
   7  *
   8  * Copyright (c) 2013-2019 Charles Anthony
   9  * Copyright (c) 2021-2022 The DPS8M Development Team
  10  *
  11  * All rights reserved.
  12  *
  13  * This software is made available under the terms of the ICU
  14  * License, version 1.8.1 or later.  For more details, see the
  15  * LICENSE.md file at the top-level directory of this distribution.
  16  *
  17  * ---------------------------------------------------------------------------
  18  */
  19 
  20 //
  21 // Thread Wrappers
  22 //
  23 
  24 #include <unistd.h>
  25 #include <stdlib.h>
  26 #include <signal.h>
  27 
  28 #include "dps8.h"
  29 #include "dps8_sys.h"
  30 #include "dps8_cpu.h"
  31 #include "dps8_faults.h"
  32 #include "dps8_iom.h"
  33 #include "dps8_utils.h"
  34 
  35 #include "threadz.h"
  36 #if ( defined ( __FreeBSD__ ) || defined ( __FreeBSD_kernel__ ) || defined (  __OpenBSD__) )
  37 # include <pthread_np.h>
  38 #endif /* FreeBSD || OpenBSD */
  39 
  40 #if defined ( __HAIKU__ )
  41 # include <OS.h>
  42 # undef pthread_setname_np
  43 # define pthread_setname_np(x,y) rename_thread(find_thread(NULL),y)
  44 #endif /* Haiku */
  45 
  46 //
  47 // Resource locks
  48 //
  49 
  50 // scp library serializer
  51 
  52 #ifdef IO_ASYNC_PAYLOAD_CHAN_THREAD
  53 pthread_cond_t iomCond;
  54 pthread_mutex_t iom_start_lock;
  55 #endif
  56 
  57 #ifndef QUIET_UNUSED
  58 void lock_simh (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  59   {
  60     pthread_mutex_lock (& simh_lock);
  61   }
  62 
  63 void unlock_simh (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  64   {
  65     pthread_mutex_unlock (& simh_lock);
  66   }
  67 #endif
  68 
  69 // libuv library serializer
  70 
  71 static pthread_mutex_t libuv_lock;
  72 
  73 void lock_libuv (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  74   {
  75     pthread_mutex_lock (& libuv_lock);
  76   }
  77 
  78 void unlock_libuv (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  79   {
  80     pthread_mutex_unlock (& libuv_lock);
  81   }
  82 
  83 #ifdef TESTING
  84 bool test_libuv_lock (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  85   {
  86     //sim_debug (DBG_TRACE, & cpu_dev, "test_libuv_lock\n");
  87     int rc;
  88     rc = pthread_mutex_trylock (& libuv_lock);
  89     if (rc)
  90       {
  91          // couldn't lock; presumably already
  92          return true;
  93       }
  94     // lock acquired, it wasn't locked
  95     rc = pthread_mutex_unlock (& libuv_lock);
  96     if (rc)
  97       sim_printf ("test_libuv_lock pthread_mutex_lock libuv_lock %d\n", rc);
  98     return false;
  99   }
 100 #endif
 101 
 102 // Memory serializer
 103 
 104 //   addrmods RMW lock
 105 //     Read()
 106 //     Write()
 107 //
 108 //   CPU -- reset locks
 109 //
 110 //   core_read/core_write locks
 111 //
 112 //   read_operand/write operand RMW lock
 113 //     Read()
 114 //     Write()
 115 //
 116 //  IOM
 117 
 118 // mem_lock -- memory atomicity lock
 119 // rmw_lock -- big R/M/W cycle lock
 120 
 121 #ifndef LOCKLESS
 122 pthread_rwlock_t mem_lock = PTHREAD_RWLOCK_INITIALIZER;
 123 static __thread bool have_mem_lock = false;
 124 static __thread bool have_rmw_lock = false;
 125 
 126 bool get_rmw_lock (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 127   {
 128     return have_rmw_lock;
 129   }
 130 
 131 void lock_rmw (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 132   {
 133     if (have_rmw_lock)
 134       {
 135         sim_warn ("%s: Already have RMW lock\n", __func__);
 136         return;
 137       }
 138     if (have_mem_lock)
 139       {
 140         sim_warn ("%s: Already have memory lock\n", __func__);
 141         return;
 142       }
 143     int rc= pthread_rwlock_wrlock (& mem_lock);
 144     if (rc)
 145       sim_printf ("%s pthread_rwlock_rdlock mem_lock %d\n", __func__, rc);
 146     have_mem_lock = true;
 147     have_rmw_lock = true;
 148   }
 149 
 150 void lock_mem_rd (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 151   {
 152     // If the big RMW lock is on, do nothing.
 153     if (have_rmw_lock)
 154       return;
 155 
 156     if (have_mem_lock)
 157       {
 158         sim_warn ("%s: Already have memory lock\n", __func__);
 159         return;
 160       }
 161     int rc= pthread_rwlock_rdlock (& mem_lock);
 162     if (rc)
 163       sim_printf ("%s pthread_rwlock_rdlock mem_lock %d\n", __func__, rc);
 164     have_mem_lock = true;
 165   }
 166 
 167 void lock_mem_wr (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 168   {
 169     // If the big RMW lock is on, do nothing.
 170     if (have_rmw_lock)
 171       return;
 172 
 173     if (have_mem_lock)
 174       {
 175         sim_warn ("%s: Already have memory lock\n", __func__);
 176         return;
 177       }
 178     int rc= pthread_rwlock_wrlock (& mem_lock);
 179     if (rc)
 180       sim_printf ("%s pthread_rwlock_wrlock mem_lock %d\n", __func__, rc);
 181     have_mem_lock = true;
 182   }
 183 
 184 void unlock_rmw (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 185   {
 186     if (! have_mem_lock)
 187       {
 188         sim_warn ("%s: Don't have memory lock\n", __func__);
 189         return;
 190       }
 191     if (! have_rmw_lock)
 192       {
 193         sim_warn ("%s: Don't have RMW lock\n", __func__);
 194         return;
 195       }
 196 
 197     int rc = pthread_rwlock_unlock (& mem_lock);
 198     if (rc)
 199       sim_printf ("%s pthread_rwlock_ublock mem_lock %d\n", __func__, rc);
 200     have_mem_lock = false;
 201     have_rmw_lock = false;
 202   }
 203 
 204 void unlock_mem (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 205   {
 206     if (have_rmw_lock)
 207       return;
 208     if (! have_mem_lock)
 209       {
 210         sim_warn ("%s: Don't have memory lock\n", __func__);
 211         return;
 212       }
 213 
 214     int rc = pthread_rwlock_unlock (& mem_lock);
 215     if (rc)
 216       sim_printf ("%s pthread_rwlock_ublock mem_lock %d\n", __func__, rc);
 217     have_mem_lock = false;
 218   }
 219 
 220 void unlock_mem_force (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 221   {
 222     if (have_mem_lock)
 223       {
 224         int rc = pthread_rwlock_unlock (& mem_lock);
 225         if (rc)
 226           sim_printf ("%s pthread_rwlock_unlock mem_lock %d\n", __func__, rc);
 227       }
 228     have_mem_lock = false;
 229     have_rmw_lock = false;
 230   }
 231 #endif
 232 
 233 // local serializer
 234 
 235 void lock_ptr (pthread_mutex_t * lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 236   {
 237     int rc;
 238     rc = pthread_mutex_lock (lock);
 239     if (rc)
 240       sim_printf ("lock_ptr %d\n", rc);
 241   }
 242 
 243 void unlock_ptr (pthread_mutex_t * lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 244   {
 245     //sim_debug (DBG_TRACE, & cpu_dev, "unlock_scu\n");
 246     int rc;
 247     rc = pthread_mutex_unlock (lock);
 248     if (rc)
 249       sim_printf ("unlock_ptr %d\n", rc);
 250   }
 251 
 252 // SCU serializer
 253 
 254 static pthread_mutex_t scu_lock;
 255 
 256 void lock_scu (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 257   {
 258     //sim_debug (DBG_TRACE, & cpu_dev, "lock_scu\n");
 259     int rc;
 260     rc = pthread_mutex_lock (& scu_lock);
 261     if (rc)
 262       sim_printf ("lock_scu pthread_spin_lock scu %d\n", rc);
 263   }
 264 
 265 void unlock_scu (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 266   {
 267     //sim_debug (DBG_TRACE, & cpu_dev, "unlock_scu\n");
 268     int rc;
 269     rc = pthread_mutex_unlock (& scu_lock);
 270     if (rc)
 271       sim_printf ("unlock_scu pthread_spin_lock scu %d\n", rc);
 272   }
 273 
 274 // IOM serializer
 275 
 276 static pthread_mutex_t iom_lock;
 277 
 278 void lock_iom (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 279   {
 280     int rc;
 281     rc = pthread_mutex_lock (& iom_lock);
 282     if (rc)
 283       sim_printf ("%s pthread_spin_lock iom %d\n", __func__, rc);
 284   }
 285 
 286 void unlock_iom (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 287   {
 288     int rc;
 289     rc = pthread_mutex_unlock (& iom_lock);
 290     if (rc)
 291       sim_printf ("%s pthread_spin_lock iom %d\n", __func__, rc);
 292   }
 293 
 294 // Debugging tool
 295 
 296 #ifdef TESTING
 297 static pthread_mutex_t tst_lock = PTHREAD_MUTEX_INITIALIZER;
 298 
 299 void lock_tst (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 300   {
 301     //sim_debug (DBG_TRACE, & cpu_dev, "lock_tst\n");
 302     int rc;
 303     rc = pthread_mutex_lock (& tst_lock);
 304     if (rc)
 305       sim_printf ("lock_tst pthread_mutex_lock tst_lock %d\n", rc);
 306   }
 307 
 308 void unlock_tst (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 309   {
 310     //sim_debug (DBG_TRACE, & cpu_dev, "unlock_tst\n");
 311     int rc;
 312     rc = pthread_mutex_unlock (& tst_lock);
 313     if (rc)
 314       sim_printf ("unlock_tst pthread_mutex_lock tst_lock %d\n", rc);
 315   }
 316 
 317 // assertion
 318 
 319 bool test_tst_lock (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 320   {
 321     //sim_debug (DBG_TRACE, & cpu_dev, "test_tst_lock\n");
 322     int rc;
 323     rc = pthread_mutex_trylock (& tst_lock);
 324     if (rc)
 325       {
 326          // couldn't lock; presumably already
 327          return true;
 328       }
 329     // lock acquired, it wasn't locked
 330     rc = pthread_mutex_unlock (& tst_lock);
 331     if (rc)
 332       sim_printf ("test_tst_lock pthread_mutex_lock tst_lock %d\n", rc);
 333     return false;
 334   }
 335 #endif
 336 
 337 #ifdef __APPLE__
 338 
 339 /*
 340  * Request RT scheduling class and ask the Mach kernel to
 341  * not preempt our threads when running under Darwin/macOS.
 342  */
 343 
 344 int
 345 rtsched_thread(pthread_t pthread)
     /* [previous][next][first][last][top][bottom][index][help] */
 346 {
 347   int kr;
 348 
 349   mach_timebase_info_data_t timebase_info;
 350   mach_timebase_info(&timebase_info);
 351 
 352   const uint64_t NANOS_PER_MSEC = 1000000ULL;
 353   double mach_clock2abs =
 354       ((double)timebase_info.denom / (double)timebase_info.numer) * NANOS_PER_MSEC;
 355 
 356   thread_time_constraint_policy_data_t tpolicy;
 357 
 358   tpolicy.period      = 0;
 359   tpolicy.computation = (uint32_t)( 5 * mach_clock2abs);
 360   tpolicy.constraint  = (uint32_t)(10 * mach_clock2abs);
 361   tpolicy.preemptible = FALSE;
 362 
 363   mach_port_t target_thread = pthread_mach_thread_np(pthread);
 364 
 365   kr = thread_policy_set(
 366           target_thread,
 367           THREAD_TIME_CONSTRAINT_POLICY,
 368           (thread_policy_t)&tpolicy,
 369           THREAD_TIME_CONSTRAINT_POLICY_COUNT);
 370 
 371   if (kr != KERN_SUCCESS)
 372     {
 373       sim_warn("\rMach thread_policy_set error %d at %s[%s:%d]\r\n",
 374                (int)kr, __FILE__, __func__, __LINE__);
 375       return 1;
 376     }
 377 
 378 # ifdef TESTING
 379   sim_warn("\rMach realtime thread scheduling policy request was successful.\r\n");
 380 # endif /* ifdef TESTING */
 381   return 0;
 382 }
 383 #endif /* ifdef __APPLE__ */
 384 
 385 ////////////////////////////////////////////////////////////////////////////////
 386 //
 387 // CPU threads
 388 //
 389 ////////////////////////////////////////////////////////////////////////////////
 390 
 391 //
 392 // main thread
 393 //   createCPUThread
 394 //
 395 // CPU thread
 396 //   cpuRunningWait
 397 //   sleepCPU
 398 //
 399 // SCU thread
 400 //   wakeCPU
 401 //
 402 // cpuThread:
 403 //
 404 //    while (1)
 405 //      {
 406 //        cpuRunningWait
 407 //        compute...
 408 //        dis:  sleepCPU
 409 //      }
 410 
 411 struct cpuThreadz_t cpuThreadz [N_CPU_UNITS_MAX];
 412 
 413 // Create a thread with Mach CPU policy
 414 
 415 #ifdef __APPLE__
 416 int pthread_create_with_cpu_policy(
     /* [previous][next][first][last][top][bottom][index][help] */
 417         pthread_t *restrict thread,
 418         int policy_group,
 419         const pthread_attr_t *restrict attr,
 420         void *(*start_routine)(void *), void *restrict arg)
 421 {
 422 # ifdef TESTING
 423   sim_msg ("\rAffinity policy group %d requested for thread.\r\n", policy_group);
 424 # endif /* ifdef TESTING */
 425   thread_affinity_policy_data_t policy_data = { policy_group };
 426   int rv = pthread_create_suspended_np(thread, attr, start_routine, arg);
 427   mach_port_t mach_thread = pthread_mach_thread_np(*thread);
 428   if (rv != 0)
 429     {
 430       return rv;
 431     }
 432   thread_policy_set(
 433           mach_thread,
 434           THREAD_AFFINITY_POLICY,
 435           (thread_policy_t)&policy_data,
 436           THREAD_AFFINITY_POLICY_COUNT);
 437   thread_resume(mach_thread);
 438   return 0;
 439 }
 440 #endif /* ifdef __APPLE__ */
 441 
 442 // Create CPU thread
 443 
 444 void createCPUThread (uint cpuNum)
     /* [previous][next][first][last][top][bottom][index][help] */
 445   {
 446     int rc;
 447     struct cpuThreadz_t * p = & cpuThreadz[cpuNum];
 448     if (p->run)
 449       return;
 450     cpu_reset_unit_idx (cpuNum, false);
 451     p->cpuThreadArg = (int) cpuNum;
 452     // initialize run/stop switch
 453     rc = pthread_mutex_init (& p->runLock, NULL);
 454     if (rc)
 455       sim_printf ("createCPUThread pthread_mutex_init runLock %d\n", rc);
 456     rc = pthread_cond_init (& p->runCond, NULL);
 457     if (rc)
 458       sim_printf ("createCPUThread pthread_cond_init runCond %d\n", rc);
 459 
 460     p->run = true;
 461 
 462     // initialize DIS sleep
 463 #ifdef USE_MONOTONIC
 464 # if defined __APPLE__ || ! defined (CLOCK_MONOTONIC)
 465     p->sleepClock = CLOCK_REALTIME;
 466     rc = pthread_cond_init (& p->sleepCond, NULL);
 467 # else
 468     rc = pthread_condattr_init (& p->sleepCondAttr);
 469     if (rc)
 470       sim_printf ("createCPUThread pthread_condattr_init sleepCond %d\n", rc);
 471 
 472     rc = pthread_condattr_setclock (& p->sleepCondAttr, CLOCK_MONOTONIC);
 473     if (rc) {
 474       //sim_printf ("createCPUThread pthread_condattr_setclock  sleepCond %d\n", rc);
 475       p->sleepClock = CLOCK_REALTIME;
 476     } else {
 477       p->sleepClock = CLOCK_MONOTONIC;
 478     }
 479 # endif // ! APPLE
 480     rc = pthread_cond_init (& p->sleepCond, & p->sleepCondAttr);
 481 #else
 482     rc = pthread_cond_init (& p->sleepCond, NULL);
 483 #endif
 484     if (rc)
 485       sim_printf ("createCPUThread pthread_cond_init sleepCond %d\n", rc);
 486 
 487 #ifdef __APPLE__
 488     rc = pthread_create_with_cpu_policy(
 489             & p->cpuThread,
 490             cpuNum,
 491             NULL,
 492             cpu_thread_main,
 493             & p->cpuThreadArg);
 494 #else
 495     rc = pthread_create(
 496             & p->cpuThread,
 497             NULL,
 498             cpu_thread_main,
 499             & p->cpuThreadArg);
 500 #endif /* ifdef __APPLE__ */
 501     if (rc)
 502       sim_printf ("createCPUThread pthread_create %d\n", rc);
 503 
 504     char nm [17];
 505     sprintf (nm, "CPU %c", 'a' + cpuNum);
 506 #ifndef __NetBSD__
 507 # if ( defined ( __FreeBSD__ ) || defined ( __FreeBSD_kernel__ ) || defined ( __OpenBSD__ ) )
 508     pthread_set_name_np (p->cpuThread, nm);
 509 # else
 510 #  ifdef __APPLE__
 511     pthread_setname_np (nm);
 512 #  else
 513 #   ifndef _AIX
 514 #    ifndef __gnu_hurd__
 515     pthread_setname_np (p->cpuThread, nm);
 516 #    endif /* ifndef __gnu_hurd__ */
 517 #   endif /* ifndef _AIX */
 518 #  endif /* ifdef __APPLE__ */
 519 # endif /* ifdef FreeBSD || OpenBSD */
 520 #endif /* ifndef __NetBSD__ */
 521 
 522 #ifdef AFFINITY
 523     if (cpus[cpuNum].set_affinity)
 524       {
 525         cpu_set_t cpuset;
 526         CPU_ZERO (& cpuset);
 527         CPU_SET (cpus[cpuNum].affinity, & cpuset);
 528         int s = pthread_setaffinity_np (p->cpuThread, sizeof (cpu_set_t), & cpuset);
 529         if (s)
 530           sim_printf ("pthread_setaffinity_np %u on CPU %u returned %d\n",
 531                       cpus[cpuNum].affinity, cpuNum, s);
 532       }
 533 #endif /* ifdef AFFINITY */
 534 
 535 #ifdef __APPLE__
 536 # ifdef USE_RTSCHED_THREAD
 537     if (rtsched_thread(p->cpuThread) != 0)
 538       sim_printf ("\rrtsched_thread failed %s[%s:%d]!\r\n",
 539                   __func__, __FILE__, __LINE__);
 540 # endif /* ifdef USE_RTSCHED_THREAD */
 541 #endif /* ifdef __APPLE__ */
 542   }
 543 
 544 void stopCPUThread(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 545   {
 546     struct cpuThreadz_t * p = & cpuThreadz[current_running_cpu_idx];
 547     p->run = false;
 548     pthread_exit(NULL);
 549   }
 550 
 551 // Called by CPU thread to block on run/sleep
 552 
 553 #ifdef THREADZ
 554 void cpuRunningWait (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 555   {
 556     int rc;
 557     struct cpuThreadz_t * p = & cpuThreadz[current_running_cpu_idx];
 558     if (p->run)
 559       return;
 560     rc = pthread_mutex_lock (& p->runLock);
 561     if (rc)
 562       sim_printf ("cpuRunningWait pthread_mutex_lock %d\n", rc);
 563     while (! p->run)
 564       {
 565         rc = pthread_cond_wait (& p->runCond, & p->runLock);
 566         if (rc)
 567           sim_printf ("cpuRunningWait pthread_cond_wait %d\n", rc);
 568      }
 569     rc = pthread_mutex_unlock (& p->runLock);
 570     if (rc)
 571       sim_printf ("cpuRunningWait pthread_mutex_unlock %d\n", rc);
 572   }
 573 #endif
 574 
 575 // Called by CPU thread to sleep until time up or signaled
 576 // Return time left
 577 unsigned long  sleepCPU (unsigned long usec) {
     /* [previous][next][first][last][top][bottom][index][help] */
 578   int rc;
 579   struct cpuThreadz_t * p = & cpuThreadz[current_running_cpu_idx];
 580   struct timespec startTime, absTime;
 581 
 582 #ifdef USE_MONOTONIC
 583   clock_gettime (p->sleepClock, & startTime);
 584 #else
 585   clock_gettime (CLOCK_REALTIME, & startTime);
 586 #endif
 587   absTime = startTime;
 588   int64_t nsec = ((int64_t) usec) * 1000 + (int64_t)startTime.tv_nsec;
 589   absTime.tv_nsec = nsec % 1000000000;
 590   absTime.tv_sec += nsec / 1000000000;
 591 
 592   rc = pthread_cond_timedwait (& p->sleepCond, & scu_lock, & absTime);
 593 
 594   if (rc == ETIMEDOUT) {
 595     return 0;
 596   }
 597 
 598   if (rc) {
 599     sim_printf ("sleepCPU pthread_cond_timedwait rc %ld  usec %ld TR %lu CPU %lu\n", (long) rc, (long) usec, (unsigned long) cpu.rTR, (unsigned long) current_running_cpu_idx);
 600   }
 601 
 602   struct timespec newTime;
 603   struct timespec delta;
 604 #ifdef USE_MONOTONIC
 605   clock_gettime (p->sleepClock, & newTime);
 606 #else
 607   clock_gettime (CLOCK_REALTIME, & newTime);
 608 #endif
 609   timespec_diff (& absTime, & newTime, & delta);
 610 
 611   if (delta.tv_nsec < 0)
 612     return 0; // safety
 613   return (unsigned long) delta.tv_nsec / 1000;
 614 }
 615 
 616 // Called to wake sleeping CPU; such as interrupt during DIS
 617 
 618 void wakeCPU (uint cpuNum)
     /* [previous][next][first][last][top][bottom][index][help] */
 619   {
 620     int rc;
 621     struct cpuThreadz_t * p = & cpuThreadz[cpuNum];
 622 
 623     rc = pthread_cond_signal (& p->sleepCond);
 624     if (rc)
 625       sim_printf ("wakeCPU pthread_cond_signal %d\n", rc);
 626   }
 627 
 628 #ifdef IO_THREADZ
 629 ////////////////////////////////////////////////////////////////////////////////
 630 //
 631 // IOM threads
 632 //
 633 ////////////////////////////////////////////////////////////////////////////////
 634 
 635 // main thread
 636 //   createIOMThread    create thread
 637 //   iomRdyWait         wait for IOM started
 638 //   setIOMInterrupt    signal IOM to start
 639 //   iomDoneWait        wait for IOM done
 640 // IOM thread
 641 //   iomInterruptWait   IOM thread wait for work
 642 //   iomInterruptDone   IOM thread signal done working
 643 //
 644 //   IOM thread
 645 //     while (1)
 646 //       {
 647 //         iomInterruptWake
 648 //         work...
 649 //         iomInterruptDone
 650 //      }
 651 
 652 struct iomThreadz_t iomThreadz [N_IOM_UNITS_MAX];
 653 
 654 // Create IOM thread
 655 
 656 void createIOMThread (uint iomNum)
     /* [previous][next][first][last][top][bottom][index][help] */
 657   {
 658     int rc;
 659     struct iomThreadz_t * p = & iomThreadz[iomNum];
 660 # ifdef tdbg
 661     p->inCnt = 0;
 662     p->outCnt = 0;
 663 # endif
 664     p->iomThreadArg = (int) iomNum;
 665 
 666     p->ready = false;
 667     // initialize interrupt wait
 668     p->intr = false;
 669     rc = pthread_mutex_init (& p->intrLock, NULL);
 670     if (rc)
 671       sim_printf ("createIOMThread pthread_mutex_init intrLock %d\n", rc);
 672     rc = pthread_cond_init (& p->intrCond, NULL);
 673     if (rc)
 674       sim_printf ("createIOMThread pthread_cond_init intrCond %d\n", rc);
 675 
 676 # ifdef __APPLE__
 677     rc = pthread_create_with_cpu_policy(
 678             & p->iomThread,
 679             iomNum,
 680             NULL,
 681             iom_thread_main,
 682             & p->iomThreadArg);
 683 # else
 684     rc = pthread_create(
 685             & p->iomThread,
 686             NULL,
 687             iom_thread_main,
 688             & p->iomThreadArg);
 689 # endif /* ifdef __APPLE__ */
 690     if (rc)
 691       sim_printf ("createIOMThread pthread_create %d\n", rc);
 692 
 693     char nm [17];
 694     sprintf (nm, "IOM %c", 'a' + iomNum);
 695 # if ( defined ( __FreeBSD__ ) || defined ( __FreeBSD_kernel__ ) || defined ( __OpenBSD__ ) )
 696     pthread_setname_np (p->iomThread, nm);
 697 # else
 698     pthread_set_name_np (p->iomThread, nm);
 699 # endif /* FreeBSD || OpenBSD */
 700   }
 701 
 702 // Called by IOM thread to block until CIOC call
 703 
 704 void iomInterruptWait (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 705   {
 706     int rc;
 707     struct iomThreadz_t * p = & iomThreadz[this_iom_idx];
 708     rc = pthread_mutex_lock (& p->intrLock);
 709     if (rc)
 710       sim_printf ("iomInterruptWait pthread_mutex_lock %d\n", rc);
 711     p -> ready = true;
 712     while (! p->intr)
 713       {
 714         rc = pthread_cond_wait (& p->intrCond, & p->intrLock);
 715         if (rc)
 716           sim_printf ("iomInterruptWait pthread_cond_wait %d\n", rc);
 717       }
 718 # ifdef tdbg
 719     p->outCnt++;
 720     if (p->inCnt != p->outCnt)
 721       sim_printf ("iom thread %d in %d out %d\n", this_iom_idx,
 722                   p->inCnt, p->outCnt);
 723 # endif
 724   }
 725 
 726 // Called by IOM thread to signal CIOC complete
 727 
 728 void iomInterruptDone (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 729   {
 730     int rc;
 731     struct iomThreadz_t * p = & iomThreadz[this_iom_idx];
 732     p->intr = false;
 733     rc = pthread_cond_signal (& p->intrCond);
 734     if (rc)
 735       sim_printf ("iomInterruptDone pthread_cond_signal %d\n", rc);
 736     rc = pthread_mutex_unlock (& p->intrLock);
 737     if (rc)
 738       sim_printf ("iomInterruptDone pthread_mutex_unlock %d\n", rc);
 739   }
 740 
 741 // Called by CPU thread to wait for iomInterruptDone
 742 
 743 void iomDoneWait (uint iomNum)
     /* [previous][next][first][last][top][bottom][index][help] */
 744   {
 745     int rc;
 746     struct iomThreadz_t * p = & iomThreadz[iomNum];
 747     rc = pthread_mutex_lock (& p->intrLock);
 748     if (rc)
 749       sim_printf ("iomDoneWait pthread_mutex_lock %d\n", rc);
 750     while (p->intr)
 751       {
 752         rc = pthread_cond_wait (& p->intrCond, & p->intrLock);
 753         if (rc)
 754           sim_printf ("iomDoneWait pthread_cond_wait %d\n", rc);
 755       }
 756     rc = pthread_mutex_unlock (& p->intrLock);
 757     if (rc)
 758       sim_printf ("iomDoneWait pthread_mutex_unlock %d\n", rc);
 759   }
 760 
 761 // Signal CIOC to IOM thread
 762 
 763 void setIOMInterrupt (uint iomNum)
     /* [previous][next][first][last][top][bottom][index][help] */
 764   {
 765     int rc;
 766     struct iomThreadz_t * p = & iomThreadz[iomNum];
 767     rc = pthread_mutex_lock (& p->intrLock);
 768     if (rc)
 769       sim_printf ("setIOMInterrupt pthread_mutex_lock %d\n", rc);
 770     while (p->intr)
 771       {
 772         rc = pthread_cond_wait(&p->intrCond, &p->intrLock);
 773         if (rc)
 774           sim_printf ("setIOMInterrupt pthread_cond_wait intrLock %d\n", rc);
 775       }
 776 # ifdef tdbg
 777     p->inCnt++;
 778 # endif
 779     p->intr = true;
 780     rc = pthread_cond_signal (& p->intrCond);
 781     if (rc)
 782       sim_printf ("setIOMInterrupt pthread_cond_signal %d\n", rc);
 783     rc = pthread_mutex_unlock (& p->intrLock);
 784     if (rc)
 785       sim_printf ("setIOMInterrupt pthread_mutex_unlock %d\n", rc);
 786   }
 787 
 788 // Wait for IOM thread to initialize
 789 
 790 void iomRdyWait (uint iomNum)
     /* [previous][next][first][last][top][bottom][index][help] */
 791   {
 792     struct iomThreadz_t * p = & iomThreadz[iomNum];
 793     while (! p -> ready)
 794       sim_usleep (10000);
 795    }
 796 
 797 ////////////////////////////////////////////////////////////////////////////////
 798 //
 799 // Channel threads
 800 //
 801 ////////////////////////////////////////////////////////////////////////////////
 802 
 803 // main thread
 804 //   createChnThread    create thread
 805 // IOM thread
 806 //   chnRdyWait         wait for channel started
 807 //   setChnConnect      signal channel to start
 808 // Channel thread
 809 //   chnConnectWait     Channel thread wait for work
 810 //   chnConnectDone     Channel thread signal done working
 811 //
 812 //   IOM thread
 813 //     while (1)
 814 //       {
 815 //         iomInterruptWake
 816 //         work...
 817 //         iomInterruptDone
 818 //      }
 819 struct chnThreadz_t chnThreadz [N_IOM_UNITS_MAX] [MAX_CHANNELS];
 820 
 821 // Create channel thread
 822 
 823 void createChnThread (uint iomNum, uint chnNum, const char * devTypeStr)
     /* [previous][next][first][last][top][bottom][index][help] */
 824   {
 825     int rc;
 826     struct chnThreadz_t * p = & chnThreadz[iomNum][chnNum];
 827     p->chnThreadArg = (int) (chnNum + iomNum * MAX_CHANNELS);
 828 
 829 # ifdef tdbg
 830     p->inCnt = 0;
 831     p->outCnt = 0;
 832 # endif
 833     p->ready = false;
 834     // initialize interrupt wait
 835     p->connect = false;
 836     rc = pthread_mutex_init (& p->connectLock, NULL);
 837     if (rc)
 838       sim_printf ("createChnThread pthread_mutex_init connectLock %d\n", rc);
 839     rc = pthread_cond_init (& p->connectCond, NULL);
 840     if (rc)
 841       sim_printf ("createChnThread pthread_cond_init connectCond %d\n", rc);
 842 
 843 # ifdef __APPLE__
 844     rc = pthread_create_with_cpu_policy(
 845             & p->chnThread,
 846             iomNum
 847             NULL,
 848             chan_thread_main,
 849             & p->chnThreadArg);
 850 # else
 851     rc = pthread_create(
 852             & p->chnThread,
 853             NULL,
 854             chan_thread_main,
 855             & p->chnThreadArg);
 856 # endif /* ifdef __APPLE__ */
 857     if (rc)
 858       sim_printf ("createChnThread pthread_create %d\n", rc);
 859 
 860     char nm [17];
 861     sprintf (nm, "chn %c/%u %s", 'a' + iomNum, chnNum, devTypeStr);
 862 # if ( defined ( __FreeBSD__ ) || defined ( __FreeBSD_kernel__ ) || defined ( __OpenBSD__ ) )
 863     pthread_setname_np (p->chnThread, nm);
 864 # else
 865     pthread_set_name_np (p->chnThread, nm);
 866 # endif /* FreeBSD || OpenBSD */
 867   }
 868 
 869 // Called by channel thread to block until I/O command presented
 870 
 871 void chnConnectWait (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 872   {
 873     int rc;
 874     struct chnThreadz_t * p = & chnThreadz[this_iom_idx][this_chan_num];
 875 
 876     rc = pthread_mutex_lock (& p->connectLock);
 877     if (rc)
 878       sim_printf ("chnConnectWait pthread_mutex_lock %d\n", rc);
 879     p -> ready = true;
 880     while (! p->connect)
 881       {
 882         rc = pthread_cond_wait (& p->connectCond, & p->connectLock);
 883         if (rc)
 884           sim_printf ("chnConnectWait pthread_cond_wait %d\n", rc);
 885       }
 886 # ifdef tdbg
 887     p->outCnt++;
 888     if (p->inCnt != p->outCnt)
 889       sim_printf ("chn thread %d in %d out %d\n", this_chan_num,
 890                   p->inCnt, p->outCnt);
 891 # endif
 892   }
 893 
 894 // Called by channel thread to signal I/O complete
 895 
 896 void chnConnectDone (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 897   {
 898     int rc;
 899     struct chnThreadz_t * p = & chnThreadz[this_iom_idx][this_chan_num];
 900     p->connect = false;
 901     rc = pthread_cond_signal (& p->connectCond);
 902     if (rc)
 903       sim_printf ("chnInterruptDone pthread_cond_signal %d\n", rc);
 904     rc = pthread_mutex_unlock (& p->connectLock);
 905     if (rc)
 906       sim_printf ("chnConnectDone pthread_mutex_unlock %d\n", rc);
 907   }
 908 
 909 // Signal I/O presented to channel thread
 910 
 911 void setChnConnect (uint iomNum, uint chnNum)
     /* [previous][next][first][last][top][bottom][index][help] */
 912   {
 913     int rc;
 914     struct chnThreadz_t * p = & chnThreadz[iomNum][chnNum];
 915     rc = pthread_mutex_lock (& p->connectLock);
 916     if (rc)
 917       sim_printf ("setChnConnect pthread_mutex_lock %d\n", rc);
 918     while (p->connect)
 919       {
 920         rc = pthread_cond_wait(&p->connectCond, &p->connectLock);
 921         if (rc)
 922           sim_printf ("setChnInterrupt pthread_cond_wait connectLock %d\n", rc);
 923       }
 924 # ifdef tdbg
 925     p->inCnt++;
 926 # endif
 927     p->connect = true;
 928     rc = pthread_cond_signal (& p->connectCond);
 929     if (rc)
 930       sim_printf ("setChnConnect pthread_cond_signal %d\n", rc);
 931     rc = pthread_mutex_unlock (& p->connectLock);
 932     if (rc)
 933       sim_printf ("setChnConnect pthread_mutex_unlock %d\n", rc);
 934   }
 935 
 936 // Block until channel thread ready
 937 
 938 void chnRdyWait (uint iomNum, uint chnNum)
     /* [previous][next][first][last][top][bottom][index][help] */
 939   {
 940     struct chnThreadz_t * p = & chnThreadz[iomNum][chnNum];
 941     while (! p -> ready)
 942       sim_usleep (10000);
 943    }
 944 #endif
 945 
 946 void initThreadz (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 947   {
 948 #ifdef IO_THREADZ
 949     // chnThreadz is sparse; make sure 'started' is false
 950     memset (chnThreadz, 0, sizeof (chnThreadz));
 951 #endif
 952 
 953 #ifndef LOCKLESS
 954     //pthread_rwlock_init (& mem_lock, PTHREAD_PROCESS_PRIVATE);
 955     have_mem_lock = false;
 956     have_rmw_lock = false;
 957 #endif
 958 #if ( defined ( __FreeBSD__ ) || defined ( __FreeBSD_kernel__ ) || defined ( __OpenBSD__ ) )
 959     pthread_mutexattr_t scu_attr;
 960     pthread_mutexattr_init(&scu_attr);
 961 # ifndef __OpenBSD__
 962     pthread_mutexattr_settype(&scu_attr, PTHREAD_MUTEX_ADAPTIVE_NP);
 963 # endif
 964     pthread_mutex_init (& scu_lock, &scu_attr);
 965 #else
 966     pthread_mutex_init (& scu_lock, NULL);
 967 #endif /* FreeBSD || OpenBSD */
 968     pthread_mutexattr_t iom_attr;
 969     pthread_mutexattr_init(& iom_attr);
 970     pthread_mutexattr_settype(& iom_attr, PTHREAD_MUTEX_RECURSIVE);
 971 
 972     pthread_mutex_init (& iom_lock, & iom_attr);
 973 
 974     pthread_mutexattr_t libuv_attr;
 975     pthread_mutexattr_init(& libuv_attr);
 976     pthread_mutexattr_settype(& libuv_attr, PTHREAD_MUTEX_RECURSIVE);
 977 
 978     pthread_mutex_init (& libuv_lock, & libuv_attr);
 979 
 980 #ifdef IO_ASYNC_PAYLOAD_CHAN_THREAD
 981     pthread_cond_init (& iomCond, NULL);
 982     pthread_mutex_init (& iom_start_lock, NULL);
 983 #endif
 984   }
 985 
 986 // Set up per-thread signal handlers
 987 
 988 void int_handler (int signal);
 989 
 990 void setSignals (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 991   {
 992 #ifndef __MINGW64__
 993 # ifndef __MINGW32__
 994     struct sigaction act;
 995     memset (& act, 0, sizeof (act));
 996     act.sa_handler = int_handler;
 997     act.sa_flags = 0;
 998     sigaction (SIGINT, & act, NULL);
 999     sigaction (SIGTERM, & act, NULL);
1000 # endif /* __MINGW32__ */
1001 #endif /* __MINGW64__ */
1002   }
1003 
1004 
1005 
1006 
1007 
1008 
1009 
1010 
1011 
1012 
1013 

/* [previous][next][first][last][top][bottom][index][help] */