new inotify options ...I

12 views
Skip to first unread message

Steven Parkes

unread,
Nov 2, 2009, 3:34:01 PM11/2/09
to eventm...@googlegroups.com
I was wondering if we can get some more inotify options on the file
watcher, e.g.,

http://github.com/smparkes/eventmachine/commit/0dc5780ce28b1ad7a7107ca1b20faba031ff3ef5

(sorry for the fprintf cruft).

I need to be able to see directory modifications and they're triggerd
via things like IN_MOVE.

Seems like a pretty small change. It shouldn't effect the results for
files, since these flags should only affect directories. It'll affect
anyone putting watches on directories, but since few events fire for
directories w/o these flags, I wonder if there are many of folks like
that.

I don't pull out the path from the results, but I do provide a buffer
for the result, otherwise read returns EINVAL. Not sure how to come up
with a size ... The failure case right now should you hit it is kinda
nasty. Seems like the events never dequeue, so you get stuck just
trying to read the big events over and over.

Overall, works great, though. I've ported/extended the Ruby watchr gem
(git://github.com/smparkes/watchr.git) and it works well on both OS X
and Linux.

Steven Parkes

unread,
Nov 3, 2009, 8:23:06 PM11/3/09
to eventm...@googlegroups.com

> I was wondering if we can get some more inotify options on the file
> watcher, e.g.,
>
> http://github.com/smparkes/eventmachine/commit/0dc5780ce28b1ad7a7107ca1b20faba031ff3ef5

Hmmm ... people that know more about the inotify interface may have
noticed (so to speak) that was not a great patch: I neglected to read
far enough in the man page to see that the kernel will stuff more than
one event per read if you give it enough space.

This commit fixes that:

http://github.com/smparkes/eventmachine/commit/8e2628173c002ad67a3f2321d8af7a3e1843af88

I tried to fix the spacing, but on github, it looks tweaked still,
somewhere between spaces and tabs, I suspect. I got rid of the old
fprintf cruft ... and added new, sigh.


Steven Parkes

unread,
Jan 6, 2010, 2:34:42 PM1/6/10
to eventm...@googlegroups.com
I've been running with more inotify options for a couple months now, without any stability problems. Any chance of getting this pulled upstream? I'd like to drop my fork.

Changes are in my fork at git://github.com/smparkes/eventmachine.git

The changes are three-fold:

1) Add some more inotify options so that directory changes can be detected.
2) Handle more than a minimal size inotify packet. Otherwise you can get an infinite loop because non-minimal packets are never delivered. This has the side effect of needing to handle multiple events per packet, since now there can now be enough room for multiple events in a packet.
3) Somewhat unrelated, but remove the 100-file limit on popen (which I need ...)

Happy to fix/change/improve, if some needs to be done.

Patch below (but can just be pulled from my fork (which has other changes for .gitignore/gemspec for my version of the gem):

diff --git a/ext/em.cpp b/ext/em.cpp
index e4ee9be..1b9c910 100644
--- a/ext/em.cpp
+++ b/ext/em.cpp
@@ -1963,9 +1963,9 @@ const unsigned long EventMachine_t::Socketpair (char * const*cmd_strings)
if (!cmd_strings)
return 0;
int j;
- for (j=0; j < 100 && cmd_strings[j]; j++)
+ for (j=0; cmd_strings[j]; j++)
;
- if ((j==0) || (j==100))
+ if (j==0)
return 0;

unsigned long output_binding = 0;
@@ -2131,7 +2131,8 @@ const unsigned long EventMachine_t::WatchFile (const char *fpath)
Add(inotify);
}

- wd = inotify_add_watch(inotify->GetSocket(), fpath, IN_MODIFY | IN_DELETE_SELF | IN_MOVE_SELF);
+ wd = inotify_add_watch(inotify->GetSocket(), fpath,
+ IN_MODIFY | IN_DELETE_SELF | IN_MOVE_SELF | IN_CREATE | IN_DELETE | IN_MOVE) ;
if (wd == -1) {
char errbuf[300];
sprintf(errbuf, "failed to open file %s for registering with inotify: %s", fpath, strerror(errno));
@@ -2207,20 +2208,27 @@ EventMachine_t::_ReadInotify_Events
void EventMachine_t::_ReadInotifyEvents()
{
#ifdef HAVE_INOTIFY
- struct inotify_event event;
+ char buffer[1024];

assert(EventCallback);

- while (read(inotify->GetSocket(), &event, INOTIFY_EVENT_SIZE) > 0) {
- assert(event.len == 0);
- if (event.mask & IN_MODIFY)
- (*EventCallback)(Files [event.wd]->GetBinding(), EM_CONNECTION_READ, "modified", 8);
- if (event.mask & IN_MOVE_SELF)
- (*EventCallback)(Files [event.wd]->GetBinding(), EM_CONNECTION_READ, "moved", 5);
- if (event.mask & IN_DELETE_SELF) {
- (*EventCallback)(Files [event.wd]->GetBinding(), EM_CONNECTION_READ, "deleted", 7);
- UnwatchFile ((int)event.wd);
- }
+ int returned;
+ while ((returned = read(inotify->GetSocket(), buffer, sizeof(buffer) )) > 0) {
+ int current = 0;
+ while(current< returned){
+ struct inotify_event* event = (struct inotify_event*)(buffer+current);
+ if (event->mask & (IN_MODIFY | IN_CREATE | IN_DELETE | IN_MOVE)){
+ (*EventCallback)(Files [event->wd]->GetBinding(), EM_CONNECTION_READ, "modified", 8);
+ }
+ if (event->mask & IN_MOVE_SELF){
+ (*EventCallback)(Files [event->wd]->GetBinding(), EM_CONNECTION_READ, "moved", 5);
+ }
+ if (event->mask & IN_DELETE_SELF) {
+ (*EventCallback)(Files [event->wd]->GetBinding(), EM_CONNECTION_READ, "deleted", 7);
+ UnwatchFile ((int)event->wd);
+ }
+ current += sizeof(struct inotify_event) + event->len;
+ }
}
#endif
}
diff --git a/ext/rubymain.cpp b/ext/rubymain.cpp
index f445de1..4c81789 100644
--- a/ext/rubymain.cpp
+++ b/ext/rubymain.cpp
@@ -754,9 +754,11 @@ static VALUE t_invoke_popen (VALUE self, VALUE cmd)
#else
int len = RARRAY (cmd)->len;
#endif
- if (len > 98)
+ char** strings = new char*[len+2];
+ if(!strings) {
rb_raise (rb_eRuntimeError, "too many arguments to popen");
- char *strings [100];
+ return ULONG2NUM (0);
+ }
for (int i=0; i < len; i++) {
VALUE ix = INT2FIX (i);
VALUE s = rb_ary_aref (1, &ix, cmd);
@@ -772,6 +774,7 @@ static VALUE t_invoke_popen (VALUE self, VALUE cmd)
snprintf (buf, sizeof(buf)-1, "no popen: %s", (err?err:"???"));
rb_raise (rb_eRuntimeError, "%s", buf);
}
+ delete [] strings;
return ULONG2NUM (f);
}

Reply all
Reply to author
Forward
0 new messages