Asynchronous Reads for Dirmonitor (#930)
Change dirmonitor reads to be synchronous, in a secondary thread.
This commit is contained in:
@@ -1,22 +1,8 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
struct dirmonitor {
|
||||
};
|
||||
|
||||
struct dirmonitor* init_dirmonitor_dummy() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void deinit_dirmonitor_dummy(struct dirmonitor* monitor) {
|
||||
}
|
||||
|
||||
int check_dirmonitor_dummy(struct dirmonitor* monitor, int (*change_callback)(int, const char*, void*), void* data) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int add_dirmonitor_dummy(struct dirmonitor* monitor, const char* path) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
void remove_dirmonitor_dummy(struct dirmonitor* monitor, int fd) {
|
||||
}
|
||||
struct dirmonitor_internal* init_dirmonitor() { return NULL; }
|
||||
void deinit_dirmonitor(struct dirmonitor_internal*) { }
|
||||
int get_changes_dirmonitor(struct dirmonitor_internal*, char*, size_t) { return -1; }
|
||||
int translate_changes_dirmonitor(struct dirmonitor_internal*, char*, int, int (*)(int, const char*, void*), void*) { return -1; }
|
||||
int add_dirmonitor(struct dirmonitor_internal*, const char*) { return -1; }
|
||||
void remove_dirmonitor(struct dirmonitor_internal*, int) { }
|
||||
|
||||
@@ -1,58 +1,53 @@
|
||||
#include <sys/inotify.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/select.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
struct dirmonitor {
|
||||
|
||||
struct dirmonitor_internal {
|
||||
int fd;
|
||||
// a pipe is used to wake the thread in case of exit
|
||||
int sig[2];
|
||||
};
|
||||
|
||||
struct dirmonitor* init_dirmonitor_inotify() {
|
||||
struct dirmonitor* monitor = calloc(sizeof(struct dirmonitor), 1);
|
||||
|
||||
struct dirmonitor_internal* init_dirmonitor() {
|
||||
struct dirmonitor_internal* monitor = calloc(sizeof(struct dirmonitor_internal), 1);
|
||||
monitor->fd = inotify_init();
|
||||
fcntl(monitor->fd, F_SETFL, O_NONBLOCK);
|
||||
|
||||
|
||||
pipe(monitor->sig);
|
||||
return monitor;
|
||||
}
|
||||
|
||||
void deinit_dirmonitor_inotify(struct dirmonitor* monitor) {
|
||||
|
||||
void deinit_dirmonitor(struct dirmonitor_internal* monitor) {
|
||||
close(monitor->sig[0]);
|
||||
close(monitor->sig[1]);
|
||||
close(monitor->fd);
|
||||
free(monitor);
|
||||
}
|
||||
|
||||
int check_dirmonitor_inotify(struct dirmonitor* monitor, int (*change_callback)(int, const char*, void*), void* data) {
|
||||
char buf[PATH_MAX + sizeof(struct inotify_event)];
|
||||
ssize_t offset = 0;
|
||||
|
||||
while (1) {
|
||||
ssize_t len = read(monitor->fd, &buf[offset], sizeof(buf) - offset);
|
||||
|
||||
if (len == -1 && errno != EAGAIN) {
|
||||
return errno;
|
||||
}
|
||||
|
||||
if (len <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (len > sizeof(struct inotify_event) && len >= ((struct inotify_event*)buf)->len + sizeof(struct inotify_event)) {
|
||||
change_callback(((const struct inotify_event *)buf)->wd, NULL, data);
|
||||
len -= sizeof(struct inotify_event) + ((struct inotify_event*)buf)->len;
|
||||
memmove(buf, &buf[sizeof(struct inotify_event) + ((struct inotify_event*)buf)->len], len);
|
||||
offset = len;
|
||||
}
|
||||
}
|
||||
int get_changes_dirmonitor(struct dirmonitor_internal* monitor, char* buffer, int length) {
|
||||
fd_set set;
|
||||
FD_ZERO(&set);
|
||||
FD_SET(monitor->fd, &set);
|
||||
FD_SET(monitor->sig[0], &set);
|
||||
select(FD_SETSIZE, &set, NULL, NULL, NULL);
|
||||
return read(monitor->fd, buffer, length);
|
||||
}
|
||||
|
||||
int add_dirmonitor_inotify(struct dirmonitor* monitor, const char* path) {
|
||||
|
||||
int translate_changes_dirmonitor(struct dirmonitor_internal* monitor, char* buffer, int length, int (*change_callback)(int, const char*, void*), void* data) {
|
||||
for (struct inotify_event* info = (struct inotify_event*)buffer; (char*)info < buffer + length; info = (struct inotify_event*)((char*)info + sizeof(struct inotify_event)))
|
||||
change_callback(info->wd, NULL, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int add_dirmonitor(struct dirmonitor_internal* monitor, const char* path) {
|
||||
return inotify_add_watch(monitor->fd, path, IN_CREATE | IN_DELETE | IN_MOVED_FROM | IN_MOVED_TO);
|
||||
}
|
||||
|
||||
void remove_dirmonitor_inotify(struct dirmonitor* monitor, int fd) {
|
||||
|
||||
void remove_dirmonitor(struct dirmonitor_internal* monitor, int fd) {
|
||||
inotify_rm_watch(monitor->fd, fd);
|
||||
}
|
||||
}
|
||||
|
||||
+25
-23
@@ -5,40 +5,41 @@
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
struct dirmonitor {
|
||||
struct dirmonitor_internal {
|
||||
int fd;
|
||||
};
|
||||
|
||||
struct dirmonitor* init_dirmonitor_kqueue() {
|
||||
struct dirmonitor* monitor = calloc(sizeof(struct dirmonitor), 1);
|
||||
|
||||
struct dirmonitor_internal* init_dirmonitor() {
|
||||
struct dirmonitor_internal* monitor = calloc(sizeof(struct dirmonitor_internal), 1);
|
||||
monitor->fd = kqueue();
|
||||
return monitor;
|
||||
}
|
||||
|
||||
void deinit_dirmonitor_kqueue(struct dirmonitor* monitor) {
|
||||
|
||||
void deinit_dirmonitor(struct dirmonitor_internal* monitor) {
|
||||
close(monitor->fd);
|
||||
free(monitor);
|
||||
}
|
||||
|
||||
int check_dirmonitor_kqueue(struct dirmonitor* monitor, int (*change_callback)(int, const char*, void*), void* data) {
|
||||
struct kevent event;
|
||||
while (1) {
|
||||
struct timespec tm = {0};
|
||||
int nev = kevent(monitor->fd, NULL, 0, &event, 1, &tm);
|
||||
|
||||
if (nev == -1) {
|
||||
return errno;
|
||||
}
|
||||
|
||||
if (nev <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
change_callback(event.ident, NULL, data);
|
||||
}
|
||||
int get_changes_dirmonitor(struct dirmonitor_internal* monitor, char* buffer, int buffer_size) {
|
||||
int nev = kevent(monitor->fd, NULL, 0, (struct kevent*)buffer, buffer_size / sizeof(kevent), NULL);
|
||||
if (nev == -1)
|
||||
return -1;
|
||||
if (nev <= 0)
|
||||
return 0;
|
||||
return nev * sizeof(struct kevent);
|
||||
}
|
||||
|
||||
int add_dirmonitor_kqueue(struct dirmonitor* monitor, const char* path) {
|
||||
|
||||
int translate_changes_dirmonitor(struct dirmonitor_internal* monitor, char* buffer, int buffer_size, int (*change_callback)(int, const char*, void*), void* data) {
|
||||
for (struct kevent* info = (struct kevent*)buffer; (char*)info < buffer + buffer_size; info = (struct kevent*)(((char*)info) + sizeof(kevent)))
|
||||
change_callback(info->ident, NULL, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int add_dirmonitor(struct dirmonitor_internal* monitor, const char* path) {
|
||||
int fd = open(path, O_RDONLY);
|
||||
struct kevent change;
|
||||
|
||||
@@ -48,6 +49,7 @@ int add_dirmonitor_kqueue(struct dirmonitor* monitor, const char* path) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
void remove_dirmonitor_kqueue(struct dirmonitor* monitor, int fd) {
|
||||
|
||||
void remove_dirmonitor(struct dirmonitor_internal* monitor, int fd) {
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
+48
-63
@@ -1,77 +1,62 @@
|
||||
#include <stdbool.h>
|
||||
#include <windows.h>
|
||||
|
||||
struct dirmonitor {
|
||||
|
||||
struct dirmonitor_internal {
|
||||
HANDLE handle;
|
||||
char buffer[64512];
|
||||
OVERLAPPED overlapped;
|
||||
bool running;
|
||||
};
|
||||
|
||||
struct dirmonitor* init_dirmonitor_win32() {
|
||||
struct dirmonitor* monitor = calloc(sizeof(struct dirmonitor), 1);
|
||||
|
||||
return monitor;
|
||||
}
|
||||
|
||||
static void close_monitor_handle(struct dirmonitor* monitor) {
|
||||
if (monitor->handle) {
|
||||
if (monitor->running) {
|
||||
BOOL result = CancelIoEx(monitor->handle, &monitor->overlapped);
|
||||
DWORD error = GetLastError();
|
||||
if (result == TRUE || error != ERROR_NOT_FOUND) {
|
||||
DWORD bytes_transferred;
|
||||
GetOverlappedResult( monitor->handle, &monitor->overlapped, &bytes_transferred, TRUE );
|
||||
}
|
||||
monitor->running = false;
|
||||
}
|
||||
CloseHandle(monitor->handle);
|
||||
}
|
||||
monitor->handle = NULL;
|
||||
}
|
||||
|
||||
void deinit_dirmonitor_win32(struct dirmonitor* monitor) {
|
||||
close_monitor_handle(monitor);
|
||||
free(monitor);
|
||||
}
|
||||
|
||||
int check_dirmonitor_win32(struct dirmonitor* monitor, int (*change_callback)(int, const char*, void*), void* data) {
|
||||
if (!monitor->running) {
|
||||
if (ReadDirectoryChangesW(monitor->handle, monitor->buffer, sizeof(monitor->buffer), TRUE, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME, NULL, &monitor->overlapped, NULL) == 0) {
|
||||
return GetLastError();
|
||||
}
|
||||
monitor->running = true;
|
||||
int get_changes_dirmonitor(struct dirmonitor_internal* monitor, char* buffer, int buffer_size) {
|
||||
HANDLE handle = monitor->handle;
|
||||
if (handle && handle != INVALID_HANDLE_VALUE) {
|
||||
DWORD bytes_transferred;
|
||||
if (ReadDirectoryChangesW(handle, buffer, buffer_size, TRUE, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME, &bytes_transferred, NULL, NULL) == 0)
|
||||
return 0;
|
||||
return bytes_transferred;
|
||||
}
|
||||
|
||||
DWORD bytes_transferred;
|
||||
|
||||
if (!GetOverlappedResult(monitor->handle, &monitor->overlapped, &bytes_transferred, FALSE)) {
|
||||
int error = GetLastError();
|
||||
return error == ERROR_IO_PENDING || error == ERROR_IO_INCOMPLETE ? 0 : error;
|
||||
}
|
||||
|
||||
monitor->running = false;
|
||||
|
||||
for (FILE_NOTIFY_INFORMATION* info = (FILE_NOTIFY_INFORMATION*)monitor->buffer; (char*)info < monitor->buffer + sizeof(monitor->buffer); info = (FILE_NOTIFY_INFORMATION*)(((char*)info) + info->NextEntryOffset)) {
|
||||
change_callback(info->FileNameLength / sizeof(WCHAR), (char*)info->FileName, data);
|
||||
if (!info->NextEntryOffset)
|
||||
break;
|
||||
}
|
||||
|
||||
monitor->running = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int add_dirmonitor_win32(struct dirmonitor* monitor, const char* path) {
|
||||
close_monitor_handle(monitor);
|
||||
monitor->handle = CreateFileA(path, FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL);
|
||||
if (monitor->handle && monitor->handle != INVALID_HANDLE_VALUE) {
|
||||
return 1;
|
||||
}
|
||||
monitor->handle = NULL;
|
||||
return -1;
|
||||
|
||||
struct dirmonitor* init_dirmonitor() {
|
||||
return calloc(sizeof(struct dirmonitor_internal), 1);
|
||||
}
|
||||
|
||||
void remove_dirmonitor_win32(struct dirmonitor* monitor, int fd) {
|
||||
|
||||
static void close_monitor_handle(struct dirmonitor_internal* monitor) {
|
||||
if (monitor->handle && monitor->handle != INVALID_HANDLE_VALUE) {
|
||||
HANDLE handle = monitor->handle;
|
||||
monitor->handle = NULL;
|
||||
CancelIoEx(handle, NULL);
|
||||
CloseHandle(handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void deinit_dirmonitor(struct dirmonitor_internal* monitor) {
|
||||
close_monitor_handle(monitor);
|
||||
}
|
||||
|
||||
|
||||
int translate_changes_dirmonitor(struct dirmonitor_internal* monitor, char* buffer, int buffer_size, int (*change_callback)(int, const char*, void*), void* data) {
|
||||
for (FILE_NOTIFY_INFORMATION* info = (FILE_NOTIFY_INFORMATION*)buffer; (char*)info < buffer + buffer_size; info = (FILE_NOTIFY_INFORMATION*)(((char*)info) + info->NextEntryOffset)) {
|
||||
char transform_buffer[PATH_MAX*4];
|
||||
int count = WideCharToMultiByte(CP_UTF8, 0, (WCHAR*)info->FileName, info->FileNameLength, transform_buffer, PATH_MAX*4 - 1, NULL, NULL);
|
||||
change_callback(count, buffer, data);
|
||||
if (!info->NextEntryOffset)
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int add_dirmonitor(struct dirmonitor_internal* monitor, const char* path) {
|
||||
close_monitor_handle(monitor);
|
||||
monitor->handle = CreateFileA(path, FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
||||
return !monitor->handle || monitor->handle == INVALID_HANDLE_VALUE ? -1 : 1;
|
||||
}
|
||||
|
||||
|
||||
void remove_dirmonitor(struct dirmonitor_internal* monitor, int fd) {
|
||||
close_monitor_handle(monitor);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user