#include <miscfs/specfs/specdev.h>
#include <miscfs/devfs/devfs.h>
#include <sys/filio.h>
-#include <architecture/byte_order.h>
#include <kern/locks.h>
#include <libkern/OSAtomic.h>
int32_t eventq_size; // number of event pointers in queue
int32_t rd, wr; // indices to the event_queue
int32_t blockers;
+ int32_t num_readers;
} fs_event_watcher;
// fs_event_watcher flags
kfs_event *kfse;
fs_event_watcher *watcher;
va_list ap;
- int error = 0;
+ int error = 0, base;
dev_t dev = 0;
va_start(ap, ctx);
// the lock is dropped.
lock_fs_event_buf();
+ base = free_event_idx;
for(i=0; i < MAX_KFS_EVENTS; i++) {
- if (fs_event_buf[(free_event_idx + i) % MAX_KFS_EVENTS].type == FSE_INVALID) {
+ if (fs_event_buf[(base + i) % MAX_KFS_EVENTS].type == FSE_INVALID) {
break;
}
}
return ENOSPC;
}
- kfse = &fs_event_buf[(free_event_idx + i) % MAX_KFS_EVENTS];
+ kfse = &fs_event_buf[(base + i) % MAX_KFS_EVENTS];
- free_event_idx++;
+ free_event_idx = ((base + i) % MAX_KFS_EVENTS) + 1;
kfse->type = type;
- kfse->refcount = 0;
+ kfse->refcount = 1;
kfse->pid = p->p_pid;
unlock_fs_event_buf(); // at this point it's safe to unlock
clean_up:
// just in case no one was interested after all...
- if (num_deliveries == 0) {
+ if (OSAddAtomic(-1, (SInt32 *)&kfse->refcount) == 1) {
do_free_event(kfse);
- free_event_idx = (int)(kfse - &fs_event_buf[0]);
}
lck_rw_done(&fsevent_big_lock);
lock_fs_event_buf();
- // mark this fsevent as invalid
- kfse->type = FSE_INVALID;
+ if (kfse->refcount > 0) {
+ panic("do_free_event: free'ing a kfsevent w/refcount == %d (kfse %p)\n",
+ kfse->refcount, kfse);
+ }
// make a copy of this so we can free things without
// holding the fs_event_buf lock
// and just to be anal, set this so that there are no args
kfse->args[0].type = FSE_ARG_DONE;
+ // mark this fsevent as invalid
+ kfse->type = FSE_INVALID;
+
free_event_idx = (kfse - fs_event_buf);
unlock_fs_event_buf();
watcher->rd = 0;
watcher->wr = 0;
watcher->blockers = 0;
+ watcher->num_readers = 0;
lock_watch_list();
return EINVAL;
}
+ if (OSAddAtomic(1, (SInt32 *)&watcher->num_readers) != 0) {
+ // don't allow multiple threads to read from the fd at the same time
+ OSAddAtomic(-1, (SInt32 *)&watcher->num_readers);
+ return EAGAIN;
+ }
if (watcher->rd == watcher->wr) {
if (watcher->flags & WATCHER_CLOSING) {
+ OSAddAtomic(-1, (SInt32 *)&watcher->num_readers);
return 0;
}
OSAddAtomic(1, (SInt32 *)&watcher->blockers);
OSAddAtomic(-1, (SInt32 *)&watcher->blockers);
if (error != 0 || (watcher->flags & WATCHER_CLOSING)) {
+ OSAddAtomic(-1, (SInt32 *)&watcher->num_readers);
return error;
}
}
}
if (error) {
+ OSAddAtomic(-1, (SInt32 *)&watcher->num_readers);
return error;
}
}
get_out:
+ OSAddAtomic(-1, (SInt32 *)&watcher->num_readers);
return error;
}
if (vname)
vnode_putname(vname);
+
+ strcpy(pathbuff, "UNKNOWN-FILE");
+ pathbuff_len = strlen(pathbuff) + 1;
}
// switch the type of the string
static struct lock__bsd__ fsevents_lck;
typedef struct fsevent_handle {
+ UInt32 flags;
+ SInt32 active;
fs_event_watcher *watcher;
struct selinfo si;
} fsevent_handle;
+#define FSEH_CLOSING 0x0001
static int
fseventsf_read(struct fileproc *fp, struct uio *uio,
pid_t pid = 0;
fsevent_dev_filter_args *devfilt_args=(fsevent_dev_filter_args *)data;
+ OSAddAtomic(1, &fseh->active);
+ if (fseh->flags & FSEH_CLOSING) {
+ OSAddAtomic(-1, &fseh->active);
+ return 0;
+ }
+
switch (cmd) {
case FIONBIO:
case FIOASYNC:
- return 0;
+ ret = 0;
+ break;
case FSEVENTS_DEVICE_FILTER: {
int new_num_devices;
dev_t *devices_to_watch, *tmp=NULL;
+ if (fseh->flags & FSEH_CLOSING) {
+ ret = 0;
+ break;
+ }
+
if (devfilt_args->num_devices > 256) {
ret = EINVAL;
break;
break;
}
+ OSAddAtomic(-1, &fseh->active);
return (ret);
}
fseventsf_close(struct fileglob *fg, struct proc *p)
{
fsevent_handle *fseh = (struct fsevent_handle *)fg->fg_data;
+ fs_event_watcher *watcher;
+
+ OSBitOrAtomic(FSEH_CLOSING, &fseh->flags);
+ while (OSAddAtomic(0, &fseh->active) > 0) {
+ tsleep((caddr_t)fseh->watcher, PRIBIO, "fsevents-close", 1);
+ }
- remove_watcher(fseh->watcher);
-
- fg->fg_data = NULL;
+ watcher = fseh->watcher;
fseh->watcher = NULL;
+ fg->fg_data = NULL;
+
+ remove_watcher(watcher);
FREE(fseh, M_TEMP);
return 0;
proc_fdunlock(p);
copyout((void *)&fd, CAST_USER_ADDR_T(fse_clone_args->fd), sizeof(int32_t));
proc_fdlock(p);
- *fdflags(p, fd) &= ~UF_RESERVED;
+ procfdtbl_releasefd(p, fd, NULL);
fp_drop(p, fd, f, 1);
proc_fdunlock(p);
break;