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

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