Lines 1-8
Link Here
|
1 |
--- server/gam_kqueue.c.orig Thu Mar 31 20:39:54 2005 |
1 |
--- server/gam_kqueue.c.orig Wed Apr 6 18:21:46 2005 |
2 |
+++ server/gam_kqueue.c Fri Apr 1 01:09:11 2005 |
2 |
+++ server/gam_kqueue.c Wed Apr 6 18:57:07 2005 |
3 |
@@ -0,0 +1,636 @@ |
3 |
@@ -0,0 +1,712 @@ |
4 |
+/* |
4 |
+/* |
5 |
+ * Copyright (C) 2005 Joe Marcus Clarke <marcus@FreeBSD.org> |
5 |
+ * Copyright (C) 2005 Joe Marcus Clarke <marcus@FreeBSD.org> |
|
|
6 |
+ * Copyright (C) 2005 Jean-Yves Lefort <jylefort@brutele.be> |
6 |
+ * |
7 |
+ * |
7 |
+ * This library is free software; you can redistribute it and/or |
8 |
+ * This library is free software; you can redistribute it and/or |
8 |
+ * modify it under the terms of the GNU Lesser General Public |
9 |
+ * modify it under the terms of the GNU Lesser General Public |
Lines 22-27
Link Here
|
22 |
+ |
23 |
+ |
23 |
+#include <config.h> |
24 |
+#include <config.h> |
24 |
+#include <sys/types.h> |
25 |
+#include <sys/types.h> |
|
|
26 |
+#include <sys/stat.h> |
25 |
+#include <sys/event.h> |
27 |
+#include <sys/event.h> |
26 |
+#include <sys/time.h> |
28 |
+#include <sys/time.h> |
27 |
+#include <fcntl.h> |
29 |
+#include <fcntl.h> |
Lines 47-52
Link Here
|
47 |
+ GSList *dirlist; |
49 |
+ GSList *dirlist; |
48 |
+} KQueueData; |
50 |
+} KQueueData; |
49 |
+ |
51 |
+ |
|
|
52 |
+typedef struct |
53 |
+{ |
54 |
+ time_t mtime; |
55 |
+ time_t ctime; |
56 |
+ off_t size; |
57 |
+} MiniStat; |
58 |
+ |
59 |
+typedef struct { |
60 |
+ char *filename; |
61 |
+ char *pathname; |
62 |
+ MiniStat sb; |
63 |
+} FileData; |
64 |
+ |
50 |
+static GHashTable *dir_path_hash = NULL; |
65 |
+static GHashTable *dir_path_hash = NULL; |
51 |
+static GHashTable *file_path_hash = NULL; |
66 |
+static GHashTable *file_path_hash = NULL; |
52 |
+static GHashTable *fd_hash = NULL; |
67 |
+static GHashTable *fd_hash = NULL; |
Lines 80-149
Link Here
|
80 |
+ return data; |
95 |
+ return data; |
81 |
+} |
96 |
+} |
82 |
+ |
97 |
+ |
83 |
+static GSList * |
98 |
+static void |
84 |
+gam_kqueue_lsdir(const char *path) |
99 |
+gam_kqueue_mini_stat (const char *pathname, MiniStat *mini_sb) |
85 |
+{ |
100 |
+{ |
86 |
+ GDir *dir; |
101 |
+ struct stat sb; |
87 |
+ GSList *lst = NULL; |
|
|
88 |
+ const gchar *entry; |
89 |
+ |
90 |
+ if (!path) |
91 |
+ return NULL; |
92 |
+ |
102 |
+ |
93 |
+ dir = g_dir_open(path, 0, NULL); |
103 |
+ if (stat(pathname, &sb) == 0) { |
94 |
+ if (!dir) |
104 |
+ mini_sb->mtime = sb.st_mtime; |
95 |
+ return NULL; |
105 |
+ mini_sb->ctime = sb.st_ctime; |
96 |
+ |
106 |
+ mini_sb->size = sb.st_size; |
97 |
+ entry = g_dir_read_name(dir); |
107 |
+ } else { |
98 |
+ |
108 |
+ mini_sb->mtime = 0; |
99 |
+ while (entry) { |
109 |
+ mini_sb->ctime = 0; |
100 |
+ lst = g_slist_prepend(lst, g_strdup(entry)); |
110 |
+ mini_sb->size = 0; |
101 |
+ entry = g_dir_read_name(dir); |
|
|
102 |
+ } |
111 |
+ } |
103 |
+ |
|
|
104 |
+ g_dir_close(dir); |
105 |
+ |
106 |
+ return lst; |
107 |
+} |
112 |
+} |
108 |
+ |
113 |
+ |
109 |
+static void |
114 |
+static FileData * |
110 |
+gam_kqueue_cmplst(GSList *lst1, GSList *lst2, GSList **added, GSList **deleted) |
115 |
+gam_kqueue_file_data_new (const char *path, const char *filename) |
111 |
+{ |
116 |
+{ |
112 |
+ int found; |
117 |
+ FileData *fdata; |
113 |
+ GSList *l; |
118 |
+ struct stat sb; |
114 |
+ |
|
|
115 |
+ if (!lst1 && !lst2) |
116 |
+ return; |
117 |
+ |
119 |
+ |
118 |
+ if (!lst1) { |
120 |
+ fdata = g_new(FileData, 1); |
119 |
+ *added = g_slist_copy(lst2); |
121 |
+ fdata->filename = g_strdup(filename); |
120 |
+ return; |
122 |
+ fdata->pathname = g_build_filename(path, filename, NULL); |
121 |
+ } |
123 |
+ gam_kqueue_mini_stat(fdata->pathname, &fdata->sb); |
122 |
+ |
|
|
123 |
+ if (!lst2) { |
124 |
+ *deleted = g_slist_copy(lst1); |
125 |
+ return; |
126 |
+ } |
127 |
+ |
124 |
+ |
128 |
+ for (l = lst1; l; l = l->next) { |
125 |
+ return fdata; |
129 |
+ found = 0; |
126 |
+} |
130 |
+ if (g_slist_find_custom(lst2, l->data, (GCompareFunc)strcmp)) { |
|
|
131 |
+ found = 1; |
132 |
+ } |
133 |
+ if (found == 0) { |
134 |
+ *deleted = g_slist_prepend(*deleted, l->data); |
135 |
+ } |
136 |
+ } |
137 |
+ |
127 |
+ |
138 |
+ for (l = lst2; l; l = l->next) { |
128 |
+static void |
139 |
+ found = 0; |
129 |
+gam_kqueue_file_data_free (FileData *fdata) |
140 |
+ if (g_slist_find_custom(lst1, l->data, (GCompareFunc)strcmp)) { |
130 |
+{ |
141 |
+ found = 1; |
131 |
+ g_free(fdata->filename); |
142 |
+ } |
132 |
+ g_free(fdata->pathname); |
143 |
+ if (found == 0) { |
133 |
+ g_free(fdata); |
144 |
+ *added = g_slist_prepend(*added, l->data); |
|
|
145 |
+ } |
146 |
+ } |
147 |
+} |
134 |
+} |
148 |
+ |
135 |
+ |
149 |
+static void |
136 |
+static void |
Lines 151-157
Link Here
|
151 |
+{ |
138 |
+{ |
152 |
+ g_free(data->path); |
139 |
+ g_free(data->path); |
153 |
+ if (data->dirlist) { |
140 |
+ if (data->dirlist) { |
154 |
+ g_slist_foreach(data->dirlist, (GFunc)g_free, NULL); |
141 |
+ g_slist_foreach(data->dirlist, (GFunc)gam_kqueue_file_data_free, NULL); |
155 |
+ g_slist_free(data->dirlist); |
142 |
+ g_slist_free(data->dirlist); |
156 |
+ } |
143 |
+ } |
157 |
+ if (data->subs) { |
144 |
+ if (data->subs) { |
Lines 160-165
Link Here
|
160 |
+ g_free(data); |
147 |
+ g_free(data); |
161 |
+} |
148 |
+} |
162 |
+ |
149 |
+ |
|
|
150 |
+static int |
151 |
+gam_kqueue_dirlist_find (FileData *fdata, const char *filename) |
152 |
+{ |
153 |
+ return strcmp(fdata->filename, filename); |
154 |
+} |
155 |
+ |
163 |
+static void |
156 |
+static void |
164 |
+gam_kqueue_add_rm_handler(const char *path, GamSubscription *sub, gboolean added, gboolean was_missing) |
157 |
+gam_kqueue_add_rm_handler(const char *path, GamSubscription *sub, gboolean added, gboolean was_missing) |
165 |
+{ |
158 |
+{ |
Lines 230-250
Link Here
|
230 |
+ gam_server_emit_event (path, isdir, GAMIN_EVENT_CREATED, subs, 1); |
223 |
+ gam_server_emit_event (path, isdir, GAMIN_EVENT_CREATED, subs, 1); |
231 |
+ } |
224 |
+ } |
232 |
+ if (gam_subscription_is_dir(sub) && isdir) { |
225 |
+ if (gam_subscription_is_dir(sub) && isdir) { |
233 |
+ GSList *l; |
226 |
+ GDir *dir; |
234 |
+ |
227 |
+ |
235 |
+ data->isdir = TRUE; |
228 |
+ data->isdir = TRUE; |
236 |
+ data->dirlist = gam_kqueue_lsdir(path); |
229 |
+ data->dirlist = NULL; |
237 |
+ |
230 |
+ |
238 |
+ for (l = data->dirlist; l; l = l->next) { |
231 |
+ dir = g_dir_open(path, 0, NULL); |
239 |
+ char *tmpentry; |
232 |
+ if (dir) { |
240 |
+ |
233 |
+ const char *entry; |
241 |
+ tmpentry = g_build_filename(path, l->data, NULL); |
234 |
+ |
242 |
+ if (!was_missing) { |
235 |
+ while ((entry = g_dir_read_name(dir))) { |
243 |
+ gam_server_emit_event (tmpentry, |
236 |
+ FileData *fdata; |
244 |
+ g_file_test(tmpentry, G_FILE_TEST_IS_DIR), |
237 |
+ |
245 |
+ GAMIN_EVENT_EXISTS, subs, 1); |
238 |
+ fdata = gam_kqueue_file_data_new(path, entry); |
|
|
239 |
+ data->dirlist = g_slist_prepend(data->dirlist, fdata); |
240 |
+ |
241 |
+ if (!was_missing) { |
242 |
+ gam_server_emit_event(fdata->pathname, |
243 |
+ g_file_test(fdata->pathname, G_FILE_TEST_IS_DIR), |
244 |
+ GAMIN_EVENT_EXISTS, subs, 1); |
245 |
+ } |
246 |
+ } |
246 |
+ } |
247 |
+ g_free(tmpentry); |
247 |
+ |
|
|
248 |
+ g_dir_close(dir); |
248 |
+ } |
249 |
+ } |
249 |
+ } |
250 |
+ } |
250 |
+ |
251 |
+ |
Lines 332-375
Link Here
|
332 |
+ isdir = g_file_test(data->path, G_FILE_TEST_IS_DIR); |
333 |
+ isdir = g_file_test(data->path, G_FILE_TEST_IS_DIR); |
333 |
+ |
334 |
+ |
334 |
+ if (gevent == GAMIN_EVENT_CHANGED && data->isdir) { |
335 |
+ if (gevent == GAMIN_EVENT_CHANGED && data->isdir) { |
335 |
+ GSList *dirlist = NULL, *added = NULL, *deleted = NULL; |
336 |
+ GSList *dirlist = NULL; |
336 |
+ GSList *l; |
337 |
+ GSList *l; |
|
|
338 |
+ GDir *dir; |
339 |
+ |
340 |
+ dir = g_dir_open(data->path, 0, NULL); |
341 |
+ if (dir) { |
342 |
+ const char *entry; |
337 |
+ |
343 |
+ |
338 |
+ dirlist = gam_kqueue_lsdir(data->path); |
344 |
+ while ((entry = g_dir_read_name(dir))) { |
339 |
+ gam_kqueue_cmplst(data->dirlist, dirlist, &added, &deleted); |
345 |
+ dirlist = g_slist_prepend(dirlist, g_strdup(entry)); |
340 |
+ if (added || deleted) { |
|
|
341 |
+ for (l = deleted; l; l = l->next) { |
342 |
+ data->dirlist = g_slist_remove(data->dirlist, l->data); |
343 |
+ event_path = g_build_filename(data->path, l->data, NULL); |
344 |
+ g_free(l->data); |
345 |
+ isdir = g_file_test(event_path, G_FILE_TEST_IS_DIR); |
346 |
+ |
347 |
+ GAM_DEBUG(DEBUG_INFO, "kqueue emitting event %s for %s\n", gam_event_to_string(GAMIN_EVENT_DELETED) , event_path); |
348 |
+ |
349 |
+ gam_server_emit_event (event_path, isdir, |
350 |
+ GAMIN_EVENT_DELETED, data->subs, 1); |
351 |
+ g_free(event_path); |
352 |
+ } |
346 |
+ } |
353 |
+ |
347 |
+ |
354 |
+ for (l = added; l; l = l->next) { |
348 |
+ g_dir_close(dir); |
355 |
+ dirlist = g_slist_remove(dirlist, l->data); |
349 |
+ } |
356 |
+ data->dirlist = g_slist_prepend(data->dirlist, |
350 |
+ |
357 |
+ g_strdup(l->data)); |
351 |
+ for (l = dirlist; l; l = l->next) { |
358 |
+ event_path = g_build_filename(data->path, l->data, NULL); |
352 |
+ if (! g_slist_find_custom(data->dirlist, l->data, (GCompareFunc) gam_kqueue_dirlist_find)) { |
359 |
+ g_free(l->data); |
353 |
+ FileData *fdata; |
360 |
+ isdir = g_file_test(event_path, G_FILE_TEST_IS_DIR); |
354 |
+ |
361 |
+ |
355 |
+ fdata = gam_kqueue_file_data_new(data->path, l->data); |
362 |
+ GAM_DEBUG(DEBUG_INFO, "kqueue emitting event %s for %s\n", gam_event_to_string(GAMIN_EVENT_CREATED) , event_path); |
356 |
+ data->dirlist = g_slist_prepend(data->dirlist, fdata); |
363 |
+ |
357 |
+ |
364 |
+ gam_server_emit_event (event_path, isdir, |
358 |
+ GAM_DEBUG(DEBUG_INFO, "kqueue emitting event %s for %s\n", gam_event_to_string(GAMIN_EVENT_CREATED), fdata->pathname); |
365 |
+ GAMIN_EVENT_CREATED, data->subs, 1); |
359 |
+ gam_server_emit_event(fdata->pathname, |
366 |
+ g_free(event_path); |
360 |
+ g_file_test(fdata->pathname, G_FILE_TEST_IS_DIR), |
|
|
361 |
+ GAMIN_EVENT_CREATED, data->subs, 1); |
367 |
+ } |
362 |
+ } |
|
|
363 |
+ } |
364 |
+ |
365 |
+ iterate: |
366 |
+ for (l = data->dirlist; l; l = l->next) { |
367 |
+ FileData *fdata = l->data; |
368 |
+ |
369 |
+ if (! g_slist_find_custom(dirlist, fdata->filename, (GCompareFunc) strcmp)) { |
370 |
+ data->dirlist = g_slist_remove(data->dirlist, fdata); |
368 |
+ |
371 |
+ |
369 |
+ if (added) |
372 |
+ GAM_DEBUG(DEBUG_INFO, "kqueue emitting event %s for %s\n", gam_event_to_string(GAMIN_EVENT_DELETED), fdata->pathname); |
370 |
+ g_slist_free(added); |
373 |
+ gam_server_emit_event(fdata->pathname, |
371 |
+ if (deleted) |
374 |
+ g_file_test(fdata->pathname, G_FILE_TEST_IS_DIR), |
372 |
+ g_slist_free(deleted); |
375 |
+ GAMIN_EVENT_DELETED, data->subs, 1); |
|
|
376 |
+ |
377 |
+ gam_kqueue_file_data_free(fdata); |
378 |
+ goto iterate; /* list changed, start again */ |
379 |
+ } |
373 |
+ } |
380 |
+ } |
374 |
+ |
381 |
+ |
375 |
+ if (dirlist) { |
382 |
+ if (dirlist) { |
Lines 380-385
Link Here
|
380 |
+ } |
387 |
+ } |
381 |
+ else { |
388 |
+ else { |
382 |
+ event_path = g_strdup (data->path); |
389 |
+ event_path = g_strdup (data->path); |
|
|
390 |
+ |
391 |
+ if (gevent == GAMIN_EVENT_DELETED |
392 |
+ || gevent == GAMIN_EVENT_ENDEXISTS |
393 |
+ || gevent == GAMIN_EVENT_MOVED) { |
394 |
+ /* close and move to exist_list, to catch next creation */ |
395 |
+ close(data->fd); |
396 |
+ if (data->isdir) { |
397 |
+ g_hash_table_remove(dir_path_hash, data->path); |
398 |
+ } |
399 |
+ else { |
400 |
+ g_hash_table_remove(file_path_hash, data->path); |
401 |
+ } |
402 |
+ g_hash_table_remove(fd_hash, GINT_TO_POINTER(data->fd)); |
403 |
+ |
404 |
+ exist_list = g_slist_append(exist_list, data); |
405 |
+ } |
383 |
+ } |
406 |
+ } |
384 |
+ |
407 |
+ |
385 |
+ isdir = g_file_test(event_path, G_FILE_TEST_IS_DIR); |
408 |
+ isdir = g_file_test(event_path, G_FILE_TEST_IS_DIR); |
Lines 418-425
Link Here
|
418 |
+ return TRUE; |
441 |
+ return TRUE; |
419 |
+} |
442 |
+} |
420 |
+ |
443 |
+ |
|
|
444 |
+static void |
445 |
+gam_kqueue_dirlist_check_cb (const char *path, KQueueData *data, gpointer user_data) |
446 |
+{ |
447 |
+ GSList *l; |
448 |
+ |
449 |
+ for (l = data->dirlist; l; l = l->next) { |
450 |
+ FileData *fdata = l->data; |
451 |
+ MiniStat sb; |
452 |
+ |
453 |
+ gam_kqueue_mini_stat(fdata->pathname, &sb); |
454 |
+ |
455 |
+ if (sb.mtime != fdata->sb.mtime |
456 |
+ || sb.ctime != fdata->sb.ctime |
457 |
+ || sb.size != fdata->sb.size) |
458 |
+ { |
459 |
+ memcpy(&fdata->sb, &sb, sizeof(sb)); |
460 |
+ |
461 |
+ GAM_DEBUG(DEBUG_INFO, "kqueue emitting event %s for %s\n", gam_event_to_string(GAMIN_EVENT_CHANGED), fdata->pathname); |
462 |
+ gam_server_emit_event(fdata->pathname, |
463 |
+ g_file_test(fdata->pathname, G_FILE_TEST_IS_DIR), |
464 |
+ GAMIN_EVENT_CHANGED, data->subs, 1); |
465 |
+ } |
466 |
+ } |
467 |
+} |
468 |
+ |
469 |
+static gboolean |
470 |
+gam_kqueue_dirlist_check (gpointer user_data) |
471 |
+{ |
472 |
+ G_LOCK(kqueue); |
473 |
+ |
474 |
+ GAM_DEBUG(DEBUG_INFO, "gam_kqueue_dirlist_check()\n"); |
475 |
+ |
476 |
+ g_hash_table_foreach(dir_path_hash, (GHFunc) gam_kqueue_dirlist_check_cb, NULL); |
477 |
+ |
478 |
+ G_UNLOCK(kqueue); |
479 |
+ |
480 |
+ return TRUE; |
481 |
+} |
482 |
+ |
421 |
+static gboolean |
483 |
+static gboolean |
422 |
+gam_kqueue_event_handler (gpointer user_data) |
484 |
+gam_kqueue_event_handler (GIOChannel *source, GIOCondition condition, gpointer user_data) |
423 |
+{ |
485 |
+{ |
424 |
+ KQueueData *data; |
486 |
+ KQueueData *data; |
425 |
+ struct kevent ev[1]; |
487 |
+ struct kevent ev[1]; |
Lines 531-536
Link Here
|
531 |
+gboolean |
593 |
+gboolean |
532 |
+gam_kqueue_init(void) |
594 |
+gam_kqueue_init(void) |
533 |
+{ |
595 |
+{ |
|
|
596 |
+ GIOChannel *channel; |
597 |
+ |
534 |
+ kq = kqueue(); |
598 |
+ kq = kqueue(); |
535 |
+ if (kq == -1) { |
599 |
+ if (kq == -1) { |
536 |
+ GAM_DEBUG(DEBUG_INFO, "Could not initialize a new kqueue\n"); |
600 |
+ GAM_DEBUG(DEBUG_INFO, "Could not initialize a new kqueue\n"); |
Lines 538-548
Link Here
|
538 |
+ } |
602 |
+ } |
539 |
+ |
603 |
+ |
540 |
+ g_timeout_add(1000, gam_kqueue_exist_check, NULL); |
604 |
+ g_timeout_add(1000, gam_kqueue_exist_check, NULL); |
541 |
+ g_timeout_add(1000, gam_kqueue_event_handler, NULL); |
605 |
+ |
|
|
606 |
+ channel = g_io_channel_unix_new(kq); |
607 |
+ g_io_add_watch(channel, G_IO_IN, gam_kqueue_event_handler, NULL); |
542 |
+ |
608 |
+ |
543 |
+ dir_path_hash = g_hash_table_new(g_str_hash, g_str_equal); |
609 |
+ dir_path_hash = g_hash_table_new(g_str_hash, g_str_equal); |
544 |
+ file_path_hash = g_hash_table_new(g_str_hash, g_str_equal); |
610 |
+ file_path_hash = g_hash_table_new(g_str_hash, g_str_equal); |
545 |
+ fd_hash = g_hash_table_new(g_direct_hash, g_direct_equal); |
611 |
+ fd_hash = g_hash_table_new(g_direct_hash, g_direct_equal); |
|
|
612 |
+ |
613 |
+ /* |
614 |
+ * gam_kqueue_dirlist_check() has to stat() every file in every |
615 |
+ * monitored directory. This can easily become an intensive task |
616 |
+ * if a few large directories are monitored (for instance a mail |
617 |
+ * checker monitoring a couple of Maildir folders), therefore we |
618 |
+ * use a reasonable poll interval (6 seconds, same as FAM's |
619 |
+ * default). |
620 |
+ */ |
621 |
+ g_timeout_add(6000, gam_kqueue_dirlist_check, NULL); |
546 |
+ |
622 |
+ |
547 |
+ GAM_DEBUG(DEBUG_INFO, "kqueue initialized\n"); |
623 |
+ GAM_DEBUG(DEBUG_INFO, "kqueue initialized\n"); |
548 |
+ |
624 |
+ |