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

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