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     rc = pthread_mutex_init (& p->runLock, NULL);
 416     if (rc)
 417       sim_printf ("createCPUThread pthread_mutex_init runLock %d\n", rc);
 418     rc = pthread_cond_init (& p->runCond, NULL);
 419     if (rc)
 420       sim_printf ("createCPUThread pthread_cond_init runCond %d\n", rc);
 421 
 422     p->run = true;
 423 
 424     // initialize DIS sleep
 425 #if defined(USE_MONOTONIC)
 426 # if defined(__APPLE__) || !defined(CLOCK_MONOTONIC)
 427     p->sleepClock = CLOCK_REALTIME;
 428     rc = pthread_cond_init (& p->sleepCond, NULL);
 429 # else
 430     rc = pthread_condattr_init (& p->sleepCondAttr);
 431     if (rc)
 432       sim_printf ("createCPUThread pthread_condattr_init sleepCond %d\n", rc);
 433 
 434     rc = pthread_condattr_setclock (& p->sleepCondAttr, CLOCK_MONOTONIC);
 435     if (rc) {
 436       //sim_printf ("createCPUThread pthread_condattr_setclock  sleepCond %d\n", rc);
 437       p->sleepClock = CLOCK_REALTIME;
 438     } else {
 439       p->sleepClock = CLOCK_MONOTONIC;
 440     }
 441 # endif // ! APPLE
 442     rc = pthread_cond_init (& p->sleepCond, & p->sleepCondAttr);
 443 #else
 444     rc = pthread_cond_init (& p->sleepCond, NULL);
 445 #endif
 446     if (rc)
 447       sim_printf ("createCPUThread pthread_cond_init sleepCond %d\n", rc);
 448 
 449 #if defined(__APPLE__)
 450     rc = pthread_create_with_cpu_policy(
 451             & p->cpuThread,
 452             cpuNum,
 453             NULL,
 454             cpu_thread_main,
 455             & p->cpuThreadArg);
 456 #else
 457     rc = pthread_create(
 458             & p->cpuThread,
 459             NULL,
 460             cpu_thread_main,
 461             & p->cpuThreadArg);
 462 #endif /* if defined(__APPLE__) */
 463     if (rc)
 464       sim_printf ("createCPUThread pthread_create %d\n", rc);
 465 
 466 #if defined(AFFINITY)
 467     if (cpus[cpuNum].set_affinity)
 468       {
 469         cpu_set_t cpuset;
 470         CPU_ZERO (& cpuset);
 471         CPU_SET (cpus[cpuNum].affinity, & cpuset);
 472         int s = pthread_setaffinity_np (p->cpuThread, sizeof (cpu_set_t), & cpuset);
 473         if (s)
 474           sim_printf ("pthread_setaffinity_np %u on CPU %u returned %d\n",
 475                       cpus[cpuNum].affinity, cpuNum, s);
 476       }
 477 #endif /* if defined(AFFINITY) */
 478   }
 479 
 480 void stopCPUThread(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 481   {
 482     struct cpuThreadz_t * p = & cpuThreadz[current_running_cpu_idx];
 483     p->run = false;
 484     pthread_exit(NULL);
 485   }
 486 
 487 // Called by CPU thread to block on run/sleep
 488 
 489 #if defined(THREADZ)
 490 void cpuRunningWait (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 491   {
 492     int rc;
 493     struct cpuThreadz_t * p = & cpuThreadz[current_running_cpu_idx];
 494     if (p->run)
 495       return;
 496     rc = pthread_mutex_lock (& p->runLock);
 497     if (rc)
 498       sim_printf ("cpuRunningWait pthread_mutex_lock %d\n", rc);
 499     while (! p->run)
 500       {
 501         rc = pthread_cond_wait (& p->runCond, & p->runLock);
 502         if (rc)
 503           sim_printf ("cpuRunningWait pthread_cond_wait %d\n", rc);
 504      }
 505     rc = pthread_mutex_unlock (& p->runLock);
 506     if (rc)
 507       sim_printf ("cpuRunningWait pthread_mutex_unlock %d\n", rc);
 508   }
 509 #endif
 510 
 511 // Called by CPU thread to sleep until time up or signaled
 512 // Return time left
 513 unsigned long  sleepCPU (unsigned long usec) {
     /* [previous][next][first][last][top][bottom][index][help] */
 514   int rc;
 515   struct cpuThreadz_t * p = & cpuThreadz[current_running_cpu_idx];
 516   struct timespec startTime, absTime;
 517 
 518 #if defined(USE_MONOTONIC)
 519   clock_gettime (p->sleepClock, & startTime);
 520 #else
 521   clock_gettime (CLOCK_REALTIME, & startTime);
 522 #endif /* if defined(USE_MONOTONIC) */
 523   absTime = startTime;
 524   int64_t nsec = ((int64_t) usec) * 1000L + (int64_t)startTime.tv_nsec;
 525   absTime.tv_nsec = nsec % 1000000000L;
 526   absTime.tv_sec += nsec / 1000000000L;
 527 
 528   rc = pthread_cond_timedwait (& p->sleepCond, & scu_lock, & absTime);
 529 
 530   if (rc == ETIMEDOUT) {
 531     return 0;
 532   }
 533 
 534   if (rc) {
 535     cpu_state_t * cpup = _cpup;
 536     sim_printf ("sleepCPU pthread_cond_timedwait rc %ld  usec %ld TR %lu CPU %lu\n",
 537                 (long) rc, (long) usec, (unsigned long) cpu.rTR,
 538                 (unsigned long) current_running_cpu_idx);
 539   }
 540 
 541   struct timespec newTime;
 542   struct timespec delta;
 543 #if defined(USE_MONOTONIC)
 544   clock_gettime (p->sleepClock, & newTime);
 545 #else
 546   clock_gettime (CLOCK_REALTIME, & newTime);
 547 #endif /* if defined(USE_MONOTONIC) */
 548   timespec_diff (& absTime, & newTime, & delta);
 549 
 550   if (delta.tv_nsec < 0)
 551     return 0; // safety
 552   return (unsigned long) delta.tv_nsec / 1000L;
 553 }
 554 
 555 // Called to wake sleeping CPU; such as interrupt during DIS
 556 
 557 void wakeCPU (uint cpuNum)
     /* [previous][next][first][last][top][bottom][index][help] */
 558   {
 559     int rc;
 560     struct cpuThreadz_t * p = & cpuThreadz[cpuNum];
 561 
 562     rc = pthread_cond_signal (& p->sleepCond);
 563     if (rc)
 564       sim_printf ("wakeCPU pthread_cond_signal %d\n", rc);
 565   }
 566 
 567 #if defined(IO_THREADZ)
 568 ////////////////////////////////////////////////////////////////////////////////
 569 //
 570 // IOM threads
 571 //
 572 ////////////////////////////////////////////////////////////////////////////////
 573 
 574 // main thread
 575 //   createIOMThread    create thread
 576 //   iomRdyWait         wait for IOM started
 577 //   setIOMInterrupt    signal IOM to start
 578 //   iomDoneWait        wait for IOM done
 579 // IOM thread
 580 //   iomInterruptWait   IOM thread wait for work
 581 //   iomInterruptDone   IOM thread signal done working
 582 //
 583 //   IOM thread
 584 //     while (1)
 585 //       {
 586 //         iomInterruptWake
 587 //         work...
 588 //         iomInterruptDone
 589 //      }
 590 
 591 struct iomThreadz_t iomThreadz [N_IOM_UNITS_MAX];
 592 
 593 // Create IOM thread
 594 
 595 void createIOMThread (uint iomNum)
     /* [previous][next][first][last][top][bottom][index][help] */
 596   {
 597     int rc;
 598     struct iomThreadz_t * p = & iomThreadz[iomNum];
 599 # if defined(tdbg)
 600     p->inCnt = 0;
 601     p->outCnt = 0;
 602 # endif
 603     p->iomThreadArg = (int) iomNum;
 604 
 605     p->ready = false;
 606     // initialize interrupt wait
 607     p->intr = false;
 608     rc = pthread_mutex_init (& p->intrLock, NULL);
 609     if (rc)
 610       sim_printf ("createIOMThread pthread_mutex_init intrLock %d\n", rc);
 611     rc = pthread_cond_init (& p->intrCond, NULL);
 612     if (rc)
 613       sim_printf ("createIOMThread pthread_cond_init intrCond %d\n", rc);
 614 
 615 # if defined(__APPLE__)
 616     rc = pthread_create_with_cpu_policy(
 617             & p->iomThread,
 618             iomNum,
 619             NULL,
 620             iom_thread_main,
 621             & p->iomThreadArg);
 622 # else
 623     rc = pthread_create(
 624             & p->iomThread,
 625             NULL,
 626             iom_thread_main,
 627             & p->iomThreadArg);
 628 # endif /* if defined(__APPLE__) */
 629     if (rc)
 630       sim_printf ("createIOMThread pthread_create %d\n", rc);
 631   }
 632 
 633 // Called by IOM thread to block until CIOC call
 634 
 635 void iomInterruptWait (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 636   {
 637     int rc;
 638     struct iomThreadz_t * p = & iomThreadz[this_iom_idx];
 639     rc = pthread_mutex_lock (& p->intrLock);
 640     if (rc)
 641       sim_printf ("iomInterruptWait pthread_mutex_lock %d\n", rc);
 642     p -> ready = true;
 643     while (! p->intr)
 644       {
 645         rc = pthread_cond_wait (& p->intrCond, & p->intrLock);
 646         if (rc)
 647           sim_printf ("iomInterruptWait pthread_cond_wait %d\n", rc);
 648       }
 649 # if defined(tdbg)
 650     p->outCnt++;
 651     if (p->inCnt != p->outCnt)
 652       sim_printf ("iom thread %d in %d out %d\n", this_iom_idx,
 653                   p->inCnt, p->outCnt);
 654 # endif
 655   }
 656 
 657 // Called by IOM thread to signal CIOC complete
 658 
 659 void iomInterruptDone (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 660   {
 661     int rc;
 662     struct iomThreadz_t * p = & iomThreadz[this_iom_idx];
 663     p->intr = false;
 664     rc = pthread_cond_signal (& p->intrCond);
 665     if (rc)
 666       sim_printf ("iomInterruptDone pthread_cond_signal %d\n", rc);
 667     rc = pthread_mutex_unlock (& p->intrLock);
 668     if (rc)
 669       sim_printf ("iomInterruptDone pthread_mutex_unlock %d\n", rc);
 670   }
 671 
 672 // Called by CPU thread to wait for iomInterruptDone
 673 
 674 void iomDoneWait (uint iomNum)
     /* [previous][next][first][last][top][bottom][index][help] */
 675   {
 676     int rc;
 677     struct iomThreadz_t * p = & iomThreadz[iomNum];
 678     rc = pthread_mutex_lock (& p->intrLock);
 679     if (rc)
 680       sim_printf ("iomDoneWait pthread_mutex_lock %d\n", rc);
 681     while (p->intr)
 682       {
 683         rc = pthread_cond_wait (& p->intrCond, & p->intrLock);
 684         if (rc)
 685           sim_printf ("iomDoneWait pthread_cond_wait %d\n", rc);
 686       }
 687     rc = pthread_mutex_unlock (& p->intrLock);
 688     if (rc)
 689       sim_printf ("iomDoneWait pthread_mutex_unlock %d\n", rc);
 690   }
 691 
 692 // Signal CIOC to IOM thread
 693 
 694 void setIOMInterrupt (uint iomNum)
     /* [previous][next][first][last][top][bottom][index][help] */
 695   {
 696     int rc;
 697     struct iomThreadz_t * p = & iomThreadz[iomNum];
 698     rc = pthread_mutex_lock (& p->intrLock);
 699     if (rc)
 700       sim_printf ("setIOMInterrupt pthread_mutex_lock %d\n", rc);
 701     while (p->intr)
 702       {
 703         rc = pthread_cond_wait(&p->intrCond, &p->intrLock);
 704         if (rc)
 705           sim_printf ("setIOMInterrupt pthread_cond_wait intrLock %d\n", rc);
 706       }
 707 # if defined(tdbg)
 708     p->inCnt++;
 709 # endif
 710     p->intr = true;
 711     rc = pthread_cond_signal (& p->intrCond);
 712     if (rc)
 713       sim_printf ("setIOMInterrupt pthread_cond_signal %d\n", rc);
 714     rc = pthread_mutex_unlock (& p->intrLock);
 715     if (rc)
 716       sim_printf ("setIOMInterrupt pthread_mutex_unlock %d\n", rc);
 717   }
 718 
 719 // Wait for IOM thread to initialize
 720 
 721 void iomRdyWait (uint iomNum)
     /* [previous][next][first][last][top][bottom][index][help] */
 722   {
 723     struct iomThreadz_t * p = & iomThreadz[iomNum];
 724     while (! p -> ready)
 725       sim_usleep (10000);
 726    }
 727 
 728 ////////////////////////////////////////////////////////////////////////////////
 729 //
 730 // Channel threads
 731 //
 732 ////////////////////////////////////////////////////////////////////////////////
 733 
 734 // main thread
 735 //   createChnThread    create thread
 736 // IOM thread
 737 //   chnRdyWait         wait for channel started
 738 //   setChnConnect      signal channel to start
 739 // Channel thread
 740 //   chnConnectWait     Channel thread wait for work
 741 //   chnConnectDone     Channel thread signal done working
 742 //
 743 //   IOM thread
 744 //     while (1)
 745 //       {
 746 //         iomInterruptWake
 747 //         work...
 748 //         iomInterruptDone
 749 //      }
 750 struct chnThreadz_t chnThreadz [N_IOM_UNITS_MAX] [MAX_CHANNELS];
 751 
 752 // Create channel thread
 753 
 754 void createChnThread (uint iomNum, uint chnNum, const char * devTypeStr)
     /* [previous][next][first][last][top][bottom][index][help] */
 755   {
 756     int rc;
 757     struct chnThreadz_t * p = & chnThreadz[iomNum][chnNum];
 758     p->chnThreadArg = (int) (chnNum + iomNum * MAX_CHANNELS);
 759 
 760 # if defined(tdbg)
 761     p->inCnt = 0;
 762     p->outCnt = 0;
 763 # endif
 764     p->ready = false;
 765     // initialize interrupt wait
 766     p->connect = false;
 767     rc = pthread_mutex_init (& p->connectLock, NULL);
 768     if (rc)
 769       sim_printf ("createChnThread pthread_mutex_init connectLock %d\n", rc);
 770     rc = pthread_cond_init (& p->connectCond, NULL);
 771     if (rc)
 772       sim_printf ("createChnThread pthread_cond_init connectCond %d\n", rc);
 773 
 774 # if defined(__APPLE__)
 775     rc = pthread_create_with_cpu_policy(
 776             & p->chnThread,
 777             iomNum
 778             NULL,
 779             chan_thread_main,
 780             & p->chnThreadArg);
 781 # else
 782     rc = pthread_create(
 783             & p->chnThread,
 784             NULL,
 785             chan_thread_main,
 786             & p->chnThreadArg);
 787 # endif /* if defined(__APPLE__) */
 788     if (rc)
 789       sim_printf ("createChnThread pthread_create %d\n", rc);
 790   }
 791 
 792 // Called by channel thread to block until I/O command presented
 793 
 794 void chnConnectWait (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 795   {
 796     int rc;
 797     struct chnThreadz_t * p = & chnThreadz[this_iom_idx][this_chan_num];
 798 
 799     rc = pthread_mutex_lock (& p->connectLock);
 800     if (rc)
 801       sim_printf ("chnConnectWait pthread_mutex_lock %d\n", rc);
 802     p -> ready = true;
 803     while (! p->connect)
 804       {
 805         rc = pthread_cond_wait (& p->connectCond, & p->connectLock);
 806         if (rc)
 807           sim_printf ("chnConnectWait pthread_cond_wait %d\n", rc);
 808       }
 809 # if defined(tdbg)
 810     p->outCnt++;
 811     if (p->inCnt != p->outCnt)
 812       sim_printf ("chn thread %d in %d out %d\n", this_chan_num,
 813                   p->inCnt, p->outCnt);
 814 # endif
 815   }
 816 
 817 // Called by channel thread to signal I/O complete
 818 
 819 void chnConnectDone (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 820   {
 821     int rc;
 822     struct chnThreadz_t * p = & chnThreadz[this_iom_idx][this_chan_num];
 823     p->connect = false;
 824     rc = pthread_cond_signal (& p->connectCond);
 825     if (rc)
 826       sim_printf ("chnInterruptDone pthread_cond_signal %d\n", rc);
 827     rc = pthread_mutex_unlock (& p->connectLock);
 828     if (rc)
 829       sim_printf ("chnConnectDone pthread_mutex_unlock %d\n", rc);
 830   }
 831 
 832 // Signal I/O presented to channel thread
 833 
 834 void setChnConnect (uint iomNum, uint chnNum)
     /* [previous][next][first][last][top][bottom][index][help] */
 835   {
 836     int rc;
 837     struct chnThreadz_t * p = & chnThreadz[iomNum][chnNum];
 838     rc = pthread_mutex_lock (& p->connectLock);
 839     if (rc)
 840       sim_printf ("setChnConnect pthread_mutex_lock %d\n", rc);
 841     while (p->connect)
 842       {
 843         rc = pthread_cond_wait(&p->connectCond, &p->connectLock);
 844         if (rc)
 845           sim_printf ("setChnInterrupt pthread_cond_wait connectLock %d\n", rc);
 846       }
 847 # if defined(tdbg)
 848     p->inCnt++;
 849 # endif
 850     p->connect = true;
 851     rc = pthread_cond_signal (& p->connectCond);
 852     if (rc)
 853       sim_printf ("setChnConnect pthread_cond_signal %d\n", rc);
 854     rc = pthread_mutex_unlock (& p->connectLock);
 855     if (rc)
 856       sim_printf ("setChnConnect pthread_mutex_unlock %d\n", rc);
 857   }
 858 
 859 // Block until channel thread ready
 860 
 861 void chnRdyWait (uint iomNum, uint chnNum)
     /* [previous][next][first][last][top][bottom][index][help] */
 862   {
 863     struct chnThreadz_t * p = & chnThreadz[iomNum][chnNum];
 864     while (! p -> ready)
 865       sim_usleep (10000);
 866    }
 867 #endif
 868 
 869 void initThreadz (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 870   {
 871 #if defined(IO_THREADZ)
 872     // chnThreadz is sparse; make sure 'started' is false
 873     (void)memset (chnThreadz, 0, sizeof (chnThreadz));
 874 #endif
 875 
 876 #if !defined(LOCKLESS)
 877     //pthread_rwlock_init (& mem_lock, PTHREAD_PROCESS_PRIVATE);
 878     have_mem_lock = false;
 879     have_rmw_lock = false;
 880 #endif
 881 #if defined(__FreeBSD__) || defined(__OpenBSD__)
 882     pthread_mutexattr_t scu_attr;
 883     pthread_mutexattr_init(&scu_attr);
 884 # if !defined(__OpenBSD__)
 885     pthread_mutexattr_settype(&scu_attr, PTHREAD_MUTEX_ADAPTIVE_NP);
 886 # endif
 887     pthread_mutex_init (& scu_lock, &scu_attr);
 888 #else
 889     pthread_mutex_init (& scu_lock, NULL);
 890 #endif /* FreeBSD || OpenBSD */
 891     pthread_mutexattr_t iom_attr;
 892     pthread_mutexattr_init(& iom_attr);
 893     pthread_mutexattr_settype(& iom_attr, PTHREAD_MUTEX_RECURSIVE);
 894 
 895     pthread_mutex_init (& iom_lock, & iom_attr);
 896 
 897     pthread_mutexattr_t libuv_attr;
 898     pthread_mutexattr_init(& libuv_attr);
 899     pthread_mutexattr_settype(& libuv_attr, PTHREAD_MUTEX_RECURSIVE);
 900 
 901     pthread_mutex_init (& libuv_lock, & libuv_attr);
 902 
 903 #if defined(IO_ASYNC_PAYLOAD_CHAN_THREAD)
 904     pthread_cond_init (& iomCond, NULL);
 905     pthread_mutex_init (& iom_start_lock, NULL);
 906 #endif
 907   }
 908 
 909 // Set up per-thread signal handlers
 910 
 911 void int_handler (int signal);
 912 
 913 void setSignals (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 914   {
 915 #if !defined(__MINGW64__) && !defined(__MINGW32__)
 916     struct sigaction act;
 917     (void)memset (& act, 0, sizeof (act));
 918     act.sa_handler = int_handler;
 919     act.sa_flags = 0;
 920     sigaction (SIGINT, & act, NULL);
 921     sigaction (SIGTERM, & act, NULL);
 922 #endif /* if !defined(__MINGW64__) && !defined(__MINGW32__) */
 923   }
 924 
 925 
 926 
 927 
 928 
 929 
 930 
 931 
 932 
 933 
 934 

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