Search code examples
sleepzos

z/os Version of nanosleep()


I have a similar question to: Is there a Windows equivalent of nanosleep? but for z/OS.

There doesn't appear to be a nanosleep() function for z/OS. After poking around a bit I see some approaches like: https://github.com/google/benchmark/pull/1067/files but I'm wondering how I would go about coding this up myself. I know the Z ISA architecture supports really precise timing even across a sysplex, so I didn't want to just do this with microseconds.


Solution

  • While the z/OS Language Environment does not support nanosleep, it does provide support for cond_timed_wait which can be used to implement nanosleep.

    First, to understand how to implement nanosleep, we need to understand what it does:

    it suspends a thread until a timeout or signal occurs

    The cond_timed_wait callable service does the following:

    It suspends the calling thread until any one of a set of events has occurred, or until a specified amount of time has passed.

    It is documented here https://www.ibm.com/docs/en/zos/2.5.0?topic=csd-cond-timed-wait-bpx1ctw-bpx4ctw-suspend-thread-limited-time-event and available via the BPX1CTW symbol.

    With that said, we can write a nanosleep function that calls BPX1CTW (cont_timed_wait) as follows:

    Note that you'll also need to consider the differences in error codes and return codes.

    #pragma linkage(BPX4CTW, OS)
    #pragma linkage(BPX1CTW, OS)
    
    int __cond_timed_wait(unsigned int secs, unsigned int nsecs,
                          unsigned int event_list, unsigned int *secs_rem,
                          unsigned int *nsecs_rem) {
      int rv, rc, rn;
    ifdef __LP64__
      BPX4CTW(&secs, &nsecs, &event_list, secs_rem, nsecs_rem, &rv, &rc, &rn);
    #else
      BPX1CTW(&secs, &nsecs, &event_list, secs_rem, nsecs_rem, &rv, &rc, &rn);
    #endif
      if (rv != 0)
        errno = rc;
      return rv;
    }
    
    int nanosleep(const struct timespec *req, struct timespec *rem) {
      unsigned secrem;
      unsigned nanorem;
      int rv;
      int err;
    
      rv = __cond_timed_wait((unsigned int)req->tv_sec, (unsigned int)req->tv_nsec,
                             (unsigned int)(CW_CONDVAR | CW_INTRPT), &secrem,
                             &nanorem);
      err = errno;
    
      if (rem != NULL && (rv == 0 || err == EINTR)) {
        rem->tv_nsec = nanorem;
        rem->tv_sec = secrem;
      }
    
      /* Don't clobber errno unless __cond_timed_wait() errored.
       * Don't leak EAGAIN, that just means the timeout expired.
       */
      if (rv == -1 && err == EAGAIN) {
        errno = 0;
        rv = 0;
      }
    
      return rv;
    }
    

    If you're looking to leverage an existing z/OS library that defines nanosleep, and potentially other C runtime functions that are missing in z/OS, then consider leveraging zoslib.