1

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.

mike
  • 819
  • 4
  • 14

1 Answers1

2

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.

  • does this work with 64-bit and 31-bit addressing? – mike Jun 21 '23 at 20:24
  • @mike Yes, since the callable service is available as BPX1CTW (for AMODE 31 callers), and BPX4CTW (for AMODE 64 callers). – phunsoft Jun 21 '23 at 20:44
  • @phunsoft ok - so a minor change to the code to call a different service (BPX1CTW) but the rest should be ok? I guess that could be coded up with a macro to choose one function or another based on compilation option (I think #if defined(_LP64) ? ) – mike Jun 21 '23 at 22:08
  • Thanks @phunsoft, I have updated the example – Igor Todorovski Jun 21 '23 at 22:19