Adjust locking to prevent clients from stalling out when memory is reclaimed.
[polipo.git] / event.c
blob91158b3f52b8a1881031e9c0c6b234adaeba15d4
1 /*
2 Copyright (c) 2003-2006 by Juliusz Chroboczek
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
23 #include "polipo.h"
25 #ifdef HAVE_FORK
26 static volatile sig_atomic_t exitFlag = 0;
27 #else
28 static int exitFlag = 0;
29 #endif
30 static int in_signalCondition = 0;
32 static TimeEventHandlerPtr timeEventQueue;
33 static TimeEventHandlerPtr timeEventQueueLast;
35 struct timeval current_time;
36 struct timeval null_time = {0,0};
38 static int fdEventSize = 0;
39 static int fdEventNum = 0;
40 static struct pollfd *poll_fds = NULL;
41 static FdEventHandlerPtr *fdEvents = NULL, *fdEventsLast = NULL;
42 int diskIsClean = 1;
44 static int fds_invalid = 0;
46 static inline int
47 timeval_cmp(struct timeval *t1, struct timeval *t2)
49 if(t1->tv_sec < t2->tv_sec)
50 return -1;
51 else if(t1->tv_sec > t2->tv_sec)
52 return +1;
53 else if(t1->tv_usec < t2->tv_usec)
54 return -1;
55 else if(t1->tv_usec > t2->tv_usec)
56 return +1;
57 else
58 return 0;
61 static inline void
62 timeval_minus(struct timeval *d,
63 const struct timeval *s1, const struct timeval *s2)
65 if(s1->tv_usec > s2->tv_usec) {
66 d->tv_usec = s1->tv_usec - s2->tv_usec;
67 d->tv_sec = s1->tv_sec - s2->tv_sec;
68 } else {
69 d->tv_usec = s1->tv_usec + 1000000 - s2->tv_usec;
70 d->tv_sec = s1->tv_sec - s2->tv_sec - 1;
74 int
75 timeval_minus_usec(const struct timeval *s1, const struct timeval *s2)
77 return (s1->tv_sec - s2->tv_sec) * 1000000 + s1->tv_usec - s2->tv_usec;
80 #ifdef HAVE_FORK
81 static void
82 sigexit(int signo)
84 if(signo == SIGUSR1)
85 exitFlag = 1;
86 else if(signo == SIGUSR2)
87 exitFlag = 2;
88 else
89 exitFlag = 3;
91 #endif
93 void
94 initEvents()
96 #ifdef HAVE_FORK
97 struct sigaction sa;
98 sigset_t ss;
100 sigemptyset(&ss);
101 sa.sa_handler = SIG_IGN;
102 sa.sa_mask = ss;
103 sa.sa_flags = 0;
104 sigaction(SIGPIPE, &sa, NULL);
106 sigemptyset(&ss);
107 sa.sa_handler = sigexit;
108 sa.sa_mask = ss;
109 sa.sa_flags = 0;
110 sigaction(SIGTERM, &sa, NULL);
112 sigemptyset(&ss);
113 sa.sa_handler = sigexit;
114 sa.sa_mask = ss;
115 sa.sa_flags = 0;
116 sigaction(SIGHUP, &sa, NULL);
118 sigemptyset(&ss);
119 sa.sa_handler = sigexit;
120 sa.sa_mask = ss;
121 sa.sa_flags = 0;
122 sigaction(SIGINT, &sa, NULL);
124 sigemptyset(&ss);
125 sa.sa_handler = sigexit;
126 sa.sa_mask = ss;
127 sa.sa_flags = 0;
128 sigaction(SIGUSR1, &sa, NULL);
130 sigemptyset(&ss);
131 sa.sa_handler = sigexit;
132 sa.sa_mask = ss;
133 sa.sa_flags = 0;
134 sigaction(SIGUSR2, &sa, NULL);
135 #endif
137 timeEventQueue = NULL;
138 timeEventQueueLast = NULL;
139 fdEventSize = 0;
140 fdEventNum = 0;
141 poll_fds = NULL;
142 fdEvents = NULL;
143 fdEventsLast = NULL;
146 void
147 uninitEvents(void)
149 #ifdef HAVE_FORK
150 struct sigaction sa;
151 sigset_t ss;
153 sigemptyset(&ss);
154 sa.sa_handler = SIG_DFL;
155 sa.sa_mask = ss;
156 sa.sa_flags = 0;
157 sigaction(SIGTERM, &sa, NULL);
159 sigemptyset(&ss);
160 sa.sa_handler = SIG_DFL;
161 sa.sa_mask = ss;
162 sa.sa_flags = 0;
163 sigaction(SIGHUP, &sa, NULL);
165 sigemptyset(&ss);
166 sa.sa_handler = SIG_DFL;
167 sa.sa_mask = ss;
168 sa.sa_flags = 0;
169 sigaction(SIGINT, &sa, NULL);
171 sigemptyset(&ss);
172 sa.sa_handler = SIG_DFL;
173 sa.sa_mask = ss;
174 sa.sa_flags = 0;
175 sigaction(SIGUSR1, &sa, NULL);
177 sigemptyset(&ss);
178 sa.sa_handler = SIG_DFL;
179 sa.sa_mask = ss;
180 sa.sa_flags = 0;
181 sigaction(SIGUSR2, &sa, NULL);
182 #endif
185 #ifdef HAVE_FORK
186 void
187 interestingSignals(sigset_t *ss)
189 sigemptyset(ss);
190 sigaddset(ss, SIGTERM);
191 sigaddset(ss, SIGHUP);
192 sigaddset(ss, SIGINT);
193 sigaddset(ss, SIGUSR1);
194 sigaddset(ss, SIGUSR2);
196 #endif
198 void
199 timeToSleep(struct timeval *time)
201 if(!timeEventQueue) {
202 time->tv_sec = ~0L;
203 time->tv_usec = ~0L;
204 } else {
205 *time = timeEventQueue->time;
209 static TimeEventHandlerPtr
210 enqueueTimeEvent(TimeEventHandlerPtr event)
212 TimeEventHandlerPtr otherevent;
214 /* We try to optimise two cases -- the event happens very soon, or
215 it happens after most of the other events. */
216 if(timeEventQueue == NULL ||
217 timeval_cmp(&event->time, &timeEventQueue->time) < 0) {
218 /* It's the first event */
219 event->next = timeEventQueue;
220 event->previous = NULL;
221 if(timeEventQueue) {
222 timeEventQueue->previous = event;
223 } else {
224 timeEventQueueLast = event;
226 timeEventQueue = event;
227 } else if(timeval_cmp(&event->time, &timeEventQueueLast->time) >= 0) {
228 /* It's the last one */
229 event->next = NULL;
230 event->previous = timeEventQueueLast;
231 timeEventQueueLast->next = event;
232 timeEventQueueLast = event;
233 } else {
234 /* Walk from the end */
235 otherevent = timeEventQueueLast;
236 while(otherevent->previous &&
237 timeval_cmp(&event->time, &otherevent->previous->time) < 0) {
238 otherevent = otherevent->previous;
240 event->next = otherevent;
241 event->previous = otherevent->previous;
242 if(otherevent->previous) {
243 otherevent->previous->next = event;
244 } else {
245 timeEventQueue = event;
247 otherevent->previous = event;
249 return event;
252 TimeEventHandlerPtr
253 scheduleTimeEvent(int seconds,
254 int (*handler)(TimeEventHandlerPtr), int dsize, void *data)
256 struct timeval when;
257 TimeEventHandlerPtr event;
259 if(seconds >= 0) {
260 when = current_time;
261 when.tv_sec += seconds;
262 } else {
263 when.tv_sec = 0;
264 when.tv_usec = 0;
267 event = malloc(sizeof(TimeEventHandlerRec) - 1 + dsize);
268 if(event == NULL) {
269 do_log(L_ERROR, "Couldn't allocate time event handler -- "
270 "discarding all objects.\n");
271 exitFlag = 2;
272 return NULL;
275 event->time = when;
276 event->handler = handler;
277 /* Let the compiler optimise the common case */
278 if(dsize == sizeof(void*))
279 memcpy(event->data, data, sizeof(void*));
280 else if(dsize > 0)
281 memcpy(event->data, data, dsize);
283 return enqueueTimeEvent(event);
286 void
287 cancelTimeEvent(TimeEventHandlerPtr event)
289 if(event == timeEventQueue)
290 timeEventQueue = event->next;
291 if(event == timeEventQueueLast)
292 timeEventQueueLast = event->previous;
293 if(event->next)
294 event->next->previous = event->previous;
295 if(event->previous)
296 event->previous->next = event->next;
297 free(event);
301 allocateFdEventNum(int fd)
303 int i;
304 if(fdEventNum < fdEventSize) {
305 i = fdEventNum;
306 fdEventNum++;
307 } else {
308 struct pollfd *new_poll_fds;
309 FdEventHandlerPtr *new_fdEvents, *new_fdEventsLast;
310 int new_size = 3 * fdEventSize / 2 + 1;
312 new_poll_fds = realloc(poll_fds, new_size * sizeof(struct pollfd));
313 if(!new_poll_fds)
314 return -1;
315 new_fdEvents = realloc(fdEvents, new_size * sizeof(FdEventHandlerPtr));
316 if(!new_fdEvents)
317 return -1;
318 new_fdEventsLast = realloc(fdEventsLast,
319 new_size * sizeof(FdEventHandlerPtr));
320 if(!new_fdEventsLast)
321 return -1;
323 poll_fds = new_poll_fds;
324 fdEvents = new_fdEvents;
325 fdEventsLast = new_fdEventsLast;
326 fdEventSize = new_size;
327 i = fdEventNum;
328 fdEventNum++;
331 poll_fds[i].fd = fd;
332 poll_fds[i].events = POLLERR | POLLHUP | POLLNVAL;
333 poll_fds[i].revents = 0;
334 fdEvents[i] = NULL;
335 fdEventsLast[i] = NULL;
336 fds_invalid = 1;
337 return i;
340 void
341 deallocateFdEventNum(int i)
343 if(i < fdEventNum - 1) {
344 memmove(&poll_fds[i], &poll_fds[i + 1],
345 (fdEventNum - i - 1) * sizeof(struct pollfd));
346 memmove(&fdEvents[i], &fdEvents[i + 1],
347 (fdEventNum - i - 1) * sizeof(FdEventHandlerPtr));
348 memmove(&fdEventsLast[i], &fdEventsLast[i + 1],
349 (fdEventNum - i - 1) * sizeof(FdEventHandlerPtr));
351 fdEventNum--;
352 fds_invalid = 1;
355 FdEventHandlerPtr
356 makeFdEvent(int fd, int poll_events,
357 int (*handler)(int, FdEventHandlerPtr), int dsize, void *data)
359 FdEventHandlerPtr event;
361 event = malloc(sizeof(FdEventHandlerRec) - 1 + dsize);
362 if(event == NULL) {
363 do_log(L_ERROR, "Couldn't allocate fd event handler -- "
364 "discarding all objects.\n");
365 exitFlag = 2;
366 return NULL;
368 event->fd = fd;
369 event->poll_events = poll_events;
370 event->handler = handler;
371 /* Let the compiler optimise the common cases */
372 if(dsize == sizeof(void*))
373 memcpy(event->data, data, sizeof(void*));
374 else if(dsize == sizeof(StreamRequestRec))
375 memcpy(event->data, data, sizeof(StreamRequestRec));
376 else if(dsize > 0)
377 memcpy(event->data, data, dsize);
378 return event;
381 FdEventHandlerPtr
382 registerFdEventHelper(FdEventHandlerPtr event)
384 int i;
385 int fd = event->fd;
387 for(i = 0; i < fdEventNum; i++)
388 if(poll_fds[i].fd == fd)
389 break;
391 if(i >= fdEventNum)
392 i = allocateFdEventNum(fd);
393 if(i < 0) {
394 free(event);
395 return NULL;
398 event->next = NULL;
399 event->previous = fdEventsLast[i];
400 if(fdEvents[i] == NULL) {
401 fdEvents[i] = event;
402 } else {
403 fdEventsLast[i]->next = event;
405 fdEventsLast[i] = event;
406 poll_fds[i].events |= event->poll_events;
408 return event;
411 FdEventHandlerPtr
412 registerFdEvent(int fd, int poll_events,
413 int (*handler)(int, FdEventHandlerPtr), int dsize, void *data)
415 FdEventHandlerPtr event;
417 event = makeFdEvent(fd, poll_events, handler, dsize, data);
418 if(event == NULL)
419 return NULL;
421 return registerFdEventHelper(event);
424 static int
425 recomputePollEvents(FdEventHandlerPtr event)
427 int pe = 0;
428 while(event) {
429 pe |= event->poll_events;
430 event = event->next;
432 return pe | POLLERR | POLLHUP | POLLNVAL;
435 static void
436 unregisterFdEventI(FdEventHandlerPtr event, int i)
438 assert(i < fdEventNum && poll_fds[i].fd == event->fd);
440 if(fdEvents[i] == event) {
441 assert(!event->previous);
442 fdEvents[i] = event->next;
443 } else {
444 event->previous->next = event->next;
447 if(fdEventsLast[i] == event) {
448 assert(!event->next);
449 fdEventsLast[i] = event->previous;
450 } else {
451 event->next->previous = event->previous;
454 free(event);
456 if(fdEvents[i] == NULL) {
457 deallocateFdEventNum(i);
458 } else {
459 poll_fds[i].events = recomputePollEvents(fdEvents[i]) |
460 POLLERR | POLLHUP | POLLNVAL;
464 void
465 unregisterFdEvent(FdEventHandlerPtr event)
467 int i;
469 for(i = 0; i < fdEventNum; i++) {
470 if(poll_fds[i].fd == event->fd) {
471 unregisterFdEventI(event, i);
472 return;
475 abort();
478 void
479 runTimeEventQueue()
481 TimeEventHandlerPtr event;
482 int done;
484 while(timeEventQueue &&
485 timeval_cmp(&timeEventQueue->time, &current_time) <= 0) {
486 event = timeEventQueue;
487 timeEventQueue = event->next;
488 if(timeEventQueue)
489 timeEventQueue->previous = NULL;
490 else
491 timeEventQueueLast = NULL;
492 done = event->handler(event);
493 assert(done);
494 free(event);
498 static FdEventHandlerPtr
499 findEventHelper(int revents, FdEventHandlerPtr events)
501 FdEventHandlerPtr event = events;
502 while(event) {
503 if(revents & event->poll_events)
504 return event;
505 event = event->next;
507 return NULL;
512 static FdEventHandlerPtr
513 findEvent(int revents, FdEventHandlerPtr events)
515 FdEventHandlerPtr event;
517 assert(!(revents & POLLNVAL));
519 if((revents & POLLHUP) || (revents & POLLERR)) {
520 event = findEventHelper(POLLOUT, events);
521 if(event) return event;
523 event = findEventHelper(POLLIN, events);
524 if(event) return event;
525 return NULL;
528 if(revents & POLLOUT) {
529 event = findEventHelper(POLLOUT, events);
530 if(event) return event;
533 if(revents & POLLIN) {
534 event = findEventHelper(POLLIN, events);
535 if(event) return event;
537 return NULL;
540 typedef struct _FdEventHandlerPoke {
541 int fd;
542 int what;
543 int status;
544 } FdEventHandlerPokeRec, *FdEventHandlerPokePtr;
546 static int
547 pokeFdEventHandler(TimeEventHandlerPtr tevent)
549 FdEventHandlerPokePtr poke = (FdEventHandlerPokePtr)tevent->data;
550 int fd = poke->fd;
551 int what = poke->what;
552 int status = poke->status;
553 int done;
554 FdEventHandlerPtr event, next;
555 int i;
557 for(i = 0; i < fdEventNum; i++) {
558 if(poll_fds[i].fd == fd)
559 break;
562 if(i >= fdEventNum)
563 return 1;
565 event = fdEvents[i];
566 while(event) {
567 next = event->next;
568 if(event->poll_events & what) {
569 done = event->handler(status, event);
570 if(done) {
571 if(fds_invalid)
572 unregisterFdEvent(event);
573 else
574 unregisterFdEventI(event, i);
576 if(fds_invalid)
577 break;
579 event = next;
581 return 1;
584 void
585 pokeFdEvent(int fd, int status, int what)
587 TimeEventHandlerPtr handler;
588 FdEventHandlerPokeRec poke;
590 poke.fd = fd;
591 poke.status = status;
592 poke.what = what;
594 handler = scheduleTimeEvent(0, pokeFdEventHandler,
595 sizeof(poke), &poke);
596 if(!handler) {
597 do_log(L_ERROR, "Couldn't allocate handler.\n");
602 workToDo()
604 struct timeval sleep_time;
605 int rc;
607 if(exitFlag)
608 return 1;
610 timeToSleep(&sleep_time);
611 gettimeofday(&current_time, NULL);
612 if(timeval_cmp(&sleep_time, &current_time) <= 0)
613 return 1;
614 rc = poll(poll_fds, fdEventNum, 0);
615 if(rc < 0) {
616 do_log_error(L_ERROR, errno, "Couldn't poll");
617 return 1;
619 return(rc >= 1);
622 void
623 eventLoop()
625 struct timeval sleep_time, timeout;
626 int rc, i, done, n;
627 FdEventHandlerPtr event;
628 int fd0;
630 gettimeofday(&current_time, NULL);
632 while(1) {
633 again:
634 if(exitFlag) {
635 if(exitFlag < 3)
636 reopenLog();
637 if(exitFlag >= 2) {
638 discardObjects(1, 0);
639 if(exitFlag >= 3)
640 return;
641 free_chunk_arenas();
642 } else {
643 writeoutObjects(1);
645 initForbidden();
646 exitFlag = 0;
649 timeToSleep(&sleep_time);
650 if(sleep_time.tv_sec == -1) {
651 rc = poll(poll_fds, fdEventNum,
652 diskIsClean ? -1 : idleTime * 1000);
653 } else if(timeval_cmp(&sleep_time, &current_time) <= 0) {
654 runTimeEventQueue();
655 continue;
656 } else {
657 gettimeofday(&current_time, NULL);
658 if(timeval_cmp(&sleep_time, &current_time) <= 0) {
659 runTimeEventQueue();
660 continue;
661 } else {
662 int t;
663 timeval_minus(&timeout, &sleep_time, &current_time);
664 t = timeout.tv_sec * 1000 + (timeout.tv_usec + 999) / 1000;
665 rc = poll(poll_fds, fdEventNum,
666 diskIsClean ? t : MIN(idleTime * 1000, t));
670 gettimeofday(&current_time, NULL);
672 if(rc < 0) {
673 if(errno == EINTR) {
674 continue;
675 } else if(errno == ENOMEM) {
676 free_chunk_arenas();
677 do_log(L_ERROR,
678 "Couldn't poll: out of memory. "
679 "Sleeping for one second.\n");
680 sleep(1);
681 } else {
682 do_log_error(L_ERROR, errno, "Couldn't poll");
683 exitFlag = 3;
685 continue;
688 if(rc == 0) {
689 if(!diskIsClean) {
690 timeToSleep(&sleep_time);
691 if(timeval_cmp(&sleep_time, &current_time) > 0)
692 writeoutObjects(0);
694 continue;
697 /* Rather than tracking all changes to the in-memory cache, we
698 assume that something changed whenever we see any activity. */
699 diskIsClean = 0;
701 fd0 =
702 (current_time.tv_usec ^ (current_time.tv_usec >> 16)) % fdEventNum;
703 n = rc;
704 for(i = 0; i < fdEventNum; i++) {
705 int j = (i + fd0) % fdEventNum;
706 if(n <= 0)
707 break;
708 if(poll_fds[j].revents) {
709 n--;
710 event = findEvent(poll_fds[j].revents, fdEvents[j]);
711 if(!event)
712 continue;
713 done = event->handler(0, event);
714 if(done) {
715 if(fds_invalid)
716 unregisterFdEvent(event);
717 else
718 unregisterFdEventI(event, j);
720 if(fds_invalid) {
721 fds_invalid = 0;
722 goto again;
729 void
730 initCondition(ConditionPtr condition)
732 condition->handlers = NULL;
735 ConditionPtr
736 makeCondition(void)
738 ConditionPtr condition;
739 condition = malloc(sizeof(ConditionRec));
740 if(condition == NULL)
741 return NULL;
742 initCondition(condition);
743 return condition;
746 ConditionHandlerPtr
747 conditionWait(ConditionPtr condition,
748 int (*handler)(int, ConditionHandlerPtr),
749 int dsize, void *data)
751 ConditionHandlerPtr chandler;
753 assert(!in_signalCondition);
755 chandler = malloc(sizeof(ConditionHandlerRec) - 1 + dsize);
756 if(!chandler)
757 return NULL;
759 chandler->condition = condition;
760 chandler->handler = handler;
761 /* Let the compiler optimise the common case */
762 if(dsize == sizeof(void*))
763 memcpy(chandler->data, data, sizeof(void*));
764 else if(dsize > 0)
765 memcpy(chandler->data, data, dsize);
767 if(condition->handlers)
768 condition->handlers->previous = chandler;
769 chandler->next = condition->handlers;
770 chandler->previous = NULL;
771 condition->handlers = chandler;
772 return chandler;
775 void
776 unregisterConditionHandler(ConditionHandlerPtr handler)
778 ConditionPtr condition = handler->condition;
780 assert(!in_signalCondition);
782 if(condition->handlers == handler)
783 condition->handlers = condition->handlers->next;
784 if(handler->next)
785 handler->next->previous = handler->previous;
786 if(handler->previous)
787 handler->previous->next = handler->next;
789 free(handler);
792 void
793 abortConditionHandler(ConditionHandlerPtr handler)
795 int done;
796 done = handler->handler(-1, handler);
797 assert(done);
798 unregisterConditionHandler(handler);
801 void
802 signalCondition(ConditionPtr condition)
804 ConditionHandlerPtr handler;
805 int done;
807 assert(!in_signalCondition);
808 in_signalCondition++;
810 handler = condition->handlers;
811 while(handler) {
812 ConditionHandlerPtr next = handler->next;
813 done = handler->handler(0, handler);
814 if(done) {
815 if(handler == condition->handlers)
816 condition->handlers = next;
817 if(next)
818 next->previous = handler->previous;
819 if(handler->previous)
820 handler->previous->next = next;
821 else
822 condition->handlers = next;
823 free(handler);
825 handler = next;
827 in_signalCondition--;
830 void
831 polipoExit()
833 exitFlag = 3;