00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <assert.h>
00020 #include <err.h>
00021 #include <errno.h>
00022 #include <fcntl.h>
00023 #include <stdbool.h>
00024 #include <stdint.h>
00025 #include <stdio.h>
00026 #include <stdlib.h>
00027 #include <string.h>
00028 #include <sys/param.h>
00029 #include <sys/stat.h>
00030 #include <sys/types.h>
00031 #include <sys/time.h>
00032 #include <unistd.h>
00033
00034 #include "pnotify.h"
00035 #include "pnotify-internal.h"
00036 #include "queue.h"
00037 #include "thread.h"
00038
00049 static pthread_key_t CTX_KEY;
00050
00051 #define CTX_GET() ((struct pnotify_ctx *) pthread_getspecific(CTX_KEY))
00052 #define CTX_SET(ctx) (pthread_setspecific(CTX_KEY, ctx))
00053
00054
00055
00056 #if HAVE_KQUEUE
00057 const struct pnotify_vtable * const sys = &BSD_VTABLE;
00058 #else
00059 const struct pnotify_vtable * const sys = &LINUX_VTABLE;
00060 #endif
00061
00063 LIST_HEAD(pnwatchhead, pn_watch) WATCH;
00064 pthread_mutex_t WATCH_MUTEX = PTHREAD_MUTEX_INITIALIZER;
00065
00066
00067 struct pn_watch *
00068 pn_get_watch_by_id(int wd)
00069 {
00070 struct pn_watch *watch;
00071
00072
00073 pthread_mutex_lock(&WATCH_MUTEX);
00074 LIST_FOREACH(watch, &WATCH, entries) {
00075 if (watch->wd == wd) {
00076 pthread_mutex_unlock(&WATCH_MUTEX);
00077 return watch;
00078 }
00079 }
00080 pthread_mutex_unlock(&WATCH_MUTEX);
00081
00082
00083
00084 return NULL;
00085 }
00086
00087
00088 void
00089 pnotify_init_once(void)
00090 {
00091 pthread_t tid;
00092
00093
00094 if (pthread_key_create(&CTX_KEY, NULL) != 0)
00095 errx(1, "error creating TLS key");
00096
00097
00098 pn_mask_signals();
00099
00100
00101 if (pthread_create( &tid, NULL, pn_signal_loop, NULL ) != 0)
00102 errx(1, "pthread_create(3) failed");
00103
00104
00105 if (pthread_create( &tid, NULL, pn_timer_loop, NULL ) != 0)
00106 errx(1, "pthread_create(3) failed");
00107
00108
00109 LIST_INIT(&WATCH);
00110 pn_timer_init();
00111
00112
00113 sys->init_once();
00114 }
00115
00116
00117
00118
00119
00120
00121 struct pnotify_ctx *
00122 pnotify_init()
00123 {
00124 static pthread_once_t once = PTHREAD_ONCE_INIT;
00125 struct pnotify_ctx *ctx;
00126
00127
00128 pthread_once(&once, pnotify_init_once);
00129
00130
00131 if ((ctx = calloc(1, sizeof(*ctx))) == NULL) {
00132 warn("calloc(3) failed");
00133 return NULL;
00134 }
00135
00136
00137 if (pthread_mutex_init(&ctx->mutex, NULL) != 0) {
00138 warn("pthread_mutex_init(3) failed");
00139 return NULL;
00140 }
00141
00142
00143 if (sem_init(&ctx->event_count, 0, 0) != 0) {
00144 warn("sem_init(3) failed");
00145 return NULL;
00146 }
00147
00148 TAILQ_INIT(&ctx->event);
00149
00150
00151 if (pthread_setspecific(CTX_KEY, ctx) != 0) {
00152 warn("pthread_setspecific(3) failed");
00153 return NULL;
00154 }
00155
00156
00157
00158
00159 return ctx;
00160 }
00161
00162
00163 int
00164 pnotify_add_watch(struct pnotify_watch *watch)
00165 {
00166 static int next_wd = 100;
00167 static pthread_mutex_t next_wd_mutex = PTHREAD_MUTEX_INITIALIZER;
00168 struct pn_watch *_watch;
00169 size_t len;
00170
00171
00172 if (!watch->ctx)
00173 watch->ctx = CTX_GET();
00174
00175
00176 if ((_watch = malloc(sizeof(*_watch))) == NULL) {
00177 warn("malloc error");
00178 return -1;
00179 }
00180
00181
00182 if (watch->type == WATCH_SIGNAL) {
00183
00184 _watch->wd = watch->ident.signum;
00185 } else {
00186 pthread_mutex_lock(&next_wd_mutex);
00187 _watch->wd = next_wd++;
00188 pthread_mutex_unlock(&next_wd_mutex);
00189 if (_watch->wd < 0) {
00190 warnx("watch descriptor overflow");
00191 free(_watch);
00192 return -1;
00193 }
00194 }
00195
00196
00197 switch (watch->type) {
00198
00199 case WATCH_VNODE:
00200 len = strlen(watch->ident.path);
00201 if (len > PATH_MAX)
00202 return -1;
00203 _watch->ident.path = malloc(len + 1);
00204
00205 (void) strncpy(_watch->ident.path, watch->ident.path, len);
00206 break;
00207
00208 case WATCH_SIGNAL:
00209 case WATCH_TIMER:
00210 case WATCH_FD:
00211 _watch->ident = watch->ident;
00212 break;
00213
00214 default:
00215 warn("invalid watch type = %d", watch->type);
00216 return -1;
00217 }
00218
00219
00220 _watch->type = watch->type;
00221 _watch->mask = watch->mask;
00222 _watch->cb = watch->cb;
00223 _watch->arg = watch->arg;
00224 _watch->ctx = watch->ctx;
00225
00226
00227 if (sys->add_watch(_watch) < 0) {
00228 warn("adding watch failed");
00229
00230 free(_watch);
00231 return -1;
00232 }
00233
00234
00235 pthread_mutex_lock(&WATCH_MUTEX);
00236 LIST_INSERT_HEAD(&WATCH, _watch, entries);
00237 pthread_mutex_unlock(&WATCH_MUTEX);
00238
00239 dprintf("added watch: wd=%d mask=%d path=%s\n",
00240 watch->wd, watch->mask, watch->path);
00241
00242 return _watch->wd;
00243 }
00244
00245
00246 int
00247 pnotify_rm_watch(int wd)
00248 {
00249 struct pn_watch *watchp, *wtmp;
00250 int found = 0;
00251
00252 pthread_mutex_lock(&WATCH_MUTEX);
00253
00254
00255 LIST_FOREACH_SAFE(watchp, &WATCH, entries, wtmp) {
00256
00257
00258 if ((watchp->wd == wd) || (watchp->parent_wd == wd)) {
00259 if (sys->rm_watch(watchp) < 0)
00260 break;
00261 switch (watchp->type) {
00262 case WATCH_TIMER:
00263 (void) pn_rm_timer(watchp);
00264 break;
00265 default:
00266 break;
00267 }
00268 LIST_REMOVE(watchp, entries);
00269 free(watchp);
00270 found++;
00271 }
00272 }
00273
00274 pthread_mutex_unlock(&WATCH_MUTEX);
00275
00276 if (found == 0) {
00277 warn("watch # %d not found", wd);
00278 return -1;
00279 } else {
00280 return 0;
00281 }
00282 }
00283
00284
00285 int
00286 pnotify_get_event(struct pnotify_event * evt, struct pnotify_ctx * ctx)
00287 {
00288 struct pnotify_event *evp;
00289
00290 assert(evt);
00291
00292
00293 if (!ctx)
00294 ctx = CTX_GET();
00295
00296
00297 if (sem_wait(&ctx->event_count) != 0) {
00298 warn("sem_wait(3) failed");
00299 return -1;
00300 }
00301
00302
00303
00304 mutex_lock(ctx);
00305 if (!TAILQ_EMPTY(&ctx->event)) {
00306 evp = TAILQ_FIRST(&ctx->event);
00307 TAILQ_REMOVE(&ctx->event, evp, entries);
00308 mutex_unlock(ctx);
00309 memcpy(evt, evp, sizeof(*evt));
00310 free(evp);
00311 return 0;
00312 } else {
00313 warnx("spurious wakeup");
00314 mutex_unlock(ctx);
00315 return -1;
00316 }
00317 }
00318
00319
00320 int
00321 pnotify_print_event(struct pnotify_event * evt)
00322 {
00323 assert(evt);
00324
00325 return printf("event: wd=%d mask=(%s%s%s%s%s) name=`%s'\n",
00326 evt->watch->wd,
00327 evt->mask & PN_ATTRIB ? "attrib," : "",
00328 evt->mask & PN_CREATE ? "create," : "",
00329 evt->mask & PN_DELETE ? "delete," : "",
00330 evt->mask & PN_MODIFY ? "modify," : "",
00331 evt->mask & PN_ERROR ? "error," : "",
00332 evt->name);
00333 }
00334
00335
00336 void
00337 pnotify_dump(struct pnotify_ctx *ctx)
00338 {
00339 struct pnotify_event *evt;
00340
00341 mutex_lock(ctx);
00342
00343 printf("\npending events:\n");
00344 TAILQ_FOREACH(evt, &ctx->event, entries) {
00345 printf("\t");
00346 (void) pnotify_print_event(evt);
00347 }
00348 printf("/* end: pending events */\n");
00349
00350 mutex_unlock(ctx);
00351 }
00352
00353
00354 void
00355 pnotify_free(struct pnotify_ctx *ctx)
00356 {
00357 struct pnotify_event *evt, *nxt;
00358
00359 assert(ctx != NULL);
00360
00361 mutex_lock(ctx);
00362
00363 #if FIXME
00364
00365
00366
00367
00368 while (!LIST_EMPTY(&ctx->watch)) {
00369 watch = LIST_FIRST(&ctx->watch);
00370 if (pnotify_rm_watch(ctx, watch->wd) < 0)
00371 errx(1,"error removing watch");
00372 }
00373 #endif
00374
00375
00376 evt = TAILQ_FIRST(&ctx->event);
00377 while (evt != NULL) {
00378 nxt = TAILQ_NEXT(evt, entries);
00379 free(evt);
00380 evt = nxt;
00381 }
00382
00383
00384 if (sem_destroy(&ctx->event_count) != 0)
00385 err(1, "sem_init(3) failed");
00386 if (pthread_mutex_destroy(&ctx->mutex) != 0)
00387 err(1, "pthread_mutex_destroy(3) failed");
00388
00389
00390 sys->cleanup();
00391
00392 mutex_unlock(ctx);
00393 free(ctx);
00394 }
00395
00396
00397
00398
00399 int
00400 pnotify_watch_vnode(const char *path, int mask, void (*cb)(), void *arg)
00401 {
00402 struct pnotify_watch w;
00403
00404 w.type = WATCH_VNODE;
00405 w.ident.path = (char *) path;
00406 w.mask = mask;
00407 w.cb = cb;
00408 w.arg = arg;
00409
00410 return pnotify_add_watch(&w);
00411 }
00412
00413
00414 int
00415 pnotify_watch_fd(int fd, int mask, void (*cb)(), void *arg)
00416 {
00417 struct pnotify_watch w;
00418
00419 w.type = WATCH_FD;
00420 w.ident.fd = fd;
00421 w.mask = mask;
00422 w.cb = cb;
00423 w.arg = arg;
00424
00425 return pnotify_add_watch(&w);
00426 }
00427
00428 int
00429 pnotify_set_timer(int interval, int mask, void (*cb)(), void *arg)
00430 {
00431 struct pnotify_watch w;
00432 int wd;
00433
00434
00435 w.type = WATCH_TIMER;
00436 w.ident.interval = interval;
00437 w.mask = mask;
00438 w.cb = cb;
00439 w.arg = arg;
00440 if ((wd = pnotify_add_watch(&w)) < 0) {
00441 warnx("unable to add watch for timer");
00442 return -1;
00443 }
00444
00445
00446 if (pn_add_timer(pn_get_watch_by_id(wd))) {
00447 warnx("unable to add timer");
00448 return -1;
00449 }
00450
00451 return 0;
00452 }
00453
00454 int
00455 pnotify_trap_signal(int signum, void (*cb)(), void *arg)
00456 {
00457 struct pnotify_watch w;
00458
00459
00460 if (pn_trap_signal(CTX_GET(), signum) != 0)
00461 return -1;
00462
00463 w.type = WATCH_SIGNAL;
00464 w.ident.signum = signum;
00465 w.mask = PN_SIGNAL;
00466 w.cb = cb;
00467 w.arg = arg;
00468
00469 return pnotify_add_watch(&w);
00470 }
00471
00472 int pnotify_call_function(int (*func)(), size_t nargs, ...)
00473 {
00474 abort();
00475
00476
00477
00478 }
00479
00480 int
00481 pnotify_dispatch()
00482 {
00483 struct pnotify_event evt;
00484
00485
00486 for (;;) {
00487
00488 if (pnotify_get_event(&evt, NULL) != 0)
00489 return -1;
00490
00491
00492 if (!evt.watch->cb)
00493 continue;
00494
00495 if (evt.watch->type == WATCH_VNODE) {
00496
00497
00498 } else if (evt.watch->type == WATCH_TIMER) {
00499 evt.watch->cb(evt.mask, evt.watch->arg);
00500 } else {
00501 evt.watch->cb(evt.watch->ident.fd, evt.mask, evt.watch->arg);
00502 }
00503
00504 }
00505 return 0;
00506 }
00507
00508
00509 void
00510 pn_event_add(struct pnotify_ctx *ctx, struct pnotify_event *evt)
00511 {
00512
00513 mutex_lock(ctx);
00514 TAILQ_INSERT_HEAD(&ctx->event, evt, entries);
00515 mutex_unlock(ctx);
00516
00517
00518 if (sem_post(&ctx->event_count) != 0)
00519 err(1, "sem_post(3)");
00520 }