void __cleanup_fct_attribute __pthread_unregister_cancel_restore (__pthread_unwind_buf_t *buf) { struct pthread *self = THREAD_SELF; struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf; THREAD_SETMEM (self, cleanup_jmp_buf, ibuf->priv.data.prev); int cancelhandling; if (ibuf->priv.data.canceltype != PTHREAD_CANCEL_DEFERRED && ((cancelhandling = THREAD_GETMEM (self, cancelhandling)) & CANCELTYPE_BITMASK) == 0) { while (1) { int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, cancelhandling | CANCELTYPE_BITMASK, cancelhandling); if (__glibc_likely (curval == cancelhandling)) /* Successfully replaced the value. */ break; /* Prepare for the next round. */ cancelhandling = curval; } CANCELLATION_P (self); } }
void __cleanup_fct_attribute __pthread_unregister_cancel_restore (__pthread_unwind_buf_t *buf) { struct pthread *self = THREAD_SELF; struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf; THREAD_SETMEM (self, cleanup_jmp_buf, ibuf->priv.data.prev); int cancelhandling; if (is_recording()) { pthread_log_record (0, PTHREAD_CANCELHANDLING_ENTER, (u_long) &self->cancelhandling, 1); cancelhandling = THREAD_GETMEM (self, cancelhandling); pthread_log_record (cancelhandling, PTHREAD_CANCELHANDLING_EXIT, (u_long) &self->cancelhandling, 0); } else if (is_replaying()) { pthread_log_replay (PTHREAD_CANCELHANDLING_ENTER, (u_long) &self->cancelhandling); cancelhandling = pthread_log_replay (PTHREAD_CANCELHANDLING_EXIT, (u_long) &self->cancelhandling); } else { cancelhandling = THREAD_GETMEM (self, cancelhandling); } if (ibuf->priv.data.canceltype != PTHREAD_CANCEL_DEFERRED && (cancelhandling & CANCELTYPE_BITMASK) == 0) { while (1) { int curval; if (is_recording()) { pthread_log_record (0, PTHREAD_CANCELHANDLING_ENTER, (u_long) &self->cancelhandling, 1); curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, cancelhandling | CANCELTYPE_BITMASK, cancelhandling); pthread_log_record (curval, PTHREAD_CANCELHANDLING_EXIT, (u_long) &self->cancelhandling, 0); } else if (is_replaying()) { pthread_log_replay (PTHREAD_CANCELHANDLING_ENTER, (u_long) &self->cancelhandling); curval = pthread_log_replay (PTHREAD_CANCELHANDLING_EXIT, (u_long) &self->cancelhandling); } else { curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, cancelhandling | CANCELTYPE_BITMASK, cancelhandling); } if (__builtin_expect (curval == cancelhandling, 1)) /* Successfully replaced the value. */ break; /* Prepare for the next round. */ cancelhandling = curval; } CANCELLATION_P (self); } }
int __new_sem_wait (sem_t *sem) { /* First check for cancellation. */ CANCELLATION_P (THREAD_SELF); int *futex = (int *) sem; int err; do { int val; if (__atomic_is_v9) val = atomic_decrement_if_positive (futex); else { __sparc32_atomic_do_lock24 (futex + 1); val = *futex; if (val > 0) *futex = val - 1; __sparc32_atomic_do_unlock24 (futex + 1); } if (val > 0) return 0; /* Enable asynchronous cancellation. Required by the standard. */ int oldtype = __pthread_enable_asynccancel (); err = lll_futex_wait (futex, 0); /* Disable asynchronous cancellation. */ __pthread_disable_asynccancel (oldtype); } while (err == 0 || err == -EWOULDBLOCK); __set_errno (-err); return -1; }
void attribute_protected _pthread_cleanup_pop_restore ( struct _pthread_cleanup_buffer *buffer, int execute) { struct pthread *self = THREAD_SELF; THREAD_SETMEM (self, cleanup, buffer->__prev); int cancelhandling; if (__builtin_expect (buffer->__canceltype != PTHREAD_CANCEL_DEFERRED, 0) && ((cancelhandling = THREAD_GETMEM (self, cancelhandling)) & CANCELTYPE_BITMASK) == 0) { while (1) { int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, cancelhandling | CANCELTYPE_BITMASK, cancelhandling); if (__builtin_expect (curval == cancelhandling, 1)) /* Successfully replaced the value. */ break; /* Prepare for the next round. */ cancelhandling = curval; } CANCELLATION_P (self); } /* If necessary call the cleanup routine after we removed the current cleanup block from the list. */ if (execute) buffer->__routine (buffer->__arg); }
/* We are going to use the `nanosleep' syscall of the kernel. But the kernel does not implement the stupid SysV SIGCHLD vs. SIG_IGN behaviour for this syscall. Therefore we have to emulate it here. */ unsigned int __sleep (unsigned int seconds) { const unsigned int max = (unsigned int) (((unsigned long int) (~((time_t) 0))) >> 1); struct timespec ts; sigset_t set, oset; unsigned int result; /* This is not necessary but some buggy programs depend on this. */ if (__glibc_unlikely (seconds == 0)) { #ifdef CANCELLATION_P CANCELLATION_P (THREAD_SELF); #endif return 0; } ts.tv_sec = 0; ts.tv_nsec = 0; again: if (sizeof (ts.tv_sec) <= sizeof (seconds)) { /* Since SECONDS is unsigned assigning the value to .tv_sec can overflow it. In this case we have to wait in steps. */ ts.tv_sec += MIN (seconds, max); seconds -= (unsigned int) ts.tv_sec; } else { ts.tv_sec = (time_t) seconds; seconds = 0; } /* Linux will wake up the system call, nanosleep, when SIGCHLD arrives even if SIGCHLD is ignored. We have to deal with it in libc. We block SIGCHLD first. */ __sigemptyset (&set); __sigaddset (&set, SIGCHLD); if (__sigprocmask (SIG_BLOCK, &set, &oset)) return -1; /* If SIGCHLD is already blocked, we don't have to do anything. */ if (!__sigismember (&oset, SIGCHLD)) { int saved_errno; struct sigaction oact; __sigemptyset (&set); __sigaddset (&set, SIGCHLD); /* We get the signal handler for SIGCHLD. */ if (__sigaction (SIGCHLD, (struct sigaction *) NULL, &oact) < 0) { saved_errno = errno; /* Restore the original signal mask. */ (void) __sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL); __set_errno (saved_errno); return -1; } /* Note the sleep() is a cancellation point. But since we call nanosleep() which itself is a cancellation point we do not have to do anything here. */ if (oact.sa_handler == SIG_IGN) { //__libc_cleanup_push (cl, &oset); /* We should leave SIGCHLD blocked. */ while (1) { result = __nanosleep (&ts, &ts); if (result != 0 || seconds == 0) break; if (sizeof (ts.tv_sec) <= sizeof (seconds)) { ts.tv_sec = MIN (seconds, max); seconds -= (unsigned int) ts.tv_nsec; } } //__libc_cleanup_pop (0); saved_errno = errno; /* Restore the original signal mask. */ (void) __sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL); __set_errno (saved_errno); goto out; } /* We should unblock SIGCHLD. Restore the original signal mask. */ (void) __sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL); } result = __nanosleep (&ts, &ts); if (result == 0 && seconds != 0) goto again; out: if (result != 0) /* Round remaining time. */ result = seconds + (unsigned int) ts.tv_sec + (ts.tv_nsec >= 500000000L); return result; }
void pthread_testcancel (void) { CANCELLATION_P (THREAD_SELF); }
/* This is a quick and dirty, but not 100% compliant with * the stupid SysV SIGCHLD vs. SIG_IGN behaviour. It is * fine unless you are messing with SIGCHLD... */ unsigned int sleep (unsigned int sec) { unsigned int res; struct timespec ts = { .tv_sec = (long int) seconds, .tv_nsec = 0 }; res = nanosleep(&ts, &ts); if (res) res = (unsigned int) ts.tv_sec + (ts.tv_nsec >= 500000000L); return res; } # else /* We are going to use the `nanosleep' syscall of the kernel. But the kernel does not implement the sstupid SysV SIGCHLD vs. SIG_IGN behaviour for this syscall. Therefore we have to emulate it here. */ unsigned int sleep (unsigned int seconds) { struct timespec ts = { .tv_sec = (long int) seconds, .tv_nsec = 0 }; sigset_t set; struct sigaction oact; unsigned int result; /* This is not necessary but some buggy programs depend on this. */ if (seconds == 0) { # ifdef CANCELLATION_P int cancelhandling; CANCELLATION_P (THREAD_SELF); # endif return 0; } /* Linux will wake up the system call, nanosleep, when SIGCHLD arrives even if SIGCHLD is ignored. We have to deal with it in libc. */ __sigemptyset (&set); __sigaddset (&set, SIGCHLD); /* Is SIGCHLD set to SIG_IGN? */ sigaction (SIGCHLD, NULL, &oact); /* never fails */ if (oact.sa_handler == SIG_IGN) { /* Yes. Block SIGCHLD, save old mask. */ sigprocmask (SIG_BLOCK, &set, &set); /* never fails */ } /* Run nanosleep, with SIGCHLD blocked if SIGCHLD is SIG_IGNed. */ result = nanosleep (&ts, &ts); if (result != 0) { /* Got EINTR. Return remaining time. */ result = (unsigned int) ts.tv_sec + (ts.tv_nsec >= 500000000L); } if (!__sigismember (&set, SIGCHLD)) { /* We did block SIGCHLD, and old mask had no SIGCHLD bit. IOW: we need to unblock SIGCHLD now. Do it. */ /* this sigprocmask call never fails, thus never updates errno, and therefore we don't need to save/restore it. */ sigprocmask (SIG_SETMASK, &set, NULL); /* never fails */ } return result; } # endif #else /* __UCLIBC_HAS_REALTIME__ */ /* no nanosleep, use signals and alarm() */ static void sleep_alarm_handler(int attribute_unused sig) { } unsigned int sleep (unsigned int seconds) { struct sigaction act, oact; sigset_t set, oset; unsigned int result, remaining; time_t before, after; int old_errno = errno; /* This is not necessary but some buggy programs depend on this. */ if (seconds == 0) return 0; /* block SIGALRM */ __sigemptyset (&set); __sigaddset (&set, SIGALRM); sigprocmask (SIG_BLOCK, &set, &oset); /* can't fail */ act.sa_handler = sleep_alarm_handler; act.sa_flags = 0; act.sa_mask = oset; sigaction(SIGALRM, &act, &oact); /* never fails */ before = time(NULL); remaining = alarm(seconds); if (remaining && remaining > seconds) { /* restore user's alarm */ sigaction(SIGALRM, &oact, NULL); alarm(remaining); /* restore old alarm */ sigsuspend(&oset); after = time(NULL); } else { sigsuspend (&oset); after = time(NULL); sigaction (SIGALRM, &oact, NULL); } result = after - before; alarm(remaining > result ? remaining - result : 0); sigprocmask (SIG_SETMASK, &oset, NULL); __set_errno(old_errno); return result > seconds ? 0 : seconds - result; } #endif /* __UCLIBC_HAS_REALTIME__ */ libc_hidden_def(sleep)