usleep.c revision 28192
1/* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#if defined(LIBC_SCCS) && !defined(lint) 35static char sccsid[] = "@(#)usleep.c 8.1 (Berkeley) 6/4/93"; 36#endif /* LIBC_SCCS and not lint */ 37 38#include <errno.h> 39#include <sys/time.h> 40#include <signal.h> 41#include <unistd.h> 42#ifdef _THREAD_SAFE 43#include <pthread.h> 44#include "pthread_private.h" 45#endif 46 47#ifndef _THREAD_SAFE 48static int alarm_termination; 49 50static void 51sleephandler() 52{ 53 alarm_termination++; 54} 55#endif /* _THREAD_SAFE */ 56 57 58void 59usleep(useconds) 60 unsigned int useconds; 61{ 62#ifdef _THREAD_SAFE 63 struct timespec time_to_sleep; 64 struct timespec time_remaining; 65 66 if (useconds) { 67 time_to_sleep.tv_nsec = (useconds % 1000000) * 1000; 68 time_to_sleep.tv_sec = useconds / 1000000; 69 do { 70 (void)nanosleep(&time_to_sleep, &time_remaining); 71 time_to_sleep = time_remaining; 72 } while (!errno || errno == EINTR || 73 time_to_sleep.tv_sec != 0 || 74 time_to_sleep.tv_nsec != 0); 75 } 76#else 77 struct timespec time_to_sleep; 78 struct timespec time_remaining; 79 struct sigaction act, oact; 80 sigset_t mask, omask; 81 int alarm_blocked; 82 83 if (useconds != 0) { 84 time_to_sleep.tv_nsec = (useconds % 1000000) * 1000; 85 time_to_sleep.tv_sec = useconds / 1000000; 86 87 /* Block SIGALRM while fiddling with it */ 88 sigemptyset(&mask); 89 sigaddset(&mask, SIGALRM); 90 if (sigprocmask(SIG_BLOCK, &mask, &omask)) 91 return; 92 93 alarm_termination = 0; 94 95 /* Was SIGALRM blocked already? */ 96 alarm_blocked = sigismember(&omask, SIGALRM); 97 98 if (!alarm_blocked) { 99 /* 100 * Set up handler to interrupt signanosleep only if 101 * SIGALRM was unblocked. (Save some syscalls) 102 */ 103 memset(&act, 0, sizeof(act)); 104 act.sa_handler = sleephandler; 105 if (sigaction(SIGALRM, &act, &oact)) { 106 (void)sigprocmask(SIG_SETMASK, &omask, 107 (sigset_t *)0); 108 return; 109 } 110 } 111 112 /* 113 * signanosleep() uses the given mask for the lifetime of 114 * the syscall only - it resets on return. Note that the 115 * old sleep() explicitly unblocks SIGALRM during the sleep, 116 * we don't do that now since we don't depend on SIGALRM 117 * to end the timeout. If the process blocks SIGALRM, it 118 * gets what it asks for. 119 */ 120 do { 121 (void)signanosleep(&time_to_sleep, &time_remaining, 122 &omask); 123 time_to_sleep = time_remaining; 124 } while (!alarm_termination && 125 (!errno || errno == EINTR || 126 time_to_sleep.tv_sec != 0 || 127 time_to_sleep.tv_nsec != 0)); 128 129 if (!alarm_blocked) { 130 /* Unwind */ 131 (void)sigaction(SIGALRM, &oact, (struct sigaction *)0); 132 (void)sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0); 133 } 134 } 135#endif /* _THREAD_SAFE */ 136} 137