ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/libev/ev.c
(Generate patch)

Comparing libev/ev.c (file contents):
Revision 1.287 by root, Mon Apr 20 19:45:58 2009 UTC vs.
Revision 1.288 by root, Sat Apr 25 14:12:48 2009 UTC

478#define ev_malloc(size) ev_realloc (0, (size)) 478#define ev_malloc(size) ev_realloc (0, (size))
479#define ev_free(ptr) ev_realloc ((ptr), 0) 479#define ev_free(ptr) ev_realloc ((ptr), 0)
480 480
481/*****************************************************************************/ 481/*****************************************************************************/
482 482
483/* file descriptor info structure */
483typedef struct 484typedef struct
484{ 485{
485 WL head; 486 WL head;
486 unsigned char events; 487 unsigned char events; /* the events watched for */
487 unsigned char reify; 488 unsigned char reify; /* flag set when this ANFD needs reification */
488 unsigned char emask; /* the epoll backend stores the actual kernel mask in here */ 489 unsigned char emask; /* the epoll backend stores the actual kernel mask in here */
489 unsigned char unused; 490 unsigned char unused;
490#if EV_USE_EPOLL 491#if EV_USE_EPOLL
491 unsigned int egen; /* generation counter to counter epoll bugs */ 492 unsigned int egen; /* generation counter to counter epoll bugs */
492#endif 493#endif
493#if EV_SELECT_IS_WINSOCKET 494#if EV_SELECT_IS_WINSOCKET
494 SOCKET handle; 495 SOCKET handle;
495#endif 496#endif
496} ANFD; 497} ANFD;
497 498
499/* stores the pending event set for a given watcher */
498typedef struct 500typedef struct
499{ 501{
500 W w; 502 W w;
501 int events; 503 int events; /* the pending event set for the given watcher */
502} ANPENDING; 504} ANPENDING;
503 505
504#if EV_USE_INOTIFY 506#if EV_USE_INOTIFY
505/* hash table entry per inotify-id */ 507/* hash table entry per inotify-id */
506typedef struct 508typedef struct
509} ANFS; 511} ANFS;
510#endif 512#endif
511 513
512/* Heap Entry */ 514/* Heap Entry */
513#if EV_HEAP_CACHE_AT 515#if EV_HEAP_CACHE_AT
516 /* a heap element */
514 typedef struct { 517 typedef struct {
515 ev_tstamp at; 518 ev_tstamp at;
516 WT w; 519 WT w;
517 } ANHE; 520 } ANHE;
518 521
519 #define ANHE_w(he) (he).w /* access watcher, read-write */ 522 #define ANHE_w(he) (he).w /* access watcher, read-write */
520 #define ANHE_at(he) (he).at /* access cached at, read-only */ 523 #define ANHE_at(he) (he).at /* access cached at, read-only */
521 #define ANHE_at_cache(he) (he).at = (he).w->at /* update at from watcher */ 524 #define ANHE_at_cache(he) (he).at = (he).w->at /* update at from watcher */
522#else 525#else
526 /* a heap element */
523 typedef WT ANHE; 527 typedef WT ANHE;
524 528
525 #define ANHE_w(he) (he) 529 #define ANHE_w(he) (he)
526 #define ANHE_at(he) (he)->at 530 #define ANHE_at(he) (he)->at
527 #define ANHE_at_cache(he) 531 #define ANHE_at_cache(he)
625 629
626/*****************************************************************************/ 630/*****************************************************************************/
627 631
628#define MALLOC_ROUND 4096 /* prefer to allocate in chunks of this size, must be 2**n and >> 4 longs */ 632#define MALLOC_ROUND 4096 /* prefer to allocate in chunks of this size, must be 2**n and >> 4 longs */
629 633
634/* find a suitable new size for the given array, */
635/* hopefully by rounding to a ncie-to-malloc size */
630inline_size int 636inline_size int
631array_nextsize (int elem, int cur, int cnt) 637array_nextsize (int elem, int cur, int cnt)
632{ 638{
633 int ncur = cur + 1; 639 int ncur = cur + 1;
634 640
680#define array_free(stem, idx) \ 686#define array_free(stem, idx) \
681 ev_free (stem ## s idx); stem ## cnt idx = stem ## max idx = 0; stem ## s idx = 0 687 ev_free (stem ## s idx); stem ## cnt idx = stem ## max idx = 0; stem ## s idx = 0
682 688
683/*****************************************************************************/ 689/*****************************************************************************/
684 690
691/* dummy callback for pending events */
692static void noinline
693pendingcb (EV_P_ ev_prepare *w, int revents)
694{
695}
696
685void noinline 697void noinline
686ev_feed_event (EV_P_ void *w, int revents) 698ev_feed_event (EV_P_ void *w, int revents)
687{ 699{
688 W w_ = (W)w; 700 W w_ = (W)w;
689 int pri = ABSPRI (w_); 701 int pri = ABSPRI (w_);
745{ 757{
746 if (fd >= 0 && fd < anfdmax) 758 if (fd >= 0 && fd < anfdmax)
747 fd_event (EV_A_ fd, revents); 759 fd_event (EV_A_ fd, revents);
748} 760}
749 761
762/* make sure the external fd watch events are in-sync */
763/* with the kernel/libev internal state */
750inline_size void 764inline_size void
751fd_reify (EV_P) 765fd_reify (EV_P)
752{ 766{
753 int i; 767 int i;
754 768
789 } 803 }
790 804
791 fdchangecnt = 0; 805 fdchangecnt = 0;
792} 806}
793 807
808/* something about the given fd changed */
794inline_size void 809inline_size void
795fd_change (EV_P_ int fd, int flags) 810fd_change (EV_P_ int fd, int flags)
796{ 811{
797 unsigned char reify = anfds [fd].reify; 812 unsigned char reify = anfds [fd].reify;
798 anfds [fd].reify |= flags; 813 anfds [fd].reify |= flags;
803 array_needsize (int, fdchanges, fdchangemax, fdchangecnt, EMPTY2); 818 array_needsize (int, fdchanges, fdchangemax, fdchangecnt, EMPTY2);
804 fdchanges [fdchangecnt - 1] = fd; 819 fdchanges [fdchangecnt - 1] = fd;
805 } 820 }
806} 821}
807 822
823/* the given fd is invalid/unusable, so make sure it doesn't hurt us anymore */
808inline_speed void 824inline_speed void
809fd_kill (EV_P_ int fd) 825fd_kill (EV_P_ int fd)
810{ 826{
811 ev_io *w; 827 ev_io *w;
812 828
815 ev_io_stop (EV_A_ w); 831 ev_io_stop (EV_A_ w);
816 ev_feed_event (EV_A_ (W)w, EV_ERROR | EV_READ | EV_WRITE); 832 ev_feed_event (EV_A_ (W)w, EV_ERROR | EV_READ | EV_WRITE);
817 } 833 }
818} 834}
819 835
836/* check whether the given fd is atcually valid, for error recovery */
820inline_size int 837inline_size int
821fd_valid (int fd) 838fd_valid (int fd)
822{ 839{
823#ifdef _WIN32 840#ifdef _WIN32
824 return _get_osfhandle (fd) != -1; 841 return _get_osfhandle (fd) != -1;
989 1006
990 heap [k] = he; 1007 heap [k] = he;
991 ev_active (ANHE_w (he)) = k; 1008 ev_active (ANHE_w (he)) = k;
992} 1009}
993 1010
1011/* move an element suitably so it is in a correct place */
994inline_size void 1012inline_size void
995adjustheap (ANHE *heap, int N, int k) 1013adjustheap (ANHE *heap, int N, int k)
996{ 1014{
997 if (k > HEAP0 && ANHE_at (heap [HPARENT (k)]) >= ANHE_at (heap [k])) 1015 if (k > HEAP0 && ANHE_at (heap [HPARENT (k)]) >= ANHE_at (heap [k]))
998 upheap (heap, k); 1016 upheap (heap, k);
1012 upheap (heap, i + HEAP0); 1030 upheap (heap, i + HEAP0);
1013} 1031}
1014 1032
1015/*****************************************************************************/ 1033/*****************************************************************************/
1016 1034
1035/* associate signal watchers to a signal signal */
1017typedef struct 1036typedef struct
1018{ 1037{
1019 WL head; 1038 WL head;
1020 EV_ATOMIC_T gotsig; 1039 EV_ATOMIC_T gotsig;
1021} ANSIG; 1040} ANSIG;
1025 1044
1026static EV_ATOMIC_T gotsig; 1045static EV_ATOMIC_T gotsig;
1027 1046
1028/*****************************************************************************/ 1047/*****************************************************************************/
1029 1048
1049/* used to prepare libev internal fd's */
1050/* this is not fork-safe */
1030inline_speed void 1051inline_speed void
1031fd_intern (int fd) 1052fd_intern (int fd)
1032{ 1053{
1033#ifdef _WIN32 1054#ifdef _WIN32
1034 unsigned long arg = 1; 1055 unsigned long arg = 1;
1040} 1061}
1041 1062
1042static void noinline 1063static void noinline
1043evpipe_init (EV_P) 1064evpipe_init (EV_P)
1044{ 1065{
1045 if (!ev_is_active (&pipeev)) 1066 if (!ev_is_active (&pipe_w))
1046 { 1067 {
1047#if EV_USE_EVENTFD 1068#if EV_USE_EVENTFD
1048 if ((evfd = eventfd (0, 0)) >= 0) 1069 if ((evfd = eventfd (0, 0)) >= 0)
1049 { 1070 {
1050 evpipe [0] = -1; 1071 evpipe [0] = -1;
1051 fd_intern (evfd); 1072 fd_intern (evfd);
1052 ev_io_set (&pipeev, evfd, EV_READ); 1073 ev_io_set (&pipe_w, evfd, EV_READ);
1053 } 1074 }
1054 else 1075 else
1055#endif 1076#endif
1056 { 1077 {
1057 while (pipe (evpipe)) 1078 while (pipe (evpipe))
1058 ev_syserr ("(libev) error creating signal/async pipe"); 1079 ev_syserr ("(libev) error creating signal/async pipe");
1059 1080
1060 fd_intern (evpipe [0]); 1081 fd_intern (evpipe [0]);
1061 fd_intern (evpipe [1]); 1082 fd_intern (evpipe [1]);
1062 ev_io_set (&pipeev, evpipe [0], EV_READ); 1083 ev_io_set (&pipe_w, evpipe [0], EV_READ);
1063 } 1084 }
1064 1085
1065 ev_io_start (EV_A_ &pipeev); 1086 ev_io_start (EV_A_ &pipe_w);
1066 ev_unref (EV_A); /* watcher should not keep loop alive */ 1087 ev_unref (EV_A); /* watcher should not keep loop alive */
1067 } 1088 }
1068} 1089}
1069 1090
1070inline_size void 1091inline_size void
1088 1109
1089 errno = old_errno; 1110 errno = old_errno;
1090 } 1111 }
1091} 1112}
1092 1113
1114/* called whenever the libev signal pipe */
1115/* got some events (signal, async) */
1093static void 1116static void
1094pipecb (EV_P_ ev_io *iow, int revents) 1117pipecb (EV_P_ ev_io *iow, int revents)
1095{ 1118{
1096#if EV_USE_EVENTFD 1119#if EV_USE_EVENTFD
1097 if (evfd >= 0) 1120 if (evfd >= 0)
1179 1202
1180#ifndef WIFCONTINUED 1203#ifndef WIFCONTINUED
1181# define WIFCONTINUED(status) 0 1204# define WIFCONTINUED(status) 0
1182#endif 1205#endif
1183 1206
1207/* handle a single child status event */
1184inline_speed void 1208inline_speed void
1185child_reap (EV_P_ int chain, int pid, int status) 1209child_reap (EV_P_ int chain, int pid, int status)
1186{ 1210{
1187 ev_child *w; 1211 ev_child *w;
1188 int traced = WIFSTOPPED (status) || WIFCONTINUED (status); 1212 int traced = WIFSTOPPED (status) || WIFCONTINUED (status);
1202 1226
1203#ifndef WCONTINUED 1227#ifndef WCONTINUED
1204# define WCONTINUED 0 1228# define WCONTINUED 0
1205#endif 1229#endif
1206 1230
1231/* called on sigchld etc., calls waitpid */
1207static void 1232static void
1208childcb (EV_P_ ev_signal *sw, int revents) 1233childcb (EV_P_ ev_signal *sw, int revents)
1209{ 1234{
1210 int pid, status; 1235 int pid, status;
1211 1236
1336ev_set_timeout_collect_interval (EV_P_ ev_tstamp interval) 1361ev_set_timeout_collect_interval (EV_P_ ev_tstamp interval)
1337{ 1362{
1338 timeout_blocktime = interval; 1363 timeout_blocktime = interval;
1339} 1364}
1340 1365
1366/* initialise a loop structure, must be zero-initialised */
1341static void noinline 1367static void noinline
1342loop_init (EV_P_ unsigned int flags) 1368loop_init (EV_P_ unsigned int flags)
1343{ 1369{
1344 if (!backend) 1370 if (!backend)
1345 { 1371 {
1405#endif 1431#endif
1406#if EV_USE_SELECT 1432#if EV_USE_SELECT
1407 if (!backend && (flags & EVBACKEND_SELECT)) backend = select_init (EV_A_ flags); 1433 if (!backend && (flags & EVBACKEND_SELECT)) backend = select_init (EV_A_ flags);
1408#endif 1434#endif
1409 1435
1436 ev_prepare_init (&pending_w, pendingcb);
1437
1410 ev_init (&pipeev, pipecb); 1438 ev_init (&pipe_w, pipecb);
1411 ev_set_priority (&pipeev, EV_MAXPRI); 1439 ev_set_priority (&pipe_w, EV_MAXPRI);
1412 } 1440 }
1413} 1441}
1414 1442
1443/* free up a loop structure */
1415static void noinline 1444static void noinline
1416loop_destroy (EV_P) 1445loop_destroy (EV_P)
1417{ 1446{
1418 int i; 1447 int i;
1419 1448
1420 if (ev_is_active (&pipeev)) 1449 if (ev_is_active (&pipe_w))
1421 { 1450 {
1422 ev_ref (EV_A); /* signal watcher */ 1451 ev_ref (EV_A); /* signal watcher */
1423 ev_io_stop (EV_A_ &pipeev); 1452 ev_io_stop (EV_A_ &pipe_w);
1424 1453
1425#if EV_USE_EVENTFD 1454#if EV_USE_EVENTFD
1426 if (evfd >= 0) 1455 if (evfd >= 0)
1427 close (evfd); 1456 close (evfd);
1428#endif 1457#endif
1505#endif 1534#endif
1506#if EV_USE_INOTIFY 1535#if EV_USE_INOTIFY
1507 infy_fork (EV_A); 1536 infy_fork (EV_A);
1508#endif 1537#endif
1509 1538
1510 if (ev_is_active (&pipeev)) 1539 if (ev_is_active (&pipe_w))
1511 { 1540 {
1512 /* this "locks" the handlers against writing to the pipe */ 1541 /* this "locks" the handlers against writing to the pipe */
1513 /* while we modify the fd vars */ 1542 /* while we modify the fd vars */
1514 gotsig = 1; 1543 gotsig = 1;
1515#if EV_ASYNC_ENABLE 1544#if EV_ASYNC_ENABLE
1516 gotasync = 1; 1545 gotasync = 1;
1517#endif 1546#endif
1518 1547
1519 ev_ref (EV_A); 1548 ev_ref (EV_A);
1520 ev_io_stop (EV_A_ &pipeev); 1549 ev_io_stop (EV_A_ &pipe_w);
1521 1550
1522#if EV_USE_EVENTFD 1551#if EV_USE_EVENTFD
1523 if (evfd >= 0) 1552 if (evfd >= 0)
1524 close (evfd); 1553 close (evfd);
1525#endif 1554#endif
1530 close (evpipe [1]); 1559 close (evpipe [1]);
1531 } 1560 }
1532 1561
1533 evpipe_init (EV_A); 1562 evpipe_init (EV_A);
1534 /* now iterate over everything, in case we missed something */ 1563 /* now iterate over everything, in case we missed something */
1535 pipecb (EV_A_ &pipeev, EV_READ); 1564 pipecb (EV_A_ &pipe_w, EV_READ);
1536 } 1565 }
1537 1566
1538 postfork = 0; 1567 postfork = 0;
1539} 1568}
1540 1569
1746 for (pri = NUMPRI; pri--; ) 1775 for (pri = NUMPRI; pri--; )
1747 while (pendingcnt [pri]) 1776 while (pendingcnt [pri])
1748 { 1777 {
1749 ANPENDING *p = pendings [pri] + --pendingcnt [pri]; 1778 ANPENDING *p = pendings [pri] + --pendingcnt [pri];
1750 1779
1751 if (expect_true (p->w))
1752 {
1753 /*assert (("libev: non-pending watcher on pending list", p->w->pending));*/ 1780 /*assert (("libev: non-pending watcher on pending list", p->w->pending));*/
1781 /* ^ this is no longer true, as pending_w could be here */
1754 1782
1755 p->w->pending = 0; 1783 p->w->pending = 0;
1756 EV_CB_INVOKE (p->w, p->events); 1784 EV_CB_INVOKE (p->w, p->events);
1757 EV_FREQUENT_CHECK; 1785 EV_FREQUENT_CHECK;
1758 }
1759 } 1786 }
1760} 1787}
1761 1788
1762#if EV_IDLE_ENABLE 1789#if EV_IDLE_ENABLE
1790/* make idle watchers pending. this handles the "call-idle */
1791/* only when higher priorities are idle" logic */
1763inline_size void 1792inline_size void
1764idle_reify (EV_P) 1793idle_reify (EV_P)
1765{ 1794{
1766 if (expect_false (idleall)) 1795 if (expect_false (idleall))
1767 { 1796 {
1780 } 1809 }
1781 } 1810 }
1782} 1811}
1783#endif 1812#endif
1784 1813
1814/* make timers pending */
1785inline_size void 1815inline_size void
1786timers_reify (EV_P) 1816timers_reify (EV_P)
1787{ 1817{
1788 EV_FREQUENT_CHECK; 1818 EV_FREQUENT_CHECK;
1789 1819
1818 feed_reverse_done (EV_A_ EV_TIMEOUT); 1848 feed_reverse_done (EV_A_ EV_TIMEOUT);
1819 } 1849 }
1820} 1850}
1821 1851
1822#if EV_PERIODIC_ENABLE 1852#if EV_PERIODIC_ENABLE
1853/* make periodics pending */
1823inline_size void 1854inline_size void
1824periodics_reify (EV_P) 1855periodics_reify (EV_P)
1825{ 1856{
1826 EV_FREQUENT_CHECK; 1857 EV_FREQUENT_CHECK;
1827 1858
1874 1905
1875 feed_reverse_done (EV_A_ EV_PERIODIC); 1906 feed_reverse_done (EV_A_ EV_PERIODIC);
1876 } 1907 }
1877} 1908}
1878 1909
1910/* simply recalculate all periodics */
1911/* TODO: maybe ensure that at leats one event happens when jumping forward? */
1879static void noinline 1912static void noinline
1880periodics_reschedule (EV_P) 1913periodics_reschedule (EV_P)
1881{ 1914{
1882 int i; 1915 int i;
1883 1916
1896 1929
1897 reheap (periodics, periodiccnt); 1930 reheap (periodics, periodiccnt);
1898} 1931}
1899#endif 1932#endif
1900 1933
1934/* adjust all timers by a given offset */
1901static void noinline 1935static void noinline
1902timers_reschedule (EV_P_ ev_tstamp adjust) 1936timers_reschedule (EV_P_ ev_tstamp adjust)
1903{ 1937{
1904 int i; 1938 int i;
1905 1939
1909 ANHE_w (*he)->at += adjust; 1943 ANHE_w (*he)->at += adjust;
1910 ANHE_at_cache (*he); 1944 ANHE_at_cache (*he);
1911 } 1945 }
1912} 1946}
1913 1947
1948/* fetch new monotonic and realtime times from the kernel */
1949/* also detetc if there was a timejump, and act accordingly */
1914inline_speed void 1950inline_speed void
1915time_update (EV_P_ ev_tstamp max_block) 1951time_update (EV_P_ ev_tstamp max_block)
1916{ 1952{
1917 int i; 1953 int i;
1918 1954
2137 ev_tstamp mn_prev = mn_now; 2173 ev_tstamp mn_prev = mn_now;
2138 2174
2139 ev_now_update (EV_A); 2175 ev_now_update (EV_A);
2140 timers_reschedule (EV_A_ mn_now - mn_prev); 2176 timers_reschedule (EV_A_ mn_now - mn_prev);
2141#if EV_PERIODIC_ENABLE 2177#if EV_PERIODIC_ENABLE
2178 /* TODO: really do this? */
2142 periodics_reschedule (EV_A); 2179 periodics_reschedule (EV_A);
2143#endif 2180#endif
2144} 2181}
2145 2182
2146/*****************************************************************************/ 2183/*****************************************************************************/
2184/* singly-linked list management, used when the expected list length is short */
2147 2185
2148inline_size void 2186inline_size void
2149wlist_add (WL *head, WL elem) 2187wlist_add (WL *head, WL elem)
2150{ 2188{
2151 elem->next = *head; 2189 elem->next = *head;
2165 2203
2166 head = &(*head)->next; 2204 head = &(*head)->next;
2167 } 2205 }
2168} 2206}
2169 2207
2208/* internal, faster, version of ev_clear_pending */
2170inline_speed void 2209inline_speed void
2171clear_pending (EV_P_ W w) 2210clear_pending (EV_P_ W w)
2172{ 2211{
2173 if (w->pending) 2212 if (w->pending)
2174 { 2213 {
2175 pendings [ABSPRI (w)][w->pending - 1].w = 0; 2214 pendings [ABSPRI (w)][w->pending - 1].w = (W)&pending_w;
2176 w->pending = 0; 2215 w->pending = 0;
2177 } 2216 }
2178} 2217}
2179 2218
2180int 2219int
2184 int pending = w_->pending; 2223 int pending = w_->pending;
2185 2224
2186 if (expect_true (pending)) 2225 if (expect_true (pending))
2187 { 2226 {
2188 ANPENDING *p = pendings [ABSPRI (w_)] + pending - 1; 2227 ANPENDING *p = pendings [ABSPRI (w_)] + pending - 1;
2228 p->w = (W)&pending_w;
2189 w_->pending = 0; 2229 w_->pending = 0;
2190 p->w = 0;
2191 return p->events; 2230 return p->events;
2192 } 2231 }
2193 else 2232 else
2194 return 0; 2233 return 0;
2195} 2234}
3201 } 3240 }
3202} 3241}
3203 3242
3204/*****************************************************************************/ 3243/*****************************************************************************/
3205 3244
3206#if 0 3245#if EV_WALK_ENABLE
3207void 3246void
3208ev_walk (EV_P_ int types, void (*cb)(EV_P_ int type, void *w)) 3247ev_walk (EV_P_ int types, void (*cb)(EV_P_ int type, void *w))
3209{ 3248{
3210 int i, j; 3249 int i, j;
3211 ev_watcher_list *wl, *wn; 3250 ev_watcher_list *wl, *wn;
3227#if EV_USE_INOTIFY 3266#if EV_USE_INOTIFY
3228 if (ev_cb ((ev_io *)wl) == infy_cb) 3267 if (ev_cb ((ev_io *)wl) == infy_cb)
3229 ; 3268 ;
3230 else 3269 else
3231#endif 3270#endif
3232 if ((ev_io *)wl != &pipeev) 3271 if ((ev_io *)wl != &pipe_w)
3233 if (types & EV_IO) 3272 if (types & EV_IO)
3234 cb (EV_A_ EV_IO, wl); 3273 cb (EV_A_ EV_IO, wl);
3235 3274
3236 wl = wn; 3275 wl = wn;
3237 } 3276 }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines