FreeBSD Bugzilla – Attachment 182749 Details for
Bug 214338
[PATCH] devel/glib20: new kqueue() backend for file monitoring
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
fix notify sequence
glib20.patch (text/plain), 40.94 KB, created by
Ivan Rozhuk
on 2017-05-19 22:39:11 UTC
(
hide
)
Description:
fix notify sequence
Filename:
MIME Type:
Creator:
Ivan Rozhuk
Created:
2017-05-19 22:39:11 UTC
Size:
40.94 KB
patch
obsolete
>Index: devel/glib20/Makefile >=================================================================== >--- devel/glib20/Makefile (revision 441251) >+++ devel/glib20/Makefile (working copy) >@@ -96,6 +96,8 @@ > @${REINPLACE_CMD} -e 's|inotify_support=yes|inotify_support=no| ; \ > s|-Werror|| ; \ > s|#define HAVE_SYS_INOTIFY_H 1||' ${WRKSRC}/configure >+ @${CP} ${FILESDIR}/kqueue_fnm.c.in ${WRKSRC}/gio/kqueue/kqueue_fnm.c >+ @${CP} ${FILESDIR}/kqueue_fnm.h.in ${WRKSRC}/gio/kqueue/kqueue_fnm.h > > post-install: > @${MKDIR} ${STAGEDIR}${PREFIX}/share/GConf/gsettings >Index: devel/glib20/files/kqueue_fnm.c.in >=================================================================== >--- devel/glib20/files/kqueue_fnm.c.in (nonexistent) >+++ devel/glib20/files/kqueue_fnm.c.in (working copy) >@@ -0,0 +1,716 @@ >+/*- >+ * Copyright (c) 2016 - 2017 Rozhuk Ivan <rozhuk.im@gmail.com> >+ * All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND >+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE >+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE >+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL >+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS >+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) >+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT >+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY >+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF >+ * SUCH DAMAGE. >+ * >+ * Author: Rozhuk Ivan <rozhuk.im@gmail.com> >+ * >+ */ >+ >+#include <sys/param.h> >+#include <sys/types.h> >+#include <sys/event.h> >+#include <sys/stat.h> >+#include <sys/fcntl.h> /* open, fcntl */ >+ >+#include <inttypes.h> >+#include <stdlib.h> /* malloc, exit */ >+#include <unistd.h> /* close, write, sysconf */ >+#include <string.h> /* bcopy, bzero, memcpy, memmove, memset, strerror... */ >+#include <dirent.h> /* opendir, readdir */ >+#include <errno.h> >+ >+#include "kqueue_fnm.h" >+ >+ >+/* Preallocate items count. */ >+#ifndef FILES_ALLOC_BLK_SIZE >+# define FILES_ALLOC_BLK_SIZE 32 >+#endif >+ >+typedef struct file_info_s { /* Directory file. */ >+ struct dirent de; /* d_reclen used for action. */ >+ struct stat sb; >+} file_info_t, *file_info_p; >+ >+ >+typedef struct readdir_data_s { >+ int fd; >+ uint8_t *buf; >+ size_t buf_size; >+ size_t buf_used; >+ size_t buf_pos; >+} readdir_data_t, *readdir_data_p; >+ >+ >+typedef struct kqueue_file_mon_data_s { >+ int fd; /* fd for notify kqueue(). */ >+ int is_dir; >+ char path[(PATH_MAX + 2)]; >+ size_t path_size; >+ size_t name_offset; /* Parent path size. */ >+ size_t st_blksize; >+ void *udata; >+ kqueue_fnm_p kfnm; >+ /* For dir. */ >+ file_info_p files; >+ volatile size_t files_count; >+ size_t files_allocated; >+} kqueue_file_mon_data_t; >+ >+ >+typedef struct kqueue_file_nonify_monitor_s { >+ int fd; /* kqueue() fd. */ >+ int pfd[2]; /* pipe queue specific. */ >+ uint8_t *tmpbuf; >+ size_t tmpbuf_size; >+} kqueue_fnm_t; >+ >+ >+typedef void (*kq_msg_cb)(kqueue_file_mon_data_p fmd); >+ >+typedef struct kqueue_file_mon_msg_pkt_s { >+ size_t magic; >+ kq_msg_cb msg_cb; >+ kqueue_file_mon_data_p fmd; >+ size_t chk_sum; >+} kqueue_fnm_msg_pkt_t, *kqueue_fnm_msg_pkt_p; >+ >+#define KF_MSG_PKT_MAGIC 0xffddaa00 >+ >+ >+#ifndef O_NOATIME >+# define O_NOATIME 0 >+#endif >+#ifndef O_EVTONLY >+# define O_EVTONLY O_RDONLY >+#endif >+#define OPEN_FILE_FLAGS (O_EVTONLY | O_NONBLOCK | O_NOFOLLOW | O_NOATIME | O_CLOEXEC) >+ >+#define EVFILT_VNODE_FLAGS_ALL (NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE) >+ >+ >+#ifndef _GENERIC_DIRSIZ >+# define _GENERIC_DIRSIZ(__de) MIN((__de)->d_reclen, sizeof(struct dirent)) >+#endif >+ >+#define IS_NAME_DOTS(__name) ('.' == (__name)[0] && \ >+ ('\0' == (__name)[1] || \ >+ ('.' == (__name)[1] && '\0' == (__name)[2]))) >+#define IS_DE_NAME_EQ(__de1, __de2) (0 == mem_cmpn((__de1)->d_name, \ >+ (__de1)->d_namlen, \ >+ (__de2)->d_name, \ >+ (__de2)->d_namlen)) >+#define zalloc(__size) calloc(1, (__size)) >+ >+ >+static inline int >+mem_cmpn(const void *buf1, const size_t buf1_size, >+ const void *buf2, const size_t buf2_size) { >+ >+ if (buf1_size != buf2_size) >+ return (((buf1_size > buf2_size) ? 127 : -127)); >+ if (0 == buf1_size || buf1 == buf2) >+ return (0); >+ if (NULL == buf1) >+ return (-127); >+ if (NULL == buf2) >+ return (127); >+ return (memcmp(buf1, buf2, buf1_size)); >+} >+ >+static inline int >+realloc_items(void **items, const size_t item_size, >+ size_t *allocated, const size_t alloc_blk_cnt, const size_t count) { >+ size_t allocated_prev, allocated_new; >+ uint8_t *items_new; >+ >+ if (NULL == items || 0 == item_size || NULL == allocated || >+ 0 == alloc_blk_cnt) >+ return (EINVAL); >+ allocated_prev = (*allocated); >+ if (NULL != (*items) && >+ allocated_prev > count && >+ allocated_prev <= (count + alloc_blk_cnt)) >+ return (0); >+ allocated_new = (((count / alloc_blk_cnt) + 1) * alloc_blk_cnt); >+#if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000 >+ items_new = (uint8_t*)reallocarray((*items), item_size, allocated_new); >+#else /* For old BSD systems. */ >+ items_new = (uint8_t*)realloc((*items), (item_size * allocated_new)); >+#endif >+ if (NULL == items_new) /* Realloc fail! */ >+ return (ENOMEM); >+ >+ if (allocated_new > allocated_prev) { /* Init new mem. */ >+ bzero((items_new + (allocated_prev * item_size)), >+ ((allocated_new - allocated_prev) * item_size)); >+ } >+ (*items) = items_new; >+ (*allocated) = allocated_new; >+ >+ return (0); >+} >+ >+ >+static int >+readdir_data_start(int fd, uint8_t *buf, size_t buf_size, readdir_data_p rdd) { >+ >+ if (-1 == fd || NULL == buf || 0 == buf_size || NULL == rdd) >+ return (EINVAL); >+ if (-1 == lseek(fd, 0, SEEK_SET)) >+ return (errno); >+ bzero(rdd, sizeof(readdir_data_t)); >+ rdd->fd = fd; >+ rdd->buf = buf; >+ rdd->buf_size = buf_size; >+ >+ return (0); >+} >+ >+static int >+readdir_data_next(readdir_data_p rdd, struct dirent *de) { >+ int ios; >+ uint8_t *ptr; >+ >+ if (NULL == rdd || NULL == de) >+ return (EINVAL); >+ >+retry: >+ if (rdd->buf_used <= rdd->buf_pos) { >+ ios = getdents(rdd->fd, (char*)rdd->buf, rdd->buf_size); >+ if (-1 == ios) >+ return (errno); >+ rdd->buf_used = (size_t)ios; >+ rdd->buf_pos = 0; >+ if (0 == ios) >+ return (ESPIPE); /* EOF. */ >+ } >+ /* Keep data aligned. */ >+ ptr = (rdd->buf + rdd->buf_pos); >+ memcpy(de, ptr, (sizeof(struct dirent) - sizeof(de->d_name))); >+ if (0 == de->d_reclen) >+ return (ESPIPE); /* EOF. */ >+ rdd->buf_pos += de->d_reclen; >+#ifdef DT_WHT >+ if (DT_WHT == de->d_type) >+ goto retry; >+#endif >+ memcpy(de, ptr, _GENERIC_DIRSIZ(de)); >+ if (IS_NAME_DOTS(de->d_name)) >+ goto retry; >+ return (0); >+} >+ >+ >+static int >+file_info_find_de_fileno(file_info_p files, size_t files_count, >+ struct dirent *de, size_t *idx) { >+ size_t i; >+ >+ if (NULL == files || NULL == de || NULL == idx) >+ return (0); >+ for (i = 0; i < files_count; i ++) { >+ if (de->d_type != files[i].de.d_type || >+ de->d_fileno != files[i].de.d_fileno) >+ continue; >+ (*idx) = i; >+ return (1); >+ } >+ (*idx) = files_count; >+ return (0); >+} >+ >+static int >+file_info_find_de_name(file_info_p files, size_t files_count, >+ const size_t skip_idx, struct dirent *de, size_t *idx) { >+ size_t i; >+ >+ if (NULL == files || NULL == de || NULL == idx) >+ return (0); >+ for (i = 0; i < files_count; i ++) { >+ if (i == skip_idx || >+ de->d_type != files[i].de.d_type || >+ 0 == IS_DE_NAME_EQ(de, &files[i].de)) >+ continue; >+ (*idx) = i; >+ return (1); >+ } >+ (*idx) = files_count; >+ return (0); >+} >+ >+ >+static void >+kqueue_file_mon_data_clean(kqueue_file_mon_data_p fmd) { >+ >+ if (NULL == fmd) >+ return; >+ close(fmd->fd); >+ fmd->fd = -1; >+ fmd->files_count = 0; >+ fmd->files_allocated = 0; >+ free(fmd->files); >+ fmd->files = NULL; >+} >+ >+static void >+kqueue_file_mon_data_free(kqueue_file_mon_data_p fmd) { >+ >+ if (NULL == fmd) >+ return; >+ close(fmd->fd); >+ free(fmd->files); >+ free(fmd); >+} >+ >+static kqueue_file_mon_data_p >+kqueue_file_mon_data_alloc(kqueue_fnm_p kfnm, const char *path, void *udata) { >+ kqueue_file_mon_data_p fmd; >+ >+ if (NULL == kfnm || NULL == path) >+ return (NULL); >+ fmd = zalloc(sizeof(kqueue_file_mon_data_t)); >+ if (NULL == fmd) >+ return (NULL); >+ /* Remember args. */ >+ fmd->path_size = strlcpy(fmd->path, path, PATH_MAX); >+ fmd->name_offset = fmd->path_size; >+ fmd->udata = udata; >+ fmd->kfnm = kfnm; >+ >+ return (fmd); >+} >+ >+static int >+kqueue_file_mon_data_readdir(kqueue_file_mon_data_p fmd) { >+ int error; >+ struct dirent *de; >+ uint8_t *tmpbuf; >+ readdir_data_t rdd; >+ >+ if (NULL == fmd || 0 == fmd->is_dir) >+ return (EINVAL); >+ >+ /* Get temp buf. */ >+ if (fmd->st_blksize > fmd->kfnm->tmpbuf_size) { >+ tmpbuf = realloc(fmd->kfnm->tmpbuf, fmd->st_blksize); >+ if (NULL == tmpbuf) >+ return (ENOMEM); >+ fmd->kfnm->tmpbuf = tmpbuf; >+ fmd->kfnm->tmpbuf_size = fmd->st_blksize; >+ } >+ >+ fmd->files_count = 0; >+ fmd->files_allocated = 0; >+ free(fmd->files); >+ fmd->files = NULL; >+ >+ error = readdir_data_start(fmd->fd, fmd->kfnm->tmpbuf, fmd->st_blksize, &rdd); >+ if (0 != error) >+ return (error); >+ for (;;) { >+ if (0 != realloc_items((void**)&fmd->files, >+ sizeof(file_info_t), &fmd->files_allocated, >+ FILES_ALLOC_BLK_SIZE, fmd->files_count)) { >+ fmd->files_count = 0; >+ fmd->files_allocated = 0; >+ free(fmd->files); >+ fmd->files = NULL; >+ return (ENOMEM); >+ } >+ de = &fmd->files[fmd->files_count].de; /* Use short name. */ >+ /* Get file name from folder. */ >+ if (0 != readdir_data_next(&rdd, de)) >+ break; >+ /* Get file attrs. */ >+ if (0 != fstatat(fmd->fd, de->d_name, >+ &fmd->files[fmd->files_count].sb, >+ AT_SYMLINK_NOFOLLOW)) { >+ bzero(&fmd->files[fmd->files_count].sb, >+ sizeof(struct stat)); >+ } >+ fmd->files_count ++; >+ } >+ >+ return (0); /* OK. */ >+} >+ >+ >+static void >+kqueue_file_mon_data_init(kqueue_file_mon_data_p fmd) { >+ struct stat sb; >+ struct kevent kev; >+ struct timespec ke_timeout; >+ >+ if (NULL == fmd) >+ return; >+ fmd->fd = open(fmd->path, OPEN_FILE_FLAGS); >+ if (-1 == fmd->fd) >+ return; >+ if (0 != fstat(fmd->fd, &sb)) >+ goto err_out; >+ fmd->st_blksize = (size_t)sb.st_blksize; >+ /* Get parent folder name. */ >+ if (S_ISDIR(sb.st_mode)) { >+ fmd->is_dir = 1; >+ /* Be sure that folder contain trailing '/'. */ >+ if ('/' != fmd->path[(fmd->path_size - 1)]) { >+ fmd->path[fmd->path_size] = '/'; >+ fmd->path_size ++; >+ fmd->path[fmd->path_size] = 0; >+ } >+ /* Skip last '/' for parent dir search. */ >+ fmd->name_offset = (fmd->path_size - 1); >+ } >+ /* Find parent dir path size. */ >+ while (0 < fmd->name_offset && '/' != fmd->path[(fmd->name_offset - 1)]) { >+ fmd->name_offset --; >+ } >+ >+ /* Dir special processing. */ >+ if (0 != fmd->is_dir) { >+ /* Read and remember dir content. */ >+ if (0 != kqueue_file_mon_data_readdir(fmd)) >+ goto err_out; >+ } >+ /* Add to kqueue. */ >+ bzero(&kev, sizeof(kev)); >+ kev.ident = (uintptr_t)fmd->fd; >+ kev.filter = EVFILT_VNODE; >+ kev.flags = (EV_ADD | EV_CLEAR); >+ kev.fflags = EVFILT_VNODE_FLAGS_ALL; >+ kev.udata = (void*)fmd; >+ >+ bzero(&ke_timeout, sizeof(ke_timeout)); >+ >+ if (-1 == kevent(fmd->kfnm->fd, &kev, 1, NULL, 0, &ke_timeout)) >+ goto err_out; >+ return; /* OK. */ >+ >+err_out: >+ kqueue_file_mon_data_clean(fmd); >+} >+ >+ >+static void >+kqueue_handle_changes(kqueue_fnm_p kfnm, kqueue_file_mon_data_p fmd, >+ kfnm_event_handler_cb cb_func) { >+ struct stat sb; >+ size_t i, k, files_count; >+ file_info_p files; >+ >+ if (NULL == kfnm || NULL == fmd || NULL == cb_func) >+ return; >+ if (0 != fstat(fmd->fd, &sb) || >+ 0 == sb.st_nlink) { >+ kqueue_file_mon_data_clean(fmd); >+ cb_func(kfnm, fmd, fmd->udata, KF_EVENT_DELETED, >+ fmd->path, "", NULL); >+ return; >+ } >+ if (0 == fmd->is_dir) { >+ fmd->path[fmd->name_offset] = 0; >+ cb_func(kfnm, fmd, fmd->udata, KF_EVENT_CHANGED, fmd->path, >+ (fmd->path + fmd->name_offset), NULL); >+ fmd->path[fmd->name_offset] = '/'; >+ return; >+ } >+ >+ /* Dir processing. */ >+ >+ /* Save prev. */ >+ files = fmd->files; >+ files_count = fmd->files_count; >+ fmd->files = NULL; >+ /* Update dir. */ >+ if (0 != kqueue_file_mon_data_readdir(fmd)) >+ goto err_out; >+ /* Notify removed first. */ >+ for (i = 0; i < files_count; i ++) { >+ if (0 != file_info_find_de_fileno(fmd->files, fmd->files_count, &files[i].de, &k) || >+ 0 != file_info_find_de_name(fmd->files, fmd->files_count, ~0, &files[i].de, &k)) /* Deleted. */ >+ continue; >+ cb_func(kfnm, fmd, fmd->udata, KF_EVENT_DELETED, >+ fmd->path, files[i].de.d_name, NULL); >+ } >+ /* Notify. */ >+ for (i = 0; i < fmd->files_count; i ++) { >+ /* Is new file/folder? */ >+ if (0 == file_info_find_de_fileno(files, files_count, &fmd->files[i].de, &k) && >+ 0 == file_info_find_de_name(files, files_count, ~0, &fmd->files[i].de, &k)) { /* Add new. */ >+ cb_func(kfnm, fmd, fmd->udata, KF_EVENT_CREATED, >+ fmd->path, fmd->files[i].de.d_name, NULL); >+ continue; >+ } >+ /* Is renamed? */ >+ if (0 == IS_DE_NAME_EQ(&files[k].de, &fmd->files[i].de)) { >+ cb_func(kfnm, fmd, fmd->udata, KF_EVENT_RENAMED, >+ fmd->path, files[k].de.d_name, fmd->files[i].de.d_name); >+ continue; >+ } >+ /* Is modified? */ >+ if (0 != memcmp(&fmd->files[i].sb, &files[k].sb, sizeof(struct stat))) { >+ cb_func(kfnm, fmd, fmd->udata, KF_EVENT_CHANGED, >+ fmd->path, fmd->files[i].de.d_name, NULL); >+ continue; >+ } >+ /* Not changed. */ >+ } >+ >+err_out: >+ free(files); >+ return; >+} >+ >+static void >+kqueue_handle_rename(kqueue_fnm_p kfnm, kqueue_file_mon_data_p fmd, >+ kfnm_event_handler_cb cb_func) { >+ int up_dir_fd, found = 0; >+ readdir_data_t rdd; >+ struct dirent de; >+ struct stat sb; >+ char old_filename[(MAXNAMLEN + 2)]; >+ size_t old_filename_size; >+ >+ if (NULL == kfnm || NULL == fmd || NULL == cb_func) >+ return; >+ if (0 != fstat(fmd->fd, &sb) || >+ 0 == sb.st_nlink) { >+notify_removed: >+ kqueue_file_mon_data_clean(fmd); >+ cb_func(kfnm, fmd, fmd->udata, KF_EVENT_DELETED, >+ fmd->path, "", NULL); >+ return; >+ } >+ /* Save old file name. */ >+ old_filename_size = (fmd->path_size - fmd->name_offset - fmd->is_dir); >+ memcpy(old_filename, >+ (fmd->path + fmd->name_offset), >+ old_filename_size); >+ old_filename[old_filename_size] = 0; >+ >+ /* Get parent folder name. */ >+ fmd->path[fmd->name_offset] = 0; >+ /* Try to open. */ >+ up_dir_fd = open(fmd->path, (OPEN_FILE_FLAGS | O_DIRECTORY)); >+ /* Restore '/' after parent folder. */ >+ fmd->path[fmd->name_offset] = '/'; >+ if (-1 == up_dir_fd || >+ 0 != fstat(up_dir_fd, &sb) || >+ 0 != readdir_data_start(up_dir_fd, fmd->kfnm->tmpbuf, sb.st_blksize, &rdd)) { >+ close(up_dir_fd); >+ return; >+ } >+ /* Find new name by inode. */ >+ while (0 == readdir_data_next(&rdd, &de)) { >+ if (de.d_fileno == sb.st_ino) { >+ found ++; >+ break; >+ } >+ } >+ close(up_dir_fd); >+ if (0 == found) >+ goto notify_removed; /* Not found. */ >+ /* Update name. */ >+ if (PATH_MAX <= (fmd->name_offset + de.d_namlen)) >+ return; /* Too long. */ >+ memcpy((fmd->path + fmd->name_offset), de.d_name, de.d_namlen); >+ fmd->path_size = (fmd->name_offset + de.d_namlen); >+ /* Add last '/' for dir. */ >+ fmd->path[fmd->path_size] = '/'; >+ fmd->path_size += fmd->is_dir; >+ fmd->path[fmd->path_size] = 0; >+ /* Notify. */ >+ cb_func(kfnm, fmd, fmd->udata, KF_EVENT_RENAMED, >+ fmd->path, old_filename, de.d_name); >+} >+ >+ >+static void >+kqueue_fnm_delay_call_process(kqueue_fnm_p kfnm, kq_msg_cb forced_msg_cb) { >+ ssize_t ios; >+ kqueue_fnm_msg_pkt_t msg; >+ >+ for (;;) { >+ ios = read(kfnm->pfd[0], &msg, sizeof(msg)); >+ if (0 >= ios) >+ return; >+ if (sizeof(msg) != ios || >+ KF_MSG_PKT_MAGIC != msg.magic || >+ (((size_t)msg.msg_cb) ^ ((size_t)msg.fmd)) != msg.chk_sum) >+ continue; >+ if (NULL != forced_msg_cb) { >+ forced_msg_cb(msg.fmd); >+ continue; >+ } >+ if (NULL == msg.msg_cb) >+ continue; >+ msg.msg_cb(msg.fmd); >+ } >+} >+ >+static int >+kqueue_fnm_delay_call(kqueue_fnm_p kfnm, kq_msg_cb msg_cb, >+ kqueue_file_mon_data_p fmd) { >+ kqueue_fnm_msg_pkt_t msg; >+ >+ if (NULL == kfnm || NULL == fmd) >+ return (EINVAL); >+ msg.magic = KF_MSG_PKT_MAGIC; >+ msg.msg_cb = msg_cb; >+ msg.fmd = fmd; >+ msg.chk_sum = (((size_t)msg.msg_cb) ^ ((size_t)msg.fmd)); >+ if (sizeof(msg) == write(kfnm->pfd[1], &msg, sizeof(msg))) >+ return (0); >+ return (errno); >+} >+ >+ >+void >+kqueue_fnm_free(kqueue_fnm_p kfnm) { >+ >+ if (NULL == kfnm) >+ return; >+ close(kfnm->fd); >+ /* Free all in delay calls queue. */ >+ kqueue_fnm_delay_call_process(kfnm, kqueue_file_mon_data_free); >+ close(kfnm->pfd[0]); >+ close(kfnm->pfd[1]); >+ free(kfnm->tmpbuf); >+ free(kfnm); >+} >+ >+kqueue_fnm_p >+kqueue_fnm_create(void) { >+ kqueue_fnm_p kfnm; >+ struct kevent kev; >+ struct timespec ke_timeout; >+ >+ kfnm = zalloc(sizeof(kqueue_fnm_t)); >+ if (NULL == kfnm) >+ return (NULL); >+ kfnm->fd = kqueue(); >+ if (-1 == kfnm->fd) >+ goto err_out; >+ if (-1 == pipe2(kfnm->pfd, O_NONBLOCK)) >+ goto err_out; >+ >+ bzero(&kev, sizeof(kev)); >+ kev.ident = kfnm->pfd[0]; >+ kev.filter = EVFILT_READ; >+ kev.flags = (EV_ADD | EV_ENABLE); >+ >+ bzero(&ke_timeout, sizeof(ke_timeout)); >+ >+ if (-1 == kevent(kfnm->fd, &kev, 1, NULL, 0, &ke_timeout)) >+ goto err_out; >+ return (kfnm); >+ >+err_out: >+ kqueue_fnm_free(kfnm); >+ return (NULL); >+} >+ >+kqueue_file_mon_data_p >+kqueue_fnm_add(kqueue_fnm_p kfnm, const char *path, void *udata) { >+ int error; >+ kqueue_file_mon_data_p fmd; >+ >+ if (NULL == kfnm || NULL == path) >+ return (NULL); >+ fmd = kqueue_file_mon_data_alloc(kfnm, path, udata); >+ if (NULL == fmd) >+ return (NULL); >+ /* Shedule delay call to init. */ >+ error = kqueue_fnm_delay_call(kfnm, kqueue_file_mon_data_init, fmd); >+ if (0 != error) { /* Error, do no directly init to avoid freezes. */ >+ kqueue_file_mon_data_free(fmd); >+ return (NULL); >+ } >+ return (fmd); >+} >+ >+void >+kqueue_fnm_del(kqueue_fnm_p kfnm, kqueue_file_mon_data_p fmd) { >+ int error; >+ >+ if (NULL == kfnm || NULL == fmd) >+ return; >+ /* Cancel notifications. */ >+ close(fmd->fd); >+ fmd->fd = -1; >+ /* Shedule delay call to free. */ >+ error = kqueue_fnm_delay_call(kfnm, kqueue_file_mon_data_free, fmd); >+ if (0 == error) >+ return; >+ /* Error, free directly. */ >+ kqueue_file_mon_data_free(fmd); >+} >+ >+ >+int >+kqueue_fnm_get_ev_recv_fd(kqueue_fnm_p kfnm) { >+ >+ if (NULL == kfnm) >+ return (-1); >+ return (kfnm->fd); >+} >+ >+void >+kqueue_fnm_proccess_events(kqueue_fnm_p kfnm, kfnm_event_handler_cb cb_func) { >+ struct kevent kev; >+ struct timespec ke_timeout; >+ kqueue_file_mon_data_p fmd; >+ >+ if (NULL == kfnm || NULL == cb_func) >+ return; >+ /* Get and proccess events. */ >+ bzero(&ke_timeout, sizeof(ke_timeout)); >+ while (0 < kevent(kfnm->fd, NULL, 0, &kev, 1, &ke_timeout)) { >+ if (kev.ident == (uintptr_t)kfnm->pfd[0] && >+ kev.filter == EVFILT_READ) { /* Handle delay calls. */ >+ kqueue_fnm_delay_call_process(kfnm, NULL); >+ continue; >+ } >+ if (EVFILT_VNODE != kev.filter || >+ 0 == kev.udata) >+ continue; /* Unknown event or no associated data, skip. */ >+ fmd = (kqueue_file_mon_data_p)kev.udata; >+ >+ if (EV_ERROR & kev.flags) { >+ kev.flags |= NOTE_REVOKE; /* Treat error as unmount. */ >+ } >+ if (NOTE_RENAME & kev.fflags) { >+ kqueue_handle_rename(kfnm, fmd, cb_func); >+ } >+ if ((NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB) & kev.fflags) { >+ kqueue_handle_changes(kfnm, fmd, cb_func); >+ } >+ if ((NOTE_DELETE | NOTE_REVOKE) & kev.fflags) { >+ kqueue_file_mon_data_clean(fmd); >+ cb_func(kfnm, fmd, fmd->udata, KF_EVENT_DELETED, >+ fmd->path, "", NULL); >+ } >+ } >+} >Index: devel/glib20/files/kqueue_fnm.h.in >=================================================================== >--- devel/glib20/files/kqueue_fnm.h.in (nonexistent) >+++ devel/glib20/files/kqueue_fnm.h.in (working copy) >@@ -0,0 +1,68 @@ >+/*- >+ * Copyright (c) 2016 - 2017 Rozhuk Ivan <rozhuk.im@gmail.com> >+ * All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND >+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE >+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE >+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL >+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS >+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) >+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT >+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY >+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF >+ * SUCH DAMAGE. >+ * >+ * Author: Rozhuk Ivan <rozhuk.im@gmail.com> >+ * >+ */ >+ >+ >+ >+#ifndef __KQUEUE_FILE_NOTIFY_MONITOR_H__ >+#define __KQUEUE_FILE_NOTIFY_MONITOR_H__ >+ >+#include <sys/param.h> >+#include <sys/types.h> >+#include <inttypes.h> >+ >+ >+typedef struct kqueue_file_nonify_monitor_s *kqueue_fnm_p; >+typedef struct kqueue_file_mon_data_s *kqueue_file_mon_data_p; >+ >+typedef void (*kfnm_event_handler_cb)(kqueue_fnm_p kfnm, >+ kqueue_file_mon_data_p fmd, void *udata, >+ uint32_t event, >+ const char *base, >+ const char *filename, >+ const char *new_filename); >+#define KF_EVENT_NOT_CHANGED 0 /* Internal use. */ >+#define KF_EVENT_CREATED 1 >+#define KF_EVENT_DELETED 2 >+#define KF_EVENT_RENAMED 3 >+#define KF_EVENT_CHANGED 4 >+ >+ >+kqueue_fnm_p kqueue_fnm_create(void); >+void kqueue_fnm_free(kqueue_fnm_p kfnm); >+ >+kqueue_file_mon_data_p kqueue_fnm_add(kqueue_fnm_p kfnm, >+ const char *path, void *udata); >+void kqueue_fnm_del(kqueue_fnm_p kfnm, kqueue_file_mon_data_p fmd); >+ >+int kqueue_fnm_get_ev_recv_fd(kqueue_fnm_p kfnm); >+void kqueue_fnm_proccess_events(kqueue_fnm_p kfnm, >+ kfnm_event_handler_cb cb_func); >+ >+ >+#endif /* __KQUEUE_FILE_NOTIFY_MONITOR_H__ */ >Index: devel/glib20/files/patch-bug739424 >=================================================================== >--- devel/glib20/files/patch-bug739424 (revision 441251) >+++ devel/glib20/files/patch-bug739424 (nonexistent) >@@ -1,59 +0,0 @@ >-From 22656f16c29591207c667362e2a42fd348fe8494 Mon Sep 17 00:00:00 2001 >-From: Martin Pieuchot <mpi@openbsd.org> >-Date: Fri, 28 Apr 2017 15:06:52 +0200 >-Subject: [PATCH] kqueue: fix use-after-free of ``kqueue_sub''. >- >-Since ``kqueue_sub'' are not refcounted it is common to see a thread >-freeing one of them while another thread is manipulating them. This >-leads to crashs reported in: >- https://bugzilla.gnome.org/show_bug.cgi?id=739424 >- >-To prevent such crash, make sure the threads are holding ``hash_lock'' >-when manipulating such items. >---- >- gio/kqueue/kqueue-helper.c | 6 ++++-- >- 1 file changed, 4 insertions(+), 2 deletions(-) >- >-diff --git a/gio/kqueue/kqueue-helper.c b/gio/kqueue/kqueue-helper.c >-index d4e66cd4d..84b9ef164 100644 >---- gio/kqueue/kqueue-helper.c >-+++ gio/kqueue/kqueue-helper.c >-@@ -291,10 +291,10 @@ process_kqueue_notifications (GIOChannel *gioc, >- >- G_LOCK (hash_lock); >- sub = (kqueue_sub *) g_hash_table_lookup (subs_hash_table, GINT_TO_POINTER (n.fd)); >-- G_UNLOCK (hash_lock); >- >- if (sub == NULL) >- { >-+ G_UNLOCK (hash_lock); >- KH_W ("Got a notification for a deleted or non-existing subscription %d", >- n.fd); >- return TRUE; >-@@ -336,6 +336,7 @@ process_kqueue_notifications (GIOChannel *gioc, >- g_file_monitor_source_handle_event (source, mask, NULL, NULL, NULL, g_get_monotonic_time ()); >- } >- >-+ G_UNLOCK (hash_lock); >- return TRUE; >- } >- >-@@ -451,13 +452,14 @@ _kh_start_watching (kqueue_sub *sub) >- >- G_LOCK (hash_lock); >- g_hash_table_insert (subs_hash_table, GINT_TO_POINTER (sub->fd), sub); >-- G_UNLOCK (hash_lock); >- >- _kqueue_thread_push_fd (sub->fd); >- >- /* Bump the kqueue thread. It will pick up a new sub entry to monitor */ >- if (!_ku_write (kqueue_socket_pair[0], "A", 1)) >- KH_W ("Failed to bump the kqueue thread (add fd, error %d)", errno); >-+ G_UNLOCK (hash_lock); >-+ >- return TRUE; >- } >- >--- >-2.12.2 >- >Index: devel/glib20/files/patch-bug778515 >=================================================================== >--- devel/glib20/files/patch-bug778515 (revision 441251) >+++ devel/glib20/files/patch-bug778515 (nonexistent) >@@ -1,55 +0,0 @@ >-From e305fe971e4647d971428a772b7290b9c308a96f Mon Sep 17 00:00:00 2001 >-From: Steven McDonald <steven@steven-mcdonald.id.au> >-Date: Sun, 12 Feb 2017 11:02:55 +1100 >-Subject: gio: Always purge kqueue subs from missing list >- >-Previously, _kh_cancel_sub assumed that it only needed to call >-_km_remove if sub did not exist in subs_hash_table. This is erroneous >-because the complementary operation, _km_add_missing, can be called >-from process_kqueue_notifications, in which context sub can *only* have >-come from subs_hash_table. >- >-Since _km_remove is implemented using g_slist_remove, which is >-documented to be a noop if the list does not contain the element to be >-removed, it is safe to call _km_remove unconditionally here. >- >-https://bugzilla.gnome.org/show_bug.cgi?id=778515 >---- >- gio/kqueue/kqueue-helper.c | 15 +++++---------- >- 1 file changed, 5 insertions(+), 10 deletions(-) >- >-diff --git a/gio/kqueue/kqueue-helper.c b/gio/kqueue/kqueue-helper.c >-index 4671396..d4e66cd 100644 >---- gio/kqueue/kqueue-helper.c >-+++ gio/kqueue/kqueue-helper.c >-@@ -498,22 +498,17 @@ _kh_add_sub (kqueue_sub *sub) >- gboolean >- _kh_cancel_sub (kqueue_sub *sub) >- { >-- gboolean missing = FALSE; >-+ gboolean removed = FALSE; >- g_assert (kqueue_socket_pair[0] != -1); >- g_assert (sub != NULL); >- >-+ _km_remove (sub); >-+ >- G_LOCK (hash_lock); >-- missing = !g_hash_table_remove (subs_hash_table, GINT_TO_POINTER (sub->fd)); >-+ removed = g_hash_table_remove (subs_hash_table, GINT_TO_POINTER (sub->fd)); >- G_UNLOCK (hash_lock); >- >-- if (missing) >-- { >-- /* If there were no fd for this subscription, file is still >-- * missing. */ >-- KH_W ("Removing subscription from missing"); >-- _km_remove (sub); >-- } >-- else >-+ if (removed) >- { >- /* fd will be closed in the kqueue thread */ >- _kqueue_thread_remove_fd (sub->fd); >--- >-cgit v0.12 >- >Index: devel/glib20/files/patch-gio_kqueue_Makefile.am >=================================================================== >--- devel/glib20/files/patch-gio_kqueue_Makefile.am (nonexistent) >+++ devel/glib20/files/patch-gio_kqueue_Makefile.am (working copy) >@@ -0,0 +1,26 @@ >+--- gio/kqueue/Makefile.am.orig 2015-10-14 14:41:16.000000000 +0300 >++++ gio/kqueue/Makefile.am 2016-11-06 05:08:37.646089000 +0300 >+@@ -4,21 +4,8 @@ >+ >+ libkqueue_la_SOURCES = \ >+ gkqueuefilemonitor.c \ >+- gkqueuefilemonitor.h \ >+- kqueue-helper.c \ >+- kqueue-helper.h \ >+- kqueue-thread.c \ >+- kqueue-thread.h \ >+- kqueue-sub.c \ >+- kqueue-sub.h \ >+- kqueue-missing.c \ >+- kqueue-missing.h \ >+- kqueue-utils.c \ >+- kqueue-utils.h \ >+- kqueue-exclusions.c \ >+- kqueue-exclusions.h \ >+- dep-list.c \ >+- dep-list.h \ >++ kqueue_fnm.c \ >++ kqueue_fnm.h \ >+ $(NULL) >+ >+ libkqueue_la_CFLAGS = \ >Index: devel/glib20/files/patch-gio_kqueue_gkqueuefilemonitor.c >=================================================================== >--- devel/glib20/files/patch-gio_kqueue_gkqueuefilemonitor.c (nonexistent) >+++ devel/glib20/files/patch-gio_kqueue_gkqueuefilemonitor.c (working copy) >@@ -0,0 +1,372 @@ >+--- gio/kqueue/gkqueuefilemonitor.c.orig 2015-10-14 14:41:16.000000000 +0300 >++++ gio/kqueue/gkqueuefilemonitor.c 2016-11-06 05:01:49.712277000 +0300 >+@@ -1,198 +1,203 @@ >+-/******************************************************************************* >+- Copyright (c) 2011, 2012 Dmitry Matveev <me@dmitrymatveev.co.uk> >+- >+- Permission is hereby granted, free of charge, to any person obtaining a copy >+- of this software and associated documentation files (the "Software"), to deal >+- in the Software without restriction, including without limitation the rights >+- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell >+- copies of the Software, and to permit persons to whom the Software is >+- furnished to do so, subject to the following conditions: >+- >+- The above copyright notice and this permission notice shall be included in >+- all copies or substantial portions of the Software. >+- >+- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR >+- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, >+- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE >+- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER >+- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, >+- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN >+- THE SOFTWARE. >+-*******************************************************************************/ >++/*- >++ * Copyright (c) 2016 Rozhuk Ivan <rozhuk.im@gmail.com> >++ * All rights reserved. >++ * >++ * Redistribution and use in source and binary forms, with or without >++ * modification, are permitted provided that the following conditions >++ * are met: >++ * 1. Redistributions of source code must retain the above copyright >++ * notice, this list of conditions and the following disclaimer. >++ * 2. Redistributions in binary form must reproduce the above copyright >++ * notice, this list of conditions and the following disclaimer in the >++ * documentation and/or other materials provided with the distribution. >++ * >++ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND >++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE >++ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE >++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL >++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS >++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) >++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT >++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY >++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF >++ * SUCH DAMAGE. >++ * >++ * Author: Rozhuk Ivan <rozhuk.im@gmail.com> >++ * >++ */ >+ >+ #include "config.h" >+ >+-#include "gkqueuefilemonitor.h" >+-#include "kqueue-helper.h" >+-#include "kqueue-exclusions.h" >+-#include <gio/gpollfilemonitor.h> >+-#include <gio/gfile.h> >++#include <glib-object.h> >++#include <string.h> >++#include <gio/gfilemonitor.h> >++#include <gio/glocalfilemonitor.h> >+ #include <gio/giomodule.h> >++#include "glib-private.h" >++#include <glib-unix.h> >++#include "kqueue_fnm.h" >+ >+ >+-struct _GKqueueFileMonitor >+-{ >+- GLocalFileMonitor parent_instance; >++static GMutex kqueue_lock; >++static GSource *kqueue_source = NULL; >++static volatile kqueue_fnm_p kqueue_fnm = NULL; >+ >+- kqueue_sub *sub; >++#define G_TYPE_KQUEUE_FILE_MONITOR (g_kqueue_file_monitor_get_type()) >++#define G_KQUEUE_FILE_MONITOR(inst) (G_TYPE_CHECK_INSTANCE_CAST((inst), \ >++ G_TYPE_KQUEUE_FILE_MONITOR, GKqueueFileMonitor)) >+ >+- GFileMonitor *fallback; >+- GFile *fbfile; >+-}; >++typedef GLocalFileMonitorClass GKqueueFileMonitorClass; >+ >+-static gboolean g_kqueue_file_monitor_cancel (GFileMonitor* monitor); >++typedef struct { >++ GLocalFileMonitor parent_instance; >++ kqueue_file_mon_data_p fmd; >++} GKqueueFileMonitor; >+ >++GType g_kqueue_file_monitor_get_type(void); >+ G_DEFINE_TYPE_WITH_CODE (GKqueueFileMonitor, g_kqueue_file_monitor, G_TYPE_LOCAL_FILE_MONITOR, >+- g_io_extension_point_implement (G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME, >++ g_io_extension_point_implement(G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME, >+ g_define_type_id, >+ "kqueue", >+- 20)) >++ 10)) >+ >+ >+ static void >+-_fallback_callback (GFileMonitor *unused, >+- GFile *first, >+- GFile *second, >+- GFileMonitorEvent event, >+- gpointer udata) >+-{ >+- GKqueueFileMonitor *kq_mon = G_KQUEUE_FILE_MONITOR (udata); >+- GFileMonitor *mon = G_FILE_MONITOR (kq_mon); >+- g_assert (kq_mon != NULL); >+- g_assert (mon != NULL); >+- (void) unused; >+- >+- if (event == G_FILE_MONITOR_EVENT_CHANGED) >+- { >+- GLocalFileMonitor *local_monitor = G_LOCAL_FILE_MONITOR (kq_mon); >+- >+- _kh_dir_diff (kq_mon->sub, local_monitor->source); >+- } >+- else >+- g_file_monitor_emit_event (mon, first, second, event); >+-} >+- >+- >+-static void >+-g_kqueue_file_monitor_finalize (GObject *object) >+-{ >+- GKqueueFileMonitor *kqueue_monitor = G_KQUEUE_FILE_MONITOR (object); >+- >+- if (kqueue_monitor->sub) >+- { >+- _kh_cancel_sub (kqueue_monitor->sub); >+- _kh_sub_free (kqueue_monitor->sub); >+- kqueue_monitor->sub = NULL; >+- } >+- >+- if (kqueue_monitor->fallback) >+- g_object_unref (kqueue_monitor->fallback); >+- >+- if (kqueue_monitor->fbfile) >+- g_object_unref (kqueue_monitor->fbfile); >+- >+- if (G_OBJECT_CLASS (g_kqueue_file_monitor_parent_class)->finalize) >+- (*G_OBJECT_CLASS (g_kqueue_file_monitor_parent_class)->finalize) (object); >+-} >+- >+-static void >+-g_kqueue_file_monitor_start (GLocalFileMonitor *local_monitor, >+- const gchar *dirname, >+- const gchar *basename, >+- const gchar *filename, >+- GFileMonitorSource *source) >+-{ >+- GKqueueFileMonitor *kqueue_monitor = G_KQUEUE_FILE_MONITOR (local_monitor); >+- GObject *obj; >+- GKqueueFileMonitorClass *klass; >+- GObjectClass *parent_class; >+- kqueue_sub *sub = NULL; >+- gboolean ret_kh_startup = FALSE; >+- const gchar *path = NULL; >+- >+- >+- ret_kh_startup = _kh_startup (); >+- g_assert (ret_kh_startup); >+- >+- path = filename; >+- if (!path) >+- path = dirname; >+- >+- /* For a directory monitor, create a subscription object anyway. >+- * It will be used for directory diff calculation routines. >+- * Wait, directory diff in a GKqueueFileMonitor? >+- * Yes, it is. When a file monitor is started on an non-existent >+- * file, GIO uses a GKqueueFileMonitor object for that. If a directory >+- * will be created under that path, GKqueueFileMonitor will have to >+- * handle the directory notifications. */ >+- >+- sub = _kh_sub_new (path, TRUE, source); >+- >+- /* FIXME: what to do about errors here? we can't return NULL or another >+- * kind of error and an assertion is probably too hard (same issue as in >+- * the inotify backend) */ >+- g_assert (sub != NULL); >+- kqueue_monitor->sub = sub; >+- >+- if (!_ke_is_excluded (path)) >+- _kh_add_sub (sub); >+- else >+- { >+- GFile *file = g_file_new_for_path (path); >+- kqueue_monitor->fbfile = file; >+- kqueue_monitor->fallback = _g_poll_file_monitor_new (file); >+- g_signal_connect (kqueue_monitor->fallback, >+- "changed", >+- G_CALLBACK (_fallback_callback), >+- kqueue_monitor); >+- } >++kqueue_event_handler(kqueue_fnm_p kfnm, >++ kqueue_file_mon_data_p fmd, void *udata, uint32_t event, >++ const char *base, const char *filename, const char *new_filename) { >++ static const uint32_t kfnm_to_glib_map[] = { >++ 0, /* KF_EVENT_NOT_CHANGED */ >++ G_FILE_MONITOR_EVENT_CREATED, /* KF_EVENT_CREATED */ >++ G_FILE_MONITOR_EVENT_DELETED, /* KF_EVENT_DELETED */ >++ G_FILE_MONITOR_EVENT_RENAMED, /* KF_EVENT_RENAMED */ >++ G_FILE_MONITOR_EVENT_CHANGED /* KF_EVENT_CHANGED */ >++ }; >++ >++ if (NULL == kfnm || NULL == filename || >++ KF_EVENT_CREATED > event || >++ KF_EVENT_CHANGED < event) >++ return; >++ g_file_monitor_source_handle_event(udata, >++ kfnm_to_glib_map[event], >++ filename, new_filename, NULL, >++ g_source_get_time(kqueue_source)); >++} >++ >++static gboolean >++g_kqueue_file_monitor_callback(gint fd, GIOCondition condition, gpointer user_data) { >++ >++ /* Only one thread process events. */ >++ g_mutex_lock(&kqueue_lock); >++ kqueue_fnm_proccess_events(kqueue_fnm, kqueue_event_handler); >++ g_mutex_unlock(&kqueue_lock); >++ >++ return (TRUE); >++} >++ >++static gboolean >++g_kqueue_file_monitor_is_supported(void) { >++ >++ if (NULL != kqueue_fnm) >++ return (TRUE); >++ /* Init only once. */ >++ g_mutex_lock(&kqueue_lock); >++ if (NULL != kqueue_fnm) { >++ g_mutex_unlock(&kqueue_lock); >++ return (TRUE); /* Initialized while wait lock. */ >++ } >++ kqueue_fnm = kqueue_fnm_create(); >++ if (NULL == kqueue_fnm) { >++ g_mutex_unlock(&kqueue_lock); >++ return (FALSE); /* Init fail. */ >++ } >++ kqueue_source = g_unix_fd_source_new(kqueue_fnm_get_ev_recv_fd(kqueue_fnm), G_IO_IN); >++ g_source_set_callback(kqueue_source, (GSourceFunc)g_kqueue_file_monitor_callback, NULL, NULL); >++ g_source_attach(kqueue_source, GLIB_PRIVATE_CALL(g_get_worker_context)()); >++ g_mutex_unlock(&kqueue_lock); >++ >++ return (TRUE); >+ } >+ >+ static gboolean >+-g_kqueue_file_monitor_is_supported (void) >+-{ >+- return _kh_startup (); >++g_kqueue_file_monitor_cancel(GFileMonitor *monitor) { >++ GKqueueFileMonitor *gffm = G_KQUEUE_FILE_MONITOR(monitor); >++ >++ kqueue_fnm_del(kqueue_fnm, gffm->fmd); >++ gffm->fmd = NULL; >++ >++ return (TRUE); >+ } >+ >+ static void >+-g_kqueue_file_monitor_class_init (GKqueueFileMonitorClass *klass) >+-{ >+- GObjectClass *gobject_class = G_OBJECT_CLASS (klass); >+- GFileMonitorClass *file_monitor_class = G_FILE_MONITOR_CLASS (klass); >+- GLocalFileMonitorClass *local_file_monitor_class = G_LOCAL_FILE_MONITOR_CLASS (klass); >++g_kqueue_file_monitor_finalize(GObject *object) { >++ GKqueueFileMonitor *gffm = G_KQUEUE_FILE_MONITOR(object); >+ >+- gobject_class->finalize = g_kqueue_file_monitor_finalize; >+- file_monitor_class->cancel = g_kqueue_file_monitor_cancel; >++ kqueue_fnm_del(kqueue_fnm, gffm->fmd); >++ gffm->fmd = NULL; >++} >+ >+- local_file_monitor_class->is_supported = g_kqueue_file_monitor_is_supported; >+- local_file_monitor_class->start = g_kqueue_file_monitor_start; >+- local_file_monitor_class->mount_notify = TRUE; /* TODO: ??? */ >++static void >++g_kqueue_file_monitor_start(GLocalFileMonitor *local_monitor, >++ const gchar *dirname, const gchar *basename, >++ const gchar *filename, GFileMonitorSource *source) { >++ GKqueueFileMonitor *gffm = G_KQUEUE_FILE_MONITOR (local_monitor); >++ >++ g_assert(NULL != kqueue_fnm); >++ g_source_ref((GSource*)source); >++ >++ if (NULL == filename) { >++ filename = dirname; >++ } >++ gffm->fmd = kqueue_fnm_add(kqueue_fnm, filename, source); >+ } >+ >+ static void >+-g_kqueue_file_monitor_init (GKqueueFileMonitor *monitor) >+-{ >++g_kqueue_file_monitor_init(GKqueueFileMonitor *monitor) { >++ >+ } >+ >+-static gboolean >+-g_kqueue_file_monitor_cancel (GFileMonitor *monitor) >+-{ >+- GKqueueFileMonitor *kqueue_monitor = G_KQUEUE_FILE_MONITOR (monitor); >+- >+- if (kqueue_monitor->sub) >+- { >+- _kh_cancel_sub (kqueue_monitor->sub); >+- _kh_sub_free (kqueue_monitor->sub); >+- kqueue_monitor->sub = NULL; >+- } >+- else if (kqueue_monitor->fallback) >+- { >+- g_signal_handlers_disconnect_by_func (kqueue_monitor->fallback, _fallback_callback, kqueue_monitor); >+- g_file_monitor_cancel (kqueue_monitor->fallback); >+- } >++static void >++g_kqueue_file_monitor_class_init(GKqueueFileMonitorClass *class) { >++ GObjectClass *gobject_class = G_OBJECT_CLASS(class); >++ GFileMonitorClass *file_monitor_class = G_FILE_MONITOR_CLASS(class); >++ >++ class->is_supported = g_kqueue_file_monitor_is_supported; >++ class->start = g_kqueue_file_monitor_start; >++ class->mount_notify = TRUE; /* TODO: ??? */ >++ file_monitor_class->cancel = g_kqueue_file_monitor_cancel; >++ gobject_class->finalize = g_kqueue_file_monitor_finalize; >++} >++ >++static void >++g_kqueue_file_monitor_class_finalize(GKqueueFileMonitorClass *class) { >++ >++} >++ >++void >++g_io_module_load(GIOModule *module) { >++ >++ g_type_module_use(G_TYPE_MODULE(module)); >++ >++ g_io_extension_point_implement(G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME, >++ G_TYPE_KQUEUE_FILE_MONITOR, "kqueue", 10); >++ g_io_extension_point_implement(G_NFS_FILE_MONITOR_EXTENSION_POINT_NAME, >++ G_TYPE_KQUEUE_FILE_MONITOR, "kqueue", 10); >++} >++ >++void >++g_io_module_unload(GIOModule *module) { >++ >++ g_assert_not_reached(); >++} >+ >+- if (G_FILE_MONITOR_CLASS (g_kqueue_file_monitor_parent_class)->cancel) >+- (*G_FILE_MONITOR_CLASS (g_kqueue_file_monitor_parent_class)->cancel) (monitor); >++char ** >++g_io_module_query(void) { >++ char *eps[] = { >++ G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME, >++ G_NFS_FILE_MONITOR_EXTENSION_POINT_NAME, >++ NULL >++ }; >+ >+- return TRUE; >++ return (g_strdupv(eps)); >+ }
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 214338
:
176801
|
178938
|
181557
|
181816
|
182423
|
182749
|
184001
|
184287
|
184290
|
184301
|
184456
|
188088
|
188134
|
188144
|
188261
|
188262
|
190711
|
190712
|
191448
|
195450
|
195570
|
195597
|
195598
|
195618
|
195619
|
195649
|
195650
|
198889
|
198900
|
199221
|
199229
|
202832
|
202839
|
202935
|
202948
|
204279
|
204331
|
218219
|
222442