Browse files

working on fsevents, fixed some warnings.

  • Loading branch information...
1 parent 29348c4 commit eda08c2f4e6e2d2589bcc7b4e44664bfec0bb612 @axkibe committed Nov 29, 2010
Showing with 205 additions and 25 deletions.
  1. +196 −20 fsevents.c
  2. +3 −3 inotify.c
  3. +6 −2 lsyncd.c
View
216 fsevents.c
@@ -1,36 +1,180 @@
-/**
- * fsevents.c from Lsyncd - Live (Mirror) Syncing Demon
+/** fsevents.c from Lsyncd - Live (Mirror) Syncing Demon
*
* License: GPLv2 (see COPYING) or any later version
*
* Authors: Axel Kittenberger <axkibe@gmail.com>
*
* -----------------------------------------------------------------------
*
- * Event interface for MacOS 10(.5) /dev/fsevents interface.
+ * Event interface for MacOS 10.5 (Leopard) /dev/fsevents interface.
+ *
+ * Special thanks go to Amit Singh and his fslogger demonstration that showed
+ * how apples /dev/fsevents can be used. http://osxbook.com/software/fslogger/
*
- * WARNING! AFAIK this interface is not strictly considered "public" API
- * by Apple. Thus it might easily change between versions. Also its said,
- * altough every event receiver has its own message queue, the OS X kernel
- * only deletes a message after *all* registered receivers handled it. So
- * one receiver blocking overflows all receivers. So spotlight might have
- * to do more stuff, when Lsyncd might cause an overflow. Use at own risk.
+ * -- WARNING -- Quoting http://www.osxbook.com/software/fslogger/ --
*
- * Special thanks go to Amit Singh and his fslogger demonstration that
- * showed how apples /dev/fsevents can be used.
- * http://osxbook.com/software/fslogger/
+ * The interface that fslogger [and thus Lsyncd] uses is private to Apple.
+ * Currently, there is a caveat regarding the use of this interface by third
+ * parties (including fslogger [and thus Lsyncd]). While the change
+ * notification interface supports multiple clients, there is a single kernel
+ * buffer for holding events that are to be delivered to one or more
+ * subscribers, with the primary subscriber being Spotlight. Now, the kernel
+ * must hold events until it has notified all subscribers that are interested
+ * in them. Since there is a single buffer, a slow subscriber can cause it to
+ * overflow. If this happens, events will be dropped — for all subscribers,
+ * including Spotlight. Consequently, Spotlight may need to look at the entire
+ * volume to determine "what changed".
*/
#include "lsyncd.h"
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "bsd/sys/fsevents.h"
+
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
+
+/* the fsevents pseudo-device */
+#define DEV_FSEVENTS "/dev/fsevents"
+
+/* buffer for reading from the device */
+#define FSEVENT_BUFSIZ 131072
+/* limited by MAX_KFS_EVENTS */
+#define EVENT_QUEUE_SIZE 4096
+#define KFS_NUM_ARGS FSE_MAX_ARGS
+
+/* OS 10.5 structuce */
+/* an event argument */
+struct kfs_event_arg {
+ /* argument type */
+ u_int16_t type;
+
+ /* size of argument data that follows this field */
+ u_int16_t len;
+
+ union {
+ struct vnode *vp;
+ char *str;
+ void *ptr;
+ int32_t int32;
+ dev_t dev;
+ ino_t ino;
+ int32_t mode;
+ uid_t uid;
+ gid_t gid;
+ uint64_t timestamp;
+ } data;
+};
+
+/* OS 10.5 structuce */
+/* an event */
+struct kfs_event {
+
+ /* event type */
+ int32_t type;
+
+ /* pid of the process that performed the operation */
+ pid_t pid;
+
+ /* event arguments */
+ struct kfs_event_arg args[KFS_NUM_ARGS];
+};
+
+/**
+ * fsevents (cloned) filedescriptor
+ */
+static int fsevents_fd = -1;
+
static const luaL_reg lfseventslib[] = {
{NULL, NULL}
};
+
+static size_t const readbuf_size = 131072;
+static char * readbuf = NULL;
+
+/**
+ * Called when fsevents has something to read
+ */
+static void
+fsevents_ready(lua_State *L, struct observance *obs)
+{
+ if (obs->fd != fsevents_fd) {
+ logstring("Error", "Internal, fsevents_fd != ob->fd");
+ exit(-1); // ERRNO
+ }
+ while(true) {
+ ptrdiff_t len;
+ int err;
+ len = read (fsevents_fd, readbuf, readbuf_size);
+ err = errno;
+ if (len == 0) {
+ /* nothing more */
+ break;
+ }
+ if (len < 0) {
+ if (err == EAGAIN) {
+ /* nothing more inotify */
+ break;
+ } else {
+ printlogf(L, "Error", "Read fail on fsevents");
+ exit(-1); // ERRNO
+ }
+ }
+ {
+ int off = 0;
+ int32_t atype;
+ uint32_t aflags;
+
+ while (off < len && !hup && !term) {
+ struct kfs_event *event = (struct kfs_event *) &readbuf[off];
+ off += sizeof(int32_t) + sizeof(pid_t);
+
+ if (event->type == FSE_EVENTS_DROPPED) {
+ logstring("Fsevents", "Events dropped!");
+ load_runner_func(L, "overflow");
+ if (lua_pcall(L, 0, 0, -2)) {
+ exit(-1); // ERRNO
+ }
+ lua_pop(L, 1);
+ hup = 1;
+ off += sizeof(u_int16_t);
+ continue;
+ }
+ atype = event->type & FSE_TYPE_MASK;
+ aflags = FSE_GET_FLAGS(event->type);
+ }
+
+ }
+ }
+}
+
+/**
+ * Called to close/tidy fsevents
+ */
+static void
+fsevents_tidy(struct observance *obs)
+{
+ if (obs->fd != fsevents_fd) {
+ logstring("Error", "Internal, fsevents_fd != ob->fd");
+ exit(-1); // ERRNO
+ }
+ close(fsevents_fd);
+
+}
+
+
/**
* registers fsevents functions.
*/
@@ -45,14 +189,46 @@ register_fsevents(lua_State *L) {
*/
extern void
open_fsevents(lua_State *L) {
- // TODO
-}
-/**
- * closes fsevents
- */
-extern void
-close_fsevents() {
- // TODO
+ int8_t event_list[] = { // action to take for each event
+ FSE_REPORT, /* FSE_CREATE_FILE */
+ FSE_REPORT, /* FSE_DELETE */
+ FSE_REPORT, /* FSE_STAT_CHANGED */
+ FSE_REPORT, /* FSE_RENAME */
+ FSE_REPORT, /* FSE_CONTENT_MODIFIED */
+ FSE_REPORT, /* FSE_EXCHANGE */
+ FSE_REPORT, /* FSE_FINDER_INFO_CHANGED */
+ FSE_REPORT, /* FSE_CREATE_DIR */
+ FSE_REPORT, /* FSE_CHOWN */
+ FSE_REPORT, /* FSE_XATTR_MODIFIED */
+ FSE_REPORT, /* FSE_XATTR_REMOVED */
+ };
+ struct fsevent_clone_args fca = {
+ .event_list = (int8_t *) event_list,
+ .num_events = sizeof(event_list)/sizeof(int8_t),
+ .event_queue_depth = EVENT_QUEUE_SIZE,
+ .fd = &fsevents_fd,
+ };
+ int fd = open(DEV_FSEVENTS, O_RDONLY);
+ if (fd < 0) {
+ printlogf(L, "Error",
+ "Cannot access %s monitor! (%d:%s)",
+ DEV_FSEVENTS, errno, strerror(errno));
+ exit(-1); // ERRNO
+ }
+
+ if (ioctl(fd, FSEVENTS_CLONE, (char *)&fca) < 0) {
+ printlogf(L, "Error",
+ "Cannot control %s monitor! (%d:%s)",
+ DEV_FSEVENTS, errno, strerror(errno));
+ exit(-1); // ERRNO
+ }
+
+ /* fd has been cloned, closes access fd */
+ close(fd);
+ close_exec_fd(fsevents_fd);
+ non_block_fd(fsevents_fd);
+ observe_fd(fsevents_fd, fsevents_ready, NULL, fsevents_tidy, NULL);
}
+
View
6 inotify.c
@@ -71,7 +71,7 @@ static int
l_addwatch(lua_State *L)
{
const char *path = luaL_checkstring(L, 1);
- lua_Integer wd = inotify_add_watch(inotify_fd, path, standard_event_mask);
+ int wd = inotify_add_watch(inotify_fd, path, standard_event_mask);
printlogf(L, "Inotify", "addwatch(%s)->%d", path, wd);
lua_pushinteger(L, wd);
return 1;
@@ -86,7 +86,7 @@ l_addwatch(lua_State *L)
static int
l_rmwatch(lua_State *L)
{
- lua_Integer wd = luaL_checkinteger(L, 1);
+ int wd = luaL_checkinteger(L, 1);
inotify_rm_watch(inotify_fd, wd);
printlogf(L, "Inotify", "rmwatch()<-%d", wd);
return 0;
@@ -352,7 +352,7 @@ open_inotify(lua_State *L) {
readbuf = s_malloc(readbuf_size);
inotify_fd = inotify_init();
- if (inotify_fd == -1) {
+ if (inotify_fd < 0) {
printlogf(L, "Error",
"Cannot access inotify monitor! (%d:%s)",
errno, strerror(errno));
View
8 lsyncd.c
@@ -1213,6 +1213,7 @@ masterloop(lua_State *L)
{
while(true) {
bool have_alarm;
+ bool force_alarm;
clock_t now = times(NULL);
clock_t alarm_time;
@@ -1223,15 +1224,18 @@ masterloop(lua_State *L)
}
if (lua_type(L, -1) == LUA_TBOOLEAN) {
- have_alarm = lua_toboolean(L, -1);
+ have_alarm = false;
+ force_alarm = lua_toboolean(L, -1);
} else {
have_alarm = true;
alarm_time =
*((clock_t *) luaL_checkudata(L, -1, "Lsyncd.jiffies"));
}
lua_pop(L, 2);
- if (have_alarm && time_before_eq(alarm_time, now)) {
+ if (force_alarm ||
+ (have_alarm && time_before_eq(alarm_time, now))
+ ) {
/* there is a delay that wants to be handled already thus instead
* of reading/writing from observances it jumps directly to
* handling */

0 comments on commit eda08c2

Please sign in to comment.