122696Sdist /* 2*34920Sbostic * Copyright (c) 1983 Eric P. Allman 333728Sbostic * Copyright (c) 1988 Regents of the University of California. 433728Sbostic * All rights reserved. 533728Sbostic * 633728Sbostic * Redistribution and use in source and binary forms are permitted 7*34920Sbostic * provided that the above copyright notice and this paragraph are 8*34920Sbostic * duplicated in all such forms and that any documentation, 9*34920Sbostic * advertising materials, and other materials related to such 10*34920Sbostic * distribution and use acknowledge that the software was developed 11*34920Sbostic * by the University of California, Berkeley. The name of the 12*34920Sbostic * University may not be used to endorse or promote products derived 13*34920Sbostic * from this software without specific prior written permission. 14*34920Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 15*34920Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 16*34920Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1733728Sbostic */ 1822696Sdist 1922696Sdist #ifndef lint 20*34920Sbostic static char sccsid[] = "@(#)clock.c 5.6 (Berkeley) 06/30/88"; 2133728Sbostic #endif /* not lint */ 2222696Sdist 237358Seric # include "sendmail.h" 2411728Seric # include <signal.h> 257358Seric 267358Seric /* 277684Seric ** SETEVENT -- set an event to happen at a specific time. 287684Seric ** 299373Seric ** Events are stored in a sorted list for fast processing. 309373Seric ** An event only applies to the process that set it. 319373Seric ** 327684Seric ** Parameters: 337684Seric ** intvl -- intvl until next event occurs. 347684Seric ** func -- function to call on event. 357684Seric ** arg -- argument to func on event. 367684Seric ** 377684Seric ** Returns: 387684Seric ** none. 397684Seric ** 407684Seric ** Side Effects: 417684Seric ** none. 427684Seric */ 437684Seric 447684Seric EVENT * 457684Seric setevent(intvl, func, arg) 467684Seric time_t intvl; 477684Seric int (*func)(); 487684Seric int arg; 497684Seric { 507684Seric register EVENT **evp; 517684Seric register EVENT *ev; 527684Seric auto time_t now; 537684Seric extern tick(); 547684Seric 557757Seric # ifdef DEBUG 567757Seric if (intvl <= 0) 577757Seric { 587757Seric syserr("setevent: intvl=%ld\n", intvl); 599346Seric return (NULL); 607757Seric } 617757Seric # endif DEBUG 627757Seric 637684Seric (void) time(&now); 647684Seric 657684Seric /* search event queue for correct position */ 667684Seric for (evp = &EventQueue; (ev = *evp) != NULL; evp = &ev->ev_link) 677684Seric { 687684Seric if (ev->ev_time >= now + intvl) 697684Seric break; 707684Seric } 717684Seric 727684Seric /* insert new event */ 737684Seric ev = (EVENT *) xalloc(sizeof *ev); 747684Seric ev->ev_time = now + intvl; 757684Seric ev->ev_func = func; 767684Seric ev->ev_arg = arg; 777931Seric ev->ev_pid = getpid(); 787684Seric ev->ev_link = *evp; 797684Seric *evp = ev; 807684Seric 817684Seric # ifdef DEBUG 828063Seric if (tTd(5, 5)) 837684Seric printf("setevent: intvl=%ld, for=%ld, func=%x, arg=%d, ev=%x\n", 847684Seric intvl, now + intvl, func, arg, ev); 857684Seric # endif DEBUG 867684Seric 877939Seric tick(); 887684Seric return (ev); 897684Seric } 907684Seric /* 917684Seric ** CLREVENT -- remove an event from the event queue. 927684Seric ** 937684Seric ** Parameters: 947684Seric ** ev -- pointer to event to remove. 957684Seric ** 967684Seric ** Returns: 977684Seric ** none. 987684Seric ** 997684Seric ** Side Effects: 1007684Seric ** arranges for event ev to not happen. 1017684Seric */ 1027684Seric 1037684Seric clrevent(ev) 1047684Seric register EVENT *ev; 1057684Seric { 1067684Seric register EVENT **evp; 1077684Seric 1087684Seric # ifdef DEBUG 1098063Seric if (tTd(5, 5)) 1107684Seric printf("clrevent: ev=%x\n", ev); 1117684Seric # endif DEBUG 1127757Seric if (ev == NULL) 1137757Seric return; 1147684Seric 1157684Seric /* find the parent event */ 1169373Seric (void) signal(SIGALRM, SIG_IGN); 1177684Seric for (evp = &EventQueue; *evp != NULL; evp = &(*evp)->ev_link) 1187684Seric { 1197684Seric if (*evp == ev) 1207684Seric break; 1217684Seric } 1227684Seric 1237684Seric /* now remove it */ 1247939Seric if (*evp != NULL) 1257939Seric { 1267939Seric *evp = ev->ev_link; 1279346Seric free((char *) ev); 1287939Seric } 1297862Seric 1307862Seric /* restore clocks and pick up anything spare */ 1317862Seric tick(); 1327684Seric } 1337684Seric /* 1347358Seric ** TICK -- take a clock tick 1357358Seric ** 1367684Seric ** Called by the alarm clock. This routine runs events as needed. 1377358Seric ** 1387358Seric ** Parameters: 1397358Seric ** none. 1407358Seric ** 1417358Seric ** Returns: 1427684Seric ** none. 1437358Seric ** 1447358Seric ** Side Effects: 1457684Seric ** calls the next function in EventQueue. 1467358Seric */ 1477358Seric 1487358Seric tick() 1497358Seric { 1507889Seric register time_t now; 1517684Seric register EVENT *ev; 15224955Seric int mypid = getpid(); 1537684Seric 1549373Seric (void) signal(SIGALRM, SIG_IGN); 1559373Seric (void) alarm(0); 1567889Seric now = curtime(); 1577684Seric 1587358Seric # ifdef DEBUG 1598063Seric if (tTd(5, 4)) 1607684Seric printf("tick: now=%ld\n", now); 1617358Seric # endif DEBUG 1627684Seric 1638128Seric while ((ev = EventQueue) != NULL && 16424955Seric (ev->ev_time <= now || ev->ev_pid != mypid)) 1657684Seric { 16616141Seric int (*f)(); 16716141Seric int arg; 16816141Seric int pid; 1697862Seric 1707684Seric /* process the event on the top of the queue */ 1717684Seric ev = EventQueue; 1727684Seric EventQueue = EventQueue->ev_link; 1737684Seric # ifdef DEBUG 1748063Seric if (tTd(5, 6)) 1757931Seric printf("tick: ev=%x, func=%x, arg=%d, pid=%d\n", ev, 1767931Seric ev->ev_func, ev->ev_arg, ev->ev_pid); 1777684Seric # endif DEBUG 1787862Seric 1797862Seric /* we must be careful in here because ev_func may not return */ 1809373Seric (void) signal(SIGALRM, tick); 18120844Seric #ifdef SIGVTALRM 18220844Seric /* reset 4.2bsd signal mask to allow future alarms */ 18320844Seric (void) sigsetmask(sigblock(0) & ~sigmask(SIGALRM)); 18420844Seric #endif SIGVTALRM 18520844Seric 1867862Seric f = ev->ev_func; 18716141Seric arg = ev->ev_arg; 18816141Seric pid = ev->ev_pid; 1899346Seric free((char *) ev); 19016141Seric if (pid != getpid()) 1917931Seric continue; 1927862Seric if (EventQueue != NULL) 1937862Seric { 1947862Seric if (EventQueue->ev_time > now) 19512635Seric (void) alarm((unsigned) (EventQueue->ev_time - now)); 1967862Seric else 1977889Seric (void) alarm(3); 1987862Seric } 19916141Seric (*f)(arg); 2007862Seric (void) alarm(0); 2017889Seric now = curtime(); 2027684Seric } 2039373Seric (void) signal(SIGALRM, tick); 2047889Seric if (EventQueue != NULL) 20512635Seric (void) alarm((unsigned) (EventQueue->ev_time - now)); 2067358Seric } 2077690Seric /* 2087690Seric ** SLEEP -- a version of sleep that works with this stuff 2097690Seric ** 2107690Seric ** Because sleep uses the alarm facility, I must reimplement 2117690Seric ** it here. 2127690Seric ** 2137690Seric ** Parameters: 2147690Seric ** intvl -- time to sleep. 2157690Seric ** 2167690Seric ** Returns: 2177690Seric ** none. 2187690Seric ** 2197690Seric ** Side Effects: 2207690Seric ** waits for intvl time. However, other events can 2217690Seric ** be run during that interval. 2227690Seric */ 2237690Seric 2247690Seric static bool SleepDone; 2257690Seric 2267690Seric sleep(intvl) 22725615Seric unsigned int intvl; 2287690Seric { 2297690Seric extern endsleep(); 2307690Seric 2317757Seric if (intvl == 0) 2327757Seric return; 2337690Seric SleepDone = FALSE; 23412635Seric (void) setevent((time_t) intvl, endsleep, 0); 2357690Seric while (!SleepDone) 2367690Seric pause(); 2377690Seric } 2387690Seric 2397690Seric static 2407690Seric endsleep() 2417690Seric { 2427690Seric SleepDone = TRUE; 2437690Seric } 244