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\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\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\n", __func__);
 127         return;
 128       }
 129     if (have_mem_lock)
 130       {
 131         sim_warn ("%s: Already have memory lock\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\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\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\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\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\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\n", __func__);
 180         return;
 181       }
 182     if (! have_rmw_lock)
 183       {
 184         sim_warn ("%s: Don't have RMW lock\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\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\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\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\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\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\n");
 237     int rc;
 238     rc = pthread_mutex_unlock (lock);
 239     if (rc)
 240       sim_printf ("unlock_ptr %d\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\n");
 250     int rc;
 251     rc = pthread_mutex_lock (& scu_lock);
 252     if (rc)
 253       sim_printf ("lock_scu pthread_spin_lock scu %d\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\n");
 259     int rc;
 260     rc = pthread_mutex_unlock (& scu_lock);
 261     if (rc)
 262       sim_printf ("unlock_scu pthread_spin_lock scu %d\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\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\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\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\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\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\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\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\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\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\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\n", rc);
 428 
 429     rc = pthread_mutex_init (& p->runLock, NULL);
 430     if (rc)
 431       sim_printf ("createCPUThread pthread_mutex_init runLock %d\n", rc);
 432 
 433     rc = pthread_cond_init (& p->runCond, NULL);
 434     if (rc)
 435       sim_printf ("createCPUThread pthread_cond_init runCond %d\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\n", rc);
 449 
 450     rc = pthread_condattr_setclock (& p->sleepCondAttr, CLOCK_MONOTONIC);
 451     if (rc) {
 452       //sim_printf ("createCPUThread pthread_condattr_setclock  sleepCond %d\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\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\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\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\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\n", rc);
 520      }
 521     rc = pthread_mutex_unlock (& p->runLock);
 522     if (rc)
 523       sim_printf ("cpuRunningWait pthread_mutex_unlock %d\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\n", rc);
 547 
 548   p->sleeping = true;
 549   rc = pthread_cond_timedwait (& p->sleepCond, & p->sleepLock, & absTime);
 550   p->sleeping = false; //-V519
 551 
 552   int rc2 = pthread_mutex_unlock (& p->sleepLock);
 553   if (rc2)
 554     sim_printf ("sleepCPU pthread_mutex_unlock sleepLock %d\n", rc2);
 555 
 556   if (rc == ETIMEDOUT) {
 557     return 0;
 558   }
 559 
 560   if (rc) {
 561     cpu_state_t * cpup = _cpup;
 562     sim_printf ("sleepCPU pthread_cond_timedwait rc %ld  usec %ld TR %lu CPU %lu\n",
 563                 (long) rc, (long) usec, (unsigned long) cpu.rTR,
 564                 (unsigned long) current_running_cpu_idx);
 565   }
 566 
 567   struct timespec newTime;
 568   struct timespec delta;
 569 #if defined(USE_MONOTONIC)
 570   clock_gettime (p->sleepClock, & newTime);
 571 #else
 572   clock_gettime (CLOCK_REALTIME, & newTime);
 573 #endif /* if defined(USE_MONOTONIC) */
 574   timespec_diff (& absTime, & newTime, & delta);
 575 
 576   if (delta.tv_nsec < 0)
 577     return 0; // safety
 578   return (unsigned long) delta.tv_nsec / 1000L;
 579 }
 580 
 581 // Called to wake sleeping CPU; such as interrupt during DIS
 582 
 583 void wakeCPU (uint cpuNum)
     /* [previous][next][first][last][top][bottom][index][help] */
 584   {
 585     int rc;
 586     struct cpuThreadz_t * p = & cpuThreadz[cpuNum];
 587 
 588     rc = pthread_mutex_lock (& p->sleepLock);
 589     if (rc)
 590       sim_printf ("sleepCPU pthread_mutex_lock sleepLock %d\n", rc);
 591 
 592     if (p->sleeping) {
 593       rc = pthread_cond_signal (& p->sleepCond);
 594       if (rc)
 595         sim_printf ("wakeCPU pthread_cond_signal %d\n", rc);
 596     }
 597 
 598     int rc2 = pthread_mutex_unlock (& p->sleepLock);
 599     if (rc2)
 600       sim_printf ("sleepCPU pthread_mutex_unlock sleepLock %d\n", rc2);
 601   }
 602 
 603 #if defined(IO_THREADZ)
 604 ////////////////////////////////////////////////////////////////////////////////
 605 //
 606 // IOM threads
 607 //
 608 ////////////////////////////////////////////////////////////////////////////////
 609 
 610 // main thread
 611 //   createIOMThread    create thread
 612 //   iomRdyWait         wait for IOM started
 613 //   setIOMInterrupt    signal IOM to start
 614 //   iomDoneWait        wait for IOM done
 615 // IOM thread
 616 //   iomInterruptWait   IOM thread wait for work
 617 //   iomInterruptDone   IOM thread signal done working
 618 //
 619 //   IOM thread
 620 //     while (1)
 621 //       {
 622 //         iomInterruptWake
 623 //         work...
 624 //         iomInterruptDone
 625 //      }
 626 
 627 struct iomThreadz_t iomThreadz [N_IOM_UNITS_MAX];
 628 
 629 // Create IOM thread
 630 
 631 void createIOMThread (uint iomNum)
     /* [previous][next][first][last][top][bottom][index][help] */
 632   {
 633     int rc;
 634     struct iomThreadz_t * p = & iomThreadz[iomNum];
 635 # if defined(tdbg)
 636     p->inCnt = 0;
 637     p->outCnt = 0;
 638 # endif
 639     p->iomThreadArg = (int) iomNum;
 640 
 641     p->ready = false;
 642     // initialize interrupt wait
 643     p->intr = false;
 644     rc = pthread_mutex_init (& p->intrLock, NULL);
 645     if (rc)
 646       sim_printf ("createIOMThread pthread_mutex_init intrLock %d\n", rc);
 647     rc = pthread_cond_init (& p->intrCond, NULL);
 648     if (rc)
 649       sim_printf ("createIOMThread pthread_cond_init intrCond %d\n", rc);
 650 
 651 # if defined(__APPLE__)
 652     rc = pthread_create_with_cpu_policy(
 653             & p->iomThread,
 654             iomNum,
 655             NULL,
 656             iom_thread_main,
 657             & p->iomThreadArg);
 658 # else
 659     rc = pthread_create(
 660             & p->iomThread,
 661             NULL,
 662             iom_thread_main,
 663             & p->iomThreadArg);
 664 # endif /* if defined(__APPLE__) */
 665     if (rc)
 666       sim_printf ("createIOMThread pthread_create %d\n", rc);
 667   }
 668 
 669 // Called by IOM thread to block until CIOC call
 670 
 671 void iomInterruptWait (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 672   {
 673     int rc;
 674     struct iomThreadz_t * p = & iomThreadz[this_iom_idx];
 675     rc = pthread_mutex_lock (& p->intrLock);
 676     if (rc)
 677       sim_printf ("iomInterruptWait pthread_mutex_lock %d\n", rc);
 678     p -> ready = true;
 679     while (! p->intr)
 680       {
 681         rc = pthread_cond_wait (& p->intrCond, & p->intrLock);
 682         if (rc)
 683           sim_printf ("iomInterruptWait pthread_cond_wait %d\n", rc);
 684       }
 685 # if defined(tdbg)
 686     p->outCnt++;
 687     if (p->inCnt != p->outCnt)
 688       sim_printf ("iom thread %d in %d out %d\n", this_iom_idx,
 689                   p->inCnt, p->outCnt);
 690 # endif
 691   }
 692 
 693 // Called by IOM thread to signal CIOC complete
 694 
 695 void iomInterruptDone (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 696   {
 697     int rc;
 698     struct iomThreadz_t * p = & iomThreadz[this_iom_idx];
 699     p->intr = false;
 700     rc = pthread_cond_signal (& p->intrCond);
 701     if (rc)
 702       sim_printf ("iomInterruptDone pthread_cond_signal %d\n", rc);
 703     rc = pthread_mutex_unlock (& p->intrLock);
 704     if (rc)
 705       sim_printf ("iomInterruptDone pthread_mutex_unlock %d\n", rc);
 706   }
 707 
 708 // Called by CPU thread to wait for iomInterruptDone
 709 
 710 void iomDoneWait (uint iomNum)
     /* [previous][next][first][last][top][bottom][index][help] */
 711   {
 712     int rc;
 713     struct iomThreadz_t * p = & iomThreadz[iomNum];
 714     rc = pthread_mutex_lock (& p->intrLock);
 715     if (rc)
 716       sim_printf ("iomDoneWait pthread_mutex_lock %d\n", rc);
 717     while (p->intr)
 718       {
 719         rc = pthread_cond_wait (& p->intrCond, & p->intrLock);
 720         if (rc)
 721           sim_printf ("iomDoneWait pthread_cond_wait %d\n", rc);
 722       }
 723     rc = pthread_mutex_unlock (& p->intrLock);
 724     if (rc)
 725       sim_printf ("iomDoneWait pthread_mutex_unlock %d\n", rc);
 726   }
 727 
 728 // Signal CIOC to IOM thread
 729 
 730 void setIOMInterrupt (uint iomNum)
     /* [previous][next][first][last][top][bottom][index][help] */
 731   {
 732     int rc;
 733     struct iomThreadz_t * p = & iomThreadz[iomNum];
 734     rc = pthread_mutex_lock (& p->intrLock);
 735     if (rc)
 736       sim_printf ("setIOMInterrupt pthread_mutex_lock %d\n", rc);
 737     while (p->intr)
 738       {
 739         rc = pthread_cond_wait(&p->intrCond, &p->intrLock);
 740         if (rc)
 741           sim_printf ("setIOMInterrupt pthread_cond_wait intrLock %d\n", rc);
 742       }
 743 # if defined(tdbg)
 744     p->inCnt++;
 745 # endif
 746     p->intr = true;
 747     rc = pthread_cond_signal (& p->intrCond);
 748     if (rc)
 749       sim_printf ("setIOMInterrupt pthread_cond_signal %d\n", rc);
 750     rc = pthread_mutex_unlock (& p->intrLock);
 751     if (rc)
 752       sim_printf ("setIOMInterrupt pthread_mutex_unlock %d\n", rc);
 753   }
 754 
 755 // Wait for IOM thread to initialize
 756 
 757 void iomRdyWait (uint iomNum)
     /* [previous][next][first][last][top][bottom][index][help] */
 758   {
 759     struct iomThreadz_t * p = & iomThreadz[iomNum];
 760     while (! p -> ready)
 761       sim_usleep (10000);
 762    }
 763 
 764 ////////////////////////////////////////////////////////////////////////////////
 765 //
 766 // Channel threads
 767 //
 768 ////////////////////////////////////////////////////////////////////////////////
 769 
 770 // main thread
 771 //   createChnThread    create thread
 772 // IOM thread
 773 //   chnRdyWait         wait for channel started
 774 //   setChnConnect      signal channel to start
 775 // Channel thread
 776 //   chnConnectWait     Channel thread wait for work
 777 //   chnConnectDone     Channel thread signal done working
 778 //
 779 //   IOM thread
 780 //     while (1)
 781 //       {
 782 //         iomInterruptWake
 783 //         work...
 784 //         iomInterruptDone
 785 //      }
 786 struct chnThreadz_t chnThreadz [N_IOM_UNITS_MAX] [MAX_CHANNELS];
 787 
 788 // Create channel thread
 789 
 790 void createChnThread (uint iomNum, uint chnNum, const char * devTypeStr)
     /* [previous][next][first][last][top][bottom][index][help] */
 791   {
 792     int rc;
 793     struct chnThreadz_t * p = & chnThreadz[iomNum][chnNum];
 794     p->chnThreadArg = (int) (chnNum + iomNum * MAX_CHANNELS);
 795 
 796 # if defined(tdbg)
 797     p->inCnt = 0;
 798     p->outCnt = 0;
 799 # endif
 800     p->ready = false;
 801     // initialize interrupt wait
 802     p->connect = false;
 803     rc = pthread_mutex_init (& p->connectLock, NULL);
 804     if (rc)
 805       sim_printf ("createChnThread pthread_mutex_init connectLock %d\n", rc);
 806     rc = pthread_cond_init (& p->connectCond, NULL);
 807     if (rc)
 808       sim_printf ("createChnThread pthread_cond_init connectCond %d\n", rc);
 809 
 810 # if defined(__APPLE__)
 811     rc = pthread_create_with_cpu_policy(
 812             & p->chnThread,
 813             iomNum
 814             NULL,
 815             chan_thread_main,
 816             & p->chnThreadArg);
 817 # else
 818     rc = pthread_create(
 819             & p->chnThread,
 820             NULL,
 821             chan_thread_main,
 822             & p->chnThreadArg);
 823 # endif /* if defined(__APPLE__) */
 824     if (rc)
 825       sim_printf ("createChnThread pthread_create %d\n", rc);
 826   }
 827 
 828 // Called by channel thread to block until I/O command presented
 829 
 830 void chnConnectWait (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 831   {
 832     int rc;
 833     struct chnThreadz_t * p = & chnThreadz[this_iom_idx][this_chan_num];
 834 
 835     rc = pthread_mutex_lock (& p->connectLock);
 836     if (rc)
 837       sim_printf ("chnConnectWait pthread_mutex_lock %d\n", rc);
 838     p -> ready = true;
 839     while (! p->connect)
 840       {
 841         rc = pthread_cond_wait (& p->connectCond, & p->connectLock);
 842         if (rc)
 843           sim_printf ("chnConnectWait pthread_cond_wait %d\n", rc);
 844       }
 845 # if defined(tdbg)
 846     p->outCnt++;
 847     if (p->inCnt != p->outCnt)
 848       sim_printf ("chn thread %d in %d out %d\n", this_chan_num,
 849                   p->inCnt, p->outCnt);
 850 # endif
 851   }
 852 
 853 // Called by channel thread to signal I/O complete
 854 
 855 void chnConnectDone (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 856   {
 857     int rc;
 858     struct chnThreadz_t * p = & chnThreadz[this_iom_idx][this_chan_num];
 859     p->connect = false;
 860     rc = pthread_cond_signal (& p->connectCond);
 861     if (rc)
 862       sim_printf ("chnInterruptDone pthread_cond_signal %d\n", rc);
 863     rc = pthread_mutex_unlock (& p->connectLock);
 864     if (rc)
 865       sim_printf ("chnConnectDone pthread_mutex_unlock %d\n", rc);
 866   }
 867 
 868 // Signal I/O presented to channel thread
 869 
 870 void setChnConnect (uint iomNum, uint chnNum)
     /* [previous][next][first][last][top][bottom][index][help] */
 871   {
 872     int rc;
 873     struct chnThreadz_t * p = & chnThreadz[iomNum][chnNum];
 874     rc = pthread_mutex_lock (& p->connectLock);
 875     if (rc)
 876       sim_printf ("setChnConnect pthread_mutex_lock %d\n", rc);
 877     while (p->connect)
 878       {
 879         rc = pthread_cond_wait(&p->connectCond, &p->connectLock);
 880         if (rc)
 881           sim_printf ("setChnInterrupt pthread_cond_wait connectLock %d\n", rc);
 882       }
 883 # if defined(tdbg)
 884     p->inCnt++;
 885 # endif
 886     p->connect = true;
 887     rc = pthread_cond_signal (& p->connectCond);
 888     if (rc)
 889       sim_printf ("setChnConnect pthread_cond_signal %d\n", rc);
 890     rc = pthread_mutex_unlock (& p->connectLock);
 891     if (rc)
 892       sim_printf ("setChnConnect pthread_mutex_unlock %d\n", rc);
 893   }
 894 
 895 // Block until channel thread ready
 896 
 897 void chnRdyWait (uint iomNum, uint chnNum)
     /* [previous][next][first][last][top][bottom][index][help] */
 898   {
 899     struct chnThreadz_t * p = & chnThreadz[iomNum][chnNum];
 900     while (! p -> ready)
 901       sim_usleep (10000);
 902    }
 903 #endif
 904 
 905 void initThreadz (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 906   {
 907 #if defined(IO_THREADZ)
 908     // chnThreadz is sparse; make sure 'started' is false
 909     (void)memset (chnThreadz, 0, sizeof (chnThreadz));
 910 #endif
 911 
 912 #if !defined(LOCKLESS)
 913     //pthread_rwlock_init (& mem_lock, PTHREAD_PROCESS_PRIVATE);
 914     have_mem_lock = false;
 915     have_rmw_lock = false;
 916 #endif
 917 #if defined(__FreeBSD__) || defined(__OpenBSD__) || (defined(__linux__) && defined(__GLIBC__))
 918     pthread_mutexattr_t scu_attr;
 919     pthread_mutexattr_init(&scu_attr);
 920 # if !defined(__OpenBSD__)
 921     pthread_mutexattr_settype(&scu_attr, PTHREAD_MUTEX_ADAPTIVE_NP);
 922 # endif
 923     pthread_mutex_init (& scu_lock, &scu_attr);
 924 #else
 925     pthread_mutex_init (& scu_lock, NULL);
 926 #endif /* FreeBSD || OpenBSD || Linux+GLIBC */
 927     pthread_mutexattr_t iom_attr;
 928     pthread_mutexattr_init(& iom_attr);
 929     pthread_mutexattr_settype(& iom_attr, PTHREAD_MUTEX_RECURSIVE);
 930 
 931     pthread_mutex_init (& iom_lock, & iom_attr);
 932 
 933     pthread_mutexattr_t libuv_attr;
 934     pthread_mutexattr_init(& libuv_attr);
 935     pthread_mutexattr_settype(& libuv_attr, PTHREAD_MUTEX_RECURSIVE);
 936 
 937     pthread_mutex_init (& libuv_lock, & libuv_attr);
 938 
 939 #if defined(IO_ASYNC_PAYLOAD_CHAN_THREAD)
 940     pthread_cond_init (& iomCond, NULL);
 941     pthread_mutex_init (& iom_start_lock, NULL);
 942 #endif
 943   }
 944 
 945 // Set up per-thread signal handlers
 946 
 947 void int_handler (int signal);
 948 
 949 void setSignals (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 950   {
 951 #if !defined(__MINGW64__) && !defined(__MINGW32__)
 952     struct sigaction act;
 953     (void)memset (& act, 0, sizeof (act));
 954     act.sa_handler = int_handler;
 955     act.sa_flags = 0;
 956     sigaction (SIGINT, & act, NULL);
 957     sigaction (SIGTERM, & act, NULL);
 958 #endif /* if !defined(__MINGW64__) && !defined(__MINGW32__) */
 959   }
 960 
 961 
 962 
 963 
 964 
 965 
 966 
 967 
 968 
 969 
 970 

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