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

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