sleep.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:11k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* ==== sleep.c ============================================================
  2.  * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
  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. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *  This product includes software developed by Chris Provenzano.
  16.  * 4. The name of Chris Provenzano may not be used to endorse or promote 
  17.  *   products derived from this software without specific prior written
  18.  *   permission.
  19.  *
  20.  * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
  21.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23.  * ARE DISCLAIMED.  IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY 
  24.  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  25.  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
  26.  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  27.  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
  28.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
  30.  * SUCH DAMAGE.
  31.  *
  32.  * Description : All the appropriate sleep routines.
  33.  *
  34.  *  1.00 93/12/28 proven
  35.  *      -Started coding this file.
  36.  *
  37.  * 1.36 94/06/04 proven
  38.  * -Use new timer structure pthread_timer, that uses seconds
  39.  * -nano seconds. Rewrite all routines completely.
  40.  *
  41.  * 1.38 94/06/13 proven
  42.  * -switch pthread_timer to timespec
  43.  */
  44. #ifndef lint
  45. static const char rcsid[] = "$Id$";
  46. #endif
  47. #include <pthread.h>
  48. #include <stdio.h>
  49. #include <errno.h>
  50. #include <sys/time.h>
  51. #include <signal.h>
  52. #include <unistd.h>
  53. #include <sys/compat.h>
  54. struct pthread * pthread_sleep = NULL;
  55. /* ==========================================================================
  56.  * sleep_compare_time()
  57.  */
  58. /* static inline int sleep_compare_time(struct timespec * time1, 
  59.   struct timespec * time2) */
  60. static int sleep_compare_time(struct timespec * time1, struct timespec * time2)
  61. {
  62. if ((time1->tv_sec < time2->tv_sec) || 
  63.   ((time1->tv_sec == time2->tv_sec) && (time1->tv_nsec < time2->tv_nsec))) {
  64. return(-1);
  65. }
  66. if ((time1->tv_sec == time2->tv_sec) && (time1->tv_nsec == time2->tv_nsec)){
  67. return(0);
  68. }
  69. return(1);
  70. }
  71. /* ==========================================================================
  72.  * machdep_stop_timer()
  73.  *
  74.  * Returns the time left on the timer.
  75.  */
  76. static struct itimerval timestop = { { 0, 0 }, { 0, 0 } };
  77. void machdep_stop_timer(struct timespec *current)
  78. {
  79. struct itimerval timenow;
  80. setitimer(ITIMER_REAL, & timestop, & timenow);
  81. __pthread_signal_delete(SIGALRM);
  82. if (current) {
  83. current->tv_nsec = timenow.it_value.tv_usec * 1000;
  84. current->tv_sec = timenow.it_value.tv_sec;
  85. }
  86. }
  87. /* ==========================================================================
  88.  * machdep_start_timer()
  89.  */
  90. int machdep_start_timer(struct timespec *current, struct timespec *wakeup)
  91. {
  92. struct itimerval timeout;
  93. timeout.it_value.tv_usec = (wakeup->tv_nsec - current->tv_nsec) / 1000;
  94. timeout.it_value.tv_sec = wakeup->tv_sec - current->tv_sec;
  95. timeout.it_interval.tv_usec = 0;
  96. timeout.it_interval.tv_sec = 0;
  97. if (timeout.it_value.tv_usec < 0) {
  98. timeout.it_value.tv_usec += 1000000;
  99. timeout.it_value.tv_sec--;
  100. }
  101. if (((long) timeout.it_value.tv_sec >= 0) &&
  102.     ((timeout.it_value.tv_usec) || (timeout.it_value.tv_sec))) {
  103.   if (setitimer(ITIMER_REAL, & timeout, NULL) < 0)
  104.   {
  105.     fprintf(stderr,"Got error %d from setitimer with:n
  106.             wakeup:   tv_sec: %ld  tv_nsec: %ldn
  107.     current:  tv_sec: %ld  tv_nsec: %ldn
  108.                     argument: tv_sec: %ld  tv_usec: %ldn",
  109.     errno,
  110.     wakeup->tv_sec, wakeup->tv_nsec,
  111.     current->tv_sec, current->tv_nsec,
  112.     timeout.it_value.tv_sec, timeout.it_value.tv_usec);
  113.     PANIC();
  114.   }
  115. } else {
  116. /*
  117.  * There is no time on the timer.
  118.  * This shouldn't happen,
  119.  * but isn't fatal.
  120.  */
  121. sig_handler_fake(SIGALRM);
  122. }
  123. return(OK);
  124. }
  125. /* ==========================================================================
  126.  * sleep_schedule()
  127.  *
  128.  * Assumes that the current thread is the thread to be scheduled
  129.  * and that the kthread is already locked.
  130.  */
  131. void sleep_schedule(struct timespec *current_time, struct timespec *new_time)
  132. {
  133. struct pthread * pthread_sleep_current, * pthread_sleep_prev;
  134. /* Record the new time as the current thread's wakeup time. */
  135. pthread_run->wakeup_time = *new_time;
  136. /* any threads? */
  137. if (pthread_sleep_current = pthread_sleep) {
  138. if (sleep_compare_time(&(pthread_sleep_current->wakeup_time),
  139.   new_time) <= 0) {
  140. /* Don't need to restart timer */
  141. while (pthread_sleep_current->sll) {
  142. pthread_sleep_prev =  pthread_sleep_current;
  143. pthread_sleep_current = pthread_sleep_current->sll;
  144. if (sleep_compare_time(&(pthread_sleep_current->wakeup_time),
  145.   new_time) > 0) {
  146. pthread_run->sll = pthread_sleep_current;
  147. pthread_sleep_prev->sll = pthread_run;
  148. return;
  149. }
  150. /* No more threads in queue, attach pthread_run to end of list */
  151. pthread_sleep_current->sll = pthread_run;
  152. pthread_run->sll = NULL;
  153. } else {
  154. /* Start timer and enqueue thread */
  155. machdep_start_timer(current_time, new_time);
  156. pthread_run->sll = pthread_sleep_current;
  157. pthread_sleep = pthread_run;
  158. }
  159. } else {
  160. /* Start timer and enqueue thread */
  161. machdep_start_timer(current_time, new_time);
  162. pthread_sleep = pthread_run;
  163. pthread_run->sll = NULL;
  164. }
  165. }
  166. /* ==========================================================================
  167.  * sleep_wakeup()
  168.  *
  169.  * This routine is called by the interrupt handler, which has already
  170.  * locked the current kthread. Since all threads on this list are owned
  171.  * by the current kthread, rescheduling won't be a problem.
  172.  */
  173. int sleep_spurious_wakeup = 0;
  174. int sleep_wakeup()
  175. {
  176. struct pthread *pthread_sleep_next;
  177. struct timespec current_time;
  178. int ret = 0;
  179. if (pthread_sleep == NULL) {
  180. return(NOTOK);
  181. machdep_gettimeofday(&current_time);
  182.     if (sleep_compare_time(&(pthread_sleep->wakeup_time), &current_time) > 0) {
  183.         machdep_start_timer(&current_time, &(pthread_sleep->wakeup_time));
  184.         sleep_spurious_wakeup++;
  185.         return(OK);
  186.     }
  187. do {
  188. if (pthread_sleep->pthread_priority > ret) {
  189. ret = pthread_sleep->pthread_priority;
  190. }
  191. /*
  192.  * Clean up removed thread and start it running again. 
  193.  *
  194.  * Note: It is VERY important to remove the thread form the
  195.  * current queue before putting it on the run queue.
  196.  * Both queues use pthread_sleep->next, and the thread that points
  197.  * to pthread_sleep should point to pthread_sleep->next then
  198.  * pthread_sleep should be put on the run queue.
  199.  */
  200. if ((SET_PF_DONE_EVENT(pthread_sleep)) == OK) {
  201. if (pthread_sleep->queue)
  202. pthread_queue_remove(pthread_sleep->queue, pthread_sleep);
  203. pthread_prio_queue_enq(pthread_current_prio_queue, pthread_sleep);
  204. pthread_sleep->state = PS_RUNNING;
  205. pthread_sleep_next = pthread_sleep->sll;
  206. pthread_sleep->sll = NULL;
  207. if ((pthread_sleep = pthread_sleep_next) == NULL) {
  208. /* No more threads on sleep queue */
  209. return(ret);
  210. }
  211. } while (sleep_compare_time(&(pthread_sleep->wakeup_time), &(current_time)) <= 0);
  212. /* Start timer for next time interval */
  213. machdep_start_timer(&current_time, &(pthread_sleep->wakeup_time));
  214. return(ret);
  215. }
  216. /* ==========================================================================
  217.  * __sleep()
  218.  */
  219. void __sleep(struct timespec * time_to_sleep)
  220. {
  221. struct pthread *pthread_sleep_prev;
  222. struct timespec current_time, wakeup_time;
  223. pthread_sched_prevent();
  224. /* Get real time */
  225. machdep_gettimeofday(&current_time);
  226. wakeup_time.tv_sec = current_time.tv_sec + time_to_sleep->tv_sec;
  227. wakeup_time.tv_nsec = current_time.tv_nsec + time_to_sleep->tv_nsec;
  228. sleep_schedule(&current_time, &wakeup_time);
  229. /* Reschedule thread */
  230. SET_PF_WAIT_EVENT(pthread_run);
  231. SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */
  232. pthread_resched_resume(PS_SLEEP_WAIT);
  233. CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */
  234. CLEAR_PF_DONE_EVENT(pthread_run);
  235. /* Return actual time slept */
  236. time_to_sleep->tv_sec = pthread_run->wakeup_time.tv_sec;
  237. time_to_sleep->tv_nsec = pthread_run->wakeup_time.tv_nsec;
  238. }
  239. /* ==========================================================================
  240.  * pthread_nanosleep()
  241.  */
  242. unsigned int pthread_nanosleep(unsigned int nseconds)
  243. {
  244. struct timespec time_to_sleep;
  245. if (nseconds) {
  246. time_to_sleep.tv_nsec = nseconds;
  247. time_to_sleep.tv_sec = 0;
  248. __sleep(&time_to_sleep);
  249. nseconds = time_to_sleep.tv_nsec;
  250. }
  251. return(nseconds);
  252. }
  253. /* ==========================================================================
  254.  * usleep()
  255.  */
  256. void usleep(unsigned int useconds)
  257. {
  258. struct timespec time_to_sleep;
  259. if (useconds) {
  260. time_to_sleep.tv_nsec = (useconds % 1000000) * 1000;
  261. time_to_sleep.tv_sec = useconds / 1000000;
  262. __sleep(&time_to_sleep);
  263. }
  264. }
  265. /* ==========================================================================
  266.  * sleep()
  267.  */
  268. unsigned int sleep(unsigned int seconds)
  269. {
  270. struct timespec time_to_sleep;
  271. if (seconds) {
  272. time_to_sleep.tv_sec = seconds;
  273. time_to_sleep.tv_nsec = 0;
  274. __sleep(&time_to_sleep);
  275. seconds = time_to_sleep.tv_sec;
  276. }
  277. return(seconds);
  278. }
  279. /* ==========================================================================
  280.  * sleep_cancel()
  281.  *
  282.  * Cannot be called while kernel is locked.
  283.  * Does not wake sleeping thread up, just remove it from the sleep queue.
  284.  */
  285. int sleep_cancel(struct pthread * pthread)
  286. {
  287.   struct timespec current_time, delta_time;
  288.   struct pthread * pthread_last;
  289.   int rval = NOTOK;
  290.   /* Lock sleep queue, Note this may be on a different kthread queue */
  291.   pthread_sched_prevent();
  292.   if (pthread_sleep) {
  293.     if (pthread == pthread_sleep) {
  294.       rval = OK;
  295.       machdep_stop_timer(&delta_time);
  296.       if (pthread_sleep = pthread_sleep->sll) {
  297. current_time.tv_sec  = delta_time.tv_sec;
  298. current_time.tv_nsec  = delta_time.tv_nsec;
  299. current_time.tv_sec  += pthread_sleep->wakeup_time.tv_sec;
  300. current_time.tv_nsec  += pthread_sleep->wakeup_time.tv_nsec;
  301. while (current_time.tv_nsec > 1000000000) {
  302.   current_time.tv_nsec -= 1000000000;
  303.   current_time.tv_sec++;
  304. }
  305. machdep_start_timer(&(current_time), 
  306.     &(pthread_sleep->wakeup_time));
  307.       }
  308.     } else {
  309.       for (pthread_last = pthread_sleep; pthread_last;
  310.    pthread_last = pthread_last->sll) {
  311. if (pthread_last->sll == pthread) {
  312.   pthread_last->sll = pthread->sll;
  313.   rval = OK;
  314.   break;
  315. }
  316.       }
  317.     }
  318.   }
  319.   pthread_sched_resume();
  320.   pthread->sll = NULL;
  321.   return(rval);
  322. }