--- libev/ev.c 2009/09/18 21:02:12 1.316 +++ libev/ev.c 2010/02/16 09:32:39 1.329 @@ -1,7 +1,7 @@ /* * libev event processing core, watcher management * - * Copyright (c) 2007,2008,2009 Marc Alexander Lehmann + * Copyright (c) 2007,2008,2009,2010 Marc Alexander Lehmann * All rights reserved. * * Redistribution and use in source and binary forms, with or without modifica- @@ -112,7 +112,7 @@ # endif # ifndef EV_USE_KQUEUE -# if HAVE_KQUEUE && HAVE_SYS_EVENT_H && HAVE_SYS_QUEUE_H +# if HAVE_KQUEUE && HAVE_SYS_EVENT_H # define EV_USE_KQUEUE 1 # else # define EV_USE_KQUEUE 0 @@ -155,6 +155,7 @@ #include #include +#include #include #include @@ -164,6 +165,7 @@ #include #include #include +#include #include @@ -345,6 +347,12 @@ /* this block fixes any misconfiguration where we know we run into trouble otherwise */ +#ifdef _AIX +/* AIX has a completely broken poll.h header */ +# undef EV_USE_POLL +# define EV_USE_POLL 0 +#endif + #ifndef CLOCK_MONOTONIC # undef EV_USE_MONOTONIC # define EV_USE_MONOTONIC 0 @@ -397,7 +405,7 @@ # ifdef __cplusplus extern "C" { # endif -int eventfd (unsigned int initval, int flags); +int (eventfd) (unsigned int initval, int flags); # ifdef __cplusplus } # endif @@ -506,7 +514,7 @@ # define EV_FD_TO_WIN32_HANDLE(fd) _get_osfhandle (fd) #endif #ifndef EV_WIN32_HANDLE_TO_FD -# define EV_WIN32_HANDLE_TO_FD(handle) _open_osfhandle (fd, 0) +# define EV_WIN32_HANDLE_TO_FD(handle) _open_osfhandle (handle, 0) #endif #ifndef EV_WIN32_CLOSE_FD # define EV_WIN32_CLOSE_FD(fd) close (fd) @@ -965,7 +973,7 @@ fd_valid (int fd) { #ifdef _WIN32 - return _get_osfhandle (fd) != -1; + return EV_FD_TO_WIN32_HANDLE (fd) != -1; #else return fcntl (fd, F_GETFD) != -1; #endif @@ -1180,7 +1188,7 @@ { #ifdef _WIN32 unsigned long arg = 1; - ioctlsocket (_get_osfhandle (fd), FIONBIO, &arg); + ioctlsocket (EV_FD_TO_WIN32_HANDLE (fd), FIONBIO, &arg); #else fcntl (fd, F_SETFD, FD_CLOEXEC); fcntl (fd, F_SETFL, O_NONBLOCK); @@ -1295,7 +1303,7 @@ EV_P = signals [signum - 1].loop; #endif -#if _WIN32 +#ifdef _WIN32 signal (signum, ev_sighandler); #endif @@ -1606,7 +1614,7 @@ fs_fd = flags & EVFLAG_NOINOTIFY ? -1 : -2; #endif #if EV_USE_SIGNALFD - sigfd = flags & EVFLAG_NOSIGFD ? -1 : -2; + sigfd = flags & EVFLAG_SIGNALFD ? -2 : -1; #endif if (!(flags & 0x0000ffffU)) @@ -1660,12 +1668,7 @@ #if EV_USE_SIGNALFD if (ev_is_active (&sigfd_w)) - { - /*ev_ref (EV_A);*/ - /*ev_io_stop (EV_A_ &sigfd_w);*/ - - close (sigfd); - } + close (sigfd); #endif #if EV_USE_INOTIFY @@ -2163,7 +2166,7 @@ } /* fetch new monotonic and realtime times from the kernel */ -/* also detetc if there was a timejump, and act accordingly */ +/* also detect if there was a timejump, and act accordingly */ inline_speed void time_update (EV_P_ ev_tstamp max_block) { @@ -2507,7 +2510,7 @@ return; assert (("libev: ev_io_start called with negative fd", fd >= 0)); - assert (("libev: ev_io start called with illegal event mask", !(w->events & ~(EV__IOFDSET | EV_READ | EV_WRITE)))); + assert (("libev: ev_io_start called with illegal event mask", !(w->events & ~(EV__IOFDSET | EV_READ | EV_WRITE)))); EV_FREQUENT_CHECK; @@ -2587,11 +2590,11 @@ } } - EV_FREQUENT_CHECK; - ev_at (w) -= mn_now; ev_stop (EV_A_ (W)w); + + EV_FREQUENT_CHECK; } void noinline @@ -2680,9 +2683,9 @@ } } - EV_FREQUENT_CHECK; - ev_stop (EV_A_ (W)w); + + EV_FREQUENT_CHECK; } void noinline @@ -2753,7 +2756,9 @@ if (sigfd < 0) /*TODO*/ # endif { -# if _WIN32 +# ifdef _WIN32 + evpipe_init (EV_A); + signal (w->signum, ev_sighandler); # else struct sigaction sa; @@ -2794,11 +2799,14 @@ #if EV_USE_SIGNALFD if (sigfd >= 0) { - sigprocmask (SIG_UNBLOCK, &sigfd_set, 0);//D + sigset_t ss; + + sigemptyset (&ss); + sigaddset (&ss, w->signum); sigdelset (&sigfd_set, w->signum); + signalfd (sigfd, &sigfd_set, 0); - sigprocmask (SIG_BLOCK, &sigfd_set, 0);//D - /*TODO: maybe unblock signal? */ + sigprocmask (SIG_UNBLOCK, &ss, 0); } else #endif @@ -2854,19 +2862,42 @@ static void noinline stat_timer_cb (EV_P_ ev_timer *w_, int revents); #if EV_USE_INOTIFY -# define EV_INOTIFY_BUFSIZE 8192 + +/* the * 2 is to allow for alignment padding, which for some reason is >> 8 */ +# define EV_INOTIFY_BUFSIZE (sizeof (struct inotify_event) * 2 + NAME_MAX) static void noinline infy_add (EV_P_ ev_stat *w) { w->wd = inotify_add_watch (fs_fd, w->path, IN_ATTRIB | IN_DELETE_SELF | IN_MOVE_SELF | IN_MODIFY | IN_DONT_FOLLOW | IN_MASK_ADD); - if (w->wd < 0) + if (w->wd >= 0) + { + struct statfs sfs; + + /* now local changes will be tracked by inotify, but remote changes won't */ + /* unless the filesystem is known to be local, we therefore still poll */ + /* also do poll on <2.6.25, but with normal frequency */ + + if (!fs_2625) + w->timer.repeat = w->interval ? w->interval : DEF_STAT_INTERVAL; + else if (!statfs (w->path, &sfs) + && (sfs.f_type == 0x1373 /* devfs */ + || sfs.f_type == 0xEF53 /* ext2/3 */ + || sfs.f_type == 0x3153464a /* jfs */ + || sfs.f_type == 0x52654973 /* reiser3 */ + || sfs.f_type == 0x01021994 /* tempfs */ + || sfs.f_type == 0x58465342 /* xfs */)) + w->timer.repeat = 0.; /* filesystem is local, kernel new enough */ + else + w->timer.repeat = w->interval ? w->interval : NFS_STAT_INTERVAL; /* remote, use reduced frequency */ + } + else { + /* can't use inotify, continue to stat */ w->timer.repeat = w->interval ? w->interval : DEF_STAT_INTERVAL; - ev_timer_again (EV_A_ &w->timer); /* this is not race-free, so we still need to recheck periodically */ - /* monitor some parent directory for speedup hints */ + /* if path is not there, monitor some parent directory for speedup hints */ /* note that exceeding the hardcoded path limit is not a correctness issue, */ /* but an efficiency issue only */ if ((errno == ENOENT || errno == EACCES) && strlen (w->path) < 4096) @@ -2892,27 +2923,12 @@ } if (w->wd >= 0) - { - struct statfs sfs; - - wlist_add (&fs_hash [w->wd & (EV_INOTIFY_HASHSIZE - 1)].head, (WL)w); - - /* now local changes will be tracked by inotify, but remote changes won't */ - /* unless the filesystem it known to be local, we therefore still poll */ - /* also do poll on <2.6.25, but with normal frequency */ - - if (fs_2625 && !statfs (w->path, &sfs)) - if (sfs.f_type == 0x1373 /* devfs */ - || sfs.f_type == 0xEF53 /* ext2/3 */ - || sfs.f_type == 0x3153464a /* jfs */ - || sfs.f_type == 0x52654973 /* reiser3 */ - || sfs.f_type == 0x01021994 /* tempfs */ - || sfs.f_type == 0x58465342 /* xfs */) - return; + wlist_add (&fs_hash [w->wd & (EV_INOTIFY_HASHSIZE - 1)].head, (WL)w); - w->timer.repeat = w->interval ? w->interval : fs_2625 ? NFS_STAT_INTERVAL : DEF_STAT_INTERVAL; - ev_timer_again (EV_A_ &w->timer); - } + /* now re-arm timer, if required */ + if (ev_is_active (&w->timer)) ev_ref (EV_A); + ev_timer_again (EV_A_ &w->timer); + if (ev_is_active (&w->timer)) ev_unref (EV_A); } static void noinline @@ -2967,12 +2983,15 @@ infy_cb (EV_P_ ev_io *w, int revents) { char buf [EV_INOTIFY_BUFSIZE]; - struct inotify_event *ev = (struct inotify_event *)buf; int ofs; int len = read (fs_fd, buf, sizeof (buf)); - for (ofs = 0; ofs < len; ofs += sizeof (struct inotify_event) + ev->len) - infy_wd (EV_A_ ev->wd, ev->wd, ev); + for (ofs = 0; ofs < len; ) + { + struct inotify_event *ev = (struct inotify_event *)(buf + ofs); + infy_wd (EV_A_ ev->wd, ev->wd, ev); + ofs += sizeof (struct inotify_event) + ev->len; + } } inline_size void @@ -3027,6 +3046,7 @@ ev_io_init (&fs_w, infy_cb, fs_fd, EV_READ); ev_set_priority (&fs_w, EV_MAXPRI); ev_io_start (EV_A_ &fs_w); + ev_unref (EV_A); } } @@ -3038,6 +3058,7 @@ if (fs_fd < 0) return; + ev_ref (EV_A); ev_io_stop (EV_A_ &fs_w); close (fs_fd); fs_fd = infy_newfd (); @@ -3047,6 +3068,7 @@ fd_intern (fs_fd); ev_io_set (&fs_w, fs_fd, EV_READ); ev_io_start (EV_A_ &fs_w); + ev_unref (EV_A); } for (slot = 0; slot < EV_INOTIFY_HASHSIZE; ++slot) @@ -3064,7 +3086,12 @@ if (fs_fd >= 0) infy_add (EV_A_ w); /* re-add, no matter what */ else - ev_timer_again (EV_A_ &w->timer); + { + w->timer.repeat = w->interval ? w->interval : DEF_STAT_INTERVAL; + if (ev_is_active (&w->timer)) ev_ref (EV_A); + ev_timer_again (EV_A_ &w->timer); + if (ev_is_active (&w->timer)) ev_unref (EV_A); + } } } } @@ -3091,25 +3118,28 @@ { ev_stat *w = (ev_stat *)(((char *)w_) - offsetof (ev_stat, timer)); - /* we copy this here each the time so that */ - /* prev has the old value when the callback gets invoked */ - w->prev = w->attr; + ev_statdata prev = w->attr; ev_stat_stat (EV_A_ w); /* memcmp doesn't work on netbsd, they.... do stuff to their struct stat */ if ( - w->prev.st_dev != w->attr.st_dev - || w->prev.st_ino != w->attr.st_ino - || w->prev.st_mode != w->attr.st_mode - || w->prev.st_nlink != w->attr.st_nlink - || w->prev.st_uid != w->attr.st_uid - || w->prev.st_gid != w->attr.st_gid - || w->prev.st_rdev != w->attr.st_rdev - || w->prev.st_size != w->attr.st_size - || w->prev.st_atime != w->attr.st_atime - || w->prev.st_mtime != w->attr.st_mtime - || w->prev.st_ctime != w->attr.st_ctime + prev.st_dev != w->attr.st_dev + || prev.st_ino != w->attr.st_ino + || prev.st_mode != w->attr.st_mode + || prev.st_nlink != w->attr.st_nlink + || prev.st_uid != w->attr.st_uid + || prev.st_gid != w->attr.st_gid + || prev.st_rdev != w->attr.st_rdev + || prev.st_size != w->attr.st_size + || prev.st_atime != w->attr.st_atime + || prev.st_mtime != w->attr.st_mtime + || prev.st_ctime != w->attr.st_ctime ) { + /* we only update w->prev on actual differences */ + /* in case we test more often than invoke the callback, */ + /* to ensure that prev is always different to attr */ + w->prev = prev; + #if EV_USE_INOTIFY if (fs_fd >= 0) { @@ -3144,7 +3174,10 @@ infy_add (EV_A_ w); else #endif - ev_timer_again (EV_A_ &w->timer); + { + ev_timer_again (EV_A_ &w->timer); + ev_unref (EV_A); + } ev_start (EV_A_ (W)w, 1); @@ -3163,7 +3196,12 @@ #if EV_USE_INOTIFY infy_del (EV_A_ w); #endif - ev_timer_stop (EV_A_ &w->timer); + + if (ev_is_active (&w->timer)) + { + ev_ref (EV_A); + ev_timer_stop (EV_A_ &w->timer); + } ev_stop (EV_A_ (W)w); @@ -3393,6 +3431,8 @@ ev_prepare_stop (EV_A_ &w->prepare); ev_fork_stop (EV_A_ &w->fork); + ev_stop (EV_A_ (W)w); + EV_FREQUENT_CHECK; } #endif