clock.c
上传用户:xu_441
上传日期:2007-01-04
资源大小:1640k
文件大小:6k
源码类别:

Email客户端

开发平台:

Unix_Linux

  1. /*
  2.  * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
  3.  * All rights reserved.
  4.  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
  5.  * Copyright (c) 1988, 1993
  6.  * The Regents of the University of California.  All rights reserved.
  7.  *
  8.  * By using this file, you agree to the terms and conditions set
  9.  * forth in the LICENSE file which can be found at the top level of
  10.  * the sendmail distribution.
  11.  *
  12.  */
  13. #ifndef lint
  14. static char id[] = "@(#)$Id: clock.c,v 8.52 1999/10/13 22:16:42 ca Exp $";
  15. #endif /* ! lint */
  16. #include <sendmail.h>
  17. #ifndef sigmask
  18. # define sigmask(s) (1 << ((s) - 1))
  19. #endif /* ! sigmask */
  20. static void endsleep __P((void));
  21. /*
  22. **  SETEVENT -- set an event to happen at a specific time.
  23. **
  24. ** Events are stored in a sorted list for fast processing.
  25. ** An event only applies to the process that set it.
  26. **
  27. ** Parameters:
  28. ** intvl -- intvl until next event occurs.
  29. ** func -- function to call on event.
  30. ** arg -- argument to func on event.
  31. **
  32. ** Returns:
  33. ** none.
  34. **
  35. ** Side Effects:
  36. ** none.
  37. */
  38. EVENT *FreeEventList; /* list of free events */
  39. EVENT *
  40. setevent(intvl, func, arg)
  41. time_t intvl;
  42. void (*func)();
  43. int arg;
  44. {
  45. register EVENT **evp;
  46. register EVENT *ev;
  47. auto time_t now;
  48. int wasblocked;
  49. if (intvl <= 0)
  50. {
  51. syserr("554 5.3.0 setevent: intvl=%ldn", intvl);
  52. return NULL;
  53. }
  54. wasblocked = blocksignal(SIGALRM);
  55. now = curtime();
  56. /* search event queue for correct position */
  57. for (evp = &EventQueue; (ev = *evp) != NULL; evp = &ev->ev_link)
  58. {
  59. if (ev->ev_time >= now + intvl)
  60. break;
  61. }
  62. /* insert new event */
  63. ev = FreeEventList;
  64. if (ev == NULL)
  65. ev = (EVENT *) xalloc(sizeof *ev);
  66. else
  67. FreeEventList = ev->ev_link;
  68. ev->ev_time = now + intvl;
  69. ev->ev_func = func;
  70. ev->ev_arg = arg;
  71. ev->ev_pid = getpid();
  72. ev->ev_link = *evp;
  73. *evp = ev;
  74. if (tTd(5, 5))
  75. dprintf("setevent: intvl=%ld, for=%ld, func=%lx, arg=%d, ev=%lxn",
  76. (long) intvl, (long)(now + intvl), (u_long) func,
  77. arg, (u_long) ev);
  78. (void) setsignal(SIGALRM, tick);
  79. intvl = EventQueue->ev_time - now;
  80. (void) alarm((unsigned) intvl < 1 ? 1 : intvl);
  81. if (wasblocked == 0)
  82. (void) releasesignal(SIGALRM);
  83. return ev;
  84. }
  85. /*
  86. **  CLREVENT -- remove an event from the event queue.
  87. **
  88. ** Parameters:
  89. ** ev -- pointer to event to remove.
  90. **
  91. ** Returns:
  92. ** none.
  93. **
  94. ** Side Effects:
  95. ** arranges for event ev to not happen.
  96. */
  97. void
  98. clrevent(ev)
  99. register EVENT *ev;
  100. {
  101. register EVENT **evp;
  102. int wasblocked;
  103. if (tTd(5, 5))
  104. dprintf("clrevent: ev=%lxn", (u_long) ev);
  105. if (ev == NULL)
  106. return;
  107. /* find the parent event */
  108. wasblocked = blocksignal(SIGALRM);
  109. for (evp = &EventQueue; *evp != NULL; evp = &(*evp)->ev_link)
  110. {
  111. if (*evp == ev)
  112. break;
  113. }
  114. /* now remove it */
  115. if (*evp != NULL)
  116. {
  117. *evp = ev->ev_link;
  118. ev->ev_link = FreeEventList;
  119. FreeEventList = ev;
  120. }
  121. /* restore clocks and pick up anything spare */
  122. if (wasblocked == 0)
  123. (void) releasesignal(SIGALRM);
  124. if (EventQueue != NULL)
  125. (void) kill(getpid(), SIGALRM);
  126. else
  127. {
  128. /* nothing left in event queue, no need for an alarm */
  129. (void) alarm(0);
  130. }
  131. }
  132. /*
  133. **  CLEAR_EVENTS -- remove all events from the event queue.
  134. **
  135. ** Parameters:
  136. ** none.
  137. **
  138. ** Returns:
  139. ** none.
  140. */
  141. void
  142. clear_events()
  143. {
  144. register EVENT *ev;
  145. int wasblocked;
  146. if (tTd(5, 5))
  147. dprintf("clear_events: EventQueue=%lxn", (u_long) EventQueue);
  148. if (EventQueue == NULL)
  149. return;
  150. /* nothing will be left in event queue, no need for an alarm */
  151. (void) alarm(0);
  152. wasblocked = blocksignal(SIGALRM);
  153. /* find the end of the EventQueue */
  154. for (ev = EventQueue; ev->ev_link != NULL; ev = ev->ev_link)
  155. continue;
  156. ev->ev_link = FreeEventList;
  157. FreeEventList = EventQueue;
  158. EventQueue = NULL;
  159. /* restore clocks and pick up anything spare */
  160. if (wasblocked == 0)
  161. (void) releasesignal(SIGALRM);
  162. }
  163. /*
  164. **  TICK -- take a clock tick
  165. **
  166. ** Called by the alarm clock.  This routine runs events as needed.
  167. ** Always called as a signal handler, so we assume that SIGALRM
  168. ** has been blocked.
  169. **
  170. ** Parameters:
  171. ** One that is ignored; for compatibility with signal handlers.
  172. **
  173. ** Returns:
  174. ** none.
  175. **
  176. ** Side Effects:
  177. ** calls the next function in EventQueue.
  178. */
  179. /* ARGSUSED */
  180. SIGFUNC_DECL
  181. tick(sig)
  182. int sig;
  183. {
  184. register time_t now;
  185. register EVENT *ev;
  186. int mypid = getpid();
  187. int save_errno = errno;
  188. (void) alarm(0);
  189. now = curtime();
  190. if (tTd(5, 4))
  191. dprintf("tick: now=%ldn", (long) now);
  192. /* reset signal in case System V semantics */
  193. (void) setsignal(SIGALRM, tick);
  194. while ((ev = EventQueue) != NULL &&
  195.        (ev->ev_time <= now || ev->ev_pid != mypid))
  196. {
  197. void (*f)();
  198. int arg;
  199. int pid;
  200. /* process the event on the top of the queue */
  201. ev = EventQueue;
  202. EventQueue = EventQueue->ev_link;
  203. if (tTd(5, 6))
  204. dprintf("tick: ev=%lx, func=%lx, arg=%d, pid=%dn",
  205. (u_long) ev, (u_long) ev->ev_func,
  206. ev->ev_arg, ev->ev_pid);
  207. /* we must be careful in here because ev_func may not return */
  208. f = ev->ev_func;
  209. arg = ev->ev_arg;
  210. pid = ev->ev_pid;
  211. ev->ev_link = FreeEventList;
  212. FreeEventList = ev;
  213. if (pid != getpid())
  214. continue;
  215. if (EventQueue != NULL)
  216. {
  217. if (EventQueue->ev_time > now)
  218. (void) alarm((unsigned) (EventQueue->ev_time - now));
  219. else
  220. (void) alarm(3);
  221. }
  222. /* call ev_func */
  223. errno = save_errno;
  224. (*f)(arg);
  225. (void) alarm(0);
  226. now = curtime();
  227. }
  228. if (EventQueue != NULL)
  229. (void) alarm((unsigned) (EventQueue->ev_time - now));
  230. errno = save_errno;
  231. return SIGFUNC_RETURN;
  232. }
  233. /*
  234. **  SLEEP -- a version of sleep that works with this stuff
  235. **
  236. ** Because sleep uses the alarm facility, I must reimplement
  237. ** it here.
  238. **
  239. ** Parameters:
  240. ** intvl -- time to sleep.
  241. **
  242. ** Returns:
  243. ** none.
  244. **
  245. ** Side Effects:
  246. ** waits for intvl time.  However, other events can
  247. ** be run during that interval.
  248. */
  249. static bool SleepDone;
  250. #ifndef SLEEP_T
  251. # define SLEEP_T unsigned int
  252. #endif /* ! SLEEP_T */
  253. SLEEP_T
  254. sleep(intvl)
  255. unsigned int intvl;
  256. {
  257. int was_held;
  258. if (intvl == 0)
  259. return (SLEEP_T) 0;
  260. SleepDone = FALSE;
  261. (void) setevent((time_t) intvl, endsleep, 0);
  262. was_held = releasesignal(SIGALRM);
  263. while (!SleepDone)
  264. (void) pause();
  265. if (was_held > 0)
  266. (void) blocksignal(SIGALRM);
  267. return (SLEEP_T) 0;
  268. }
  269. static void
  270. endsleep()
  271. {
  272. SleepDone = TRUE;
  273. }