1/* 2 * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. 3 * 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. Neither the name of the author nor the names of any co-contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD$ 30 */ 31 32#include "namespace.h" 33#include <stdio.h> 34#include <errno.h> 35#include <pthread.h> 36#include "un-namespace.h" 37#include "thr_private.h" 38 39int __nanosleep(const struct timespec *time_to_sleep, 40 struct timespec *time_remaining); 41 42__weak_reference(__nanosleep, nanosleep); 43 44int 45_nanosleep(const struct timespec *time_to_sleep, 46 struct timespec *time_remaining) 47{ 48 struct pthread *curthread = _get_curthread(); 49 int ret = 0; 50 struct timespec ts, ts1; 51 struct timespec remaining_time; 52 struct timespec wakeup_time; 53 54 /* Check if the time to sleep is legal: */ 55 if ((time_to_sleep == NULL) || (time_to_sleep->tv_sec < 0) || 56 (time_to_sleep->tv_nsec < 0) || 57 (time_to_sleep->tv_nsec >= 1000000000)) { 58 /* Return an EINVAL error : */ 59 errno = EINVAL; 60 ret = -1; 61 } else { 62 if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) 63 return (__sys_nanosleep(time_to_sleep, time_remaining)); 64 65 KSE_GET_TOD(curthread->kse, &ts); 66 67 /* Calculate the time for the current thread to wake up: */ 68 TIMESPEC_ADD(&wakeup_time, &ts, time_to_sleep); 69 70 THR_LOCK_SWITCH(curthread); 71 curthread->interrupted = 0; 72 curthread->wakeup_time = wakeup_time; 73 THR_SET_STATE(curthread, PS_SLEEP_WAIT); 74 75 /* Reschedule the current thread to sleep: */ 76 _thr_sched_switch_unlocked(curthread); 77 78 /* Calculate the remaining time to sleep: */ 79 KSE_GET_TOD(curthread->kse, &ts1); 80 remaining_time.tv_sec = time_to_sleep->tv_sec 81 + ts.tv_sec - ts1.tv_sec; 82 remaining_time.tv_nsec = time_to_sleep->tv_nsec 83 + ts.tv_nsec - ts1.tv_nsec; 84 85 /* Check if the nanosecond field has underflowed: */ 86 if (remaining_time.tv_nsec < 0) { 87 /* Handle the underflow: */ 88 remaining_time.tv_sec -= 1; 89 remaining_time.tv_nsec += 1000000000; 90 } 91 /* Check if the nanosecond field has overflowed: */ 92 else if (remaining_time.tv_nsec >= 1000000000) { 93 /* Handle the overflow: */ 94 remaining_time.tv_sec += 1; 95 remaining_time.tv_nsec -= 1000000000; 96 } 97 98 /* Check if the sleep was longer than the required time: */ 99 if (remaining_time.tv_sec < 0) { 100 /* Reset the time left: */ 101 remaining_time.tv_sec = 0; 102 remaining_time.tv_nsec = 0; 103 } 104 105 /* Check if the time remaining is to be returned: */ 106 if (time_remaining != NULL) { 107 /* Return the actual time slept: */ 108 time_remaining->tv_sec = remaining_time.tv_sec; 109 time_remaining->tv_nsec = remaining_time.tv_nsec; 110 } 111 112 /* Check if the sleep was interrupted: */ 113 if (curthread->interrupted) { 114 /* Return an EINTR error : */ 115 errno = EINTR; 116 ret = -1; 117 } 118 } 119 return (ret); 120} 121 122int 123__nanosleep(const struct timespec *time_to_sleep, 124 struct timespec *time_remaining) 125{ 126 struct pthread *curthread = _get_curthread(); 127 int ret; 128 129 _thr_cancel_enter(curthread); 130 ret = _nanosleep(time_to_sleep, time_remaining); 131 _thr_cancel_leave(curthread, 1); 132 133 return (ret); 134} 135