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

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