aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFrancesco Abbate <francesco.bbt@gmail.com>2021-10-08 21:55:43 +0200
committerFrancesco Abbate <francesco.bbt@gmail.com>2021-10-08 21:55:43 +0200
commitbba42adc73bf592b9de4aa4a5d44410618ec59ae (patch)
tree6291c60259ee9d7807d56166841ae5d59ea7697f /src
parent9c43727ebc269cb0695f6d418e5bf88615677aaf (diff)
downloadlite-xl-bba42adc73bf592b9de4aa4a5d44410618ec59ae.tar.gz
lite-xl-bba42adc73bf592b9de4aa4a5d44410618ec59ae.zip
Adopt new version of dmon
Diffstat (limited to 'src')
-rw-r--r--src/dirmonitor.c1
-rw-r--r--src/dirmonitor.h1
-rw-r--r--src/dmon.h130
-rw-r--r--src/dmon_extra.h162
4 files changed, 170 insertions, 124 deletions
diff --git a/src/dirmonitor.c b/src/dirmonitor.c
index eb3b185f..958d463e 100644
--- a/src/dirmonitor.c
+++ b/src/dirmonitor.c
@@ -5,6 +5,7 @@
#define DMON_IMPL
#include "dmon.h"
+#include "dmon_extra.h"
#include "dirmonitor.h"
diff --git a/src/dirmonitor.h b/src/dirmonitor.h
index ab9376c0..074a9ae8 100644
--- a/src/dirmonitor.h
+++ b/src/dirmonitor.h
@@ -4,6 +4,7 @@
#include <stdint.h>
#include "dmon.h"
+#include "dmon_extra.h"
void dirmonitor_init();
void dirmonitor_deinit();
diff --git a/src/dmon.h b/src/dmon.h
index 1ccae446..ed10d11f 100644
--- a/src/dmon.h
+++ b/src/dmon.h
@@ -1,3 +1,6 @@
+#ifndef __DMON_H__
+#define __DMON_H__
+
//
// Copyright 2021 Sepehr Taghdisian (septag@github). All rights reserved.
// License: https://github.com/septag/dmon#license-bsd-2-clause
@@ -68,9 +71,9 @@
// 1.1.1 Minor fixes, eliminate gcc/clang warnings with -Wall
// 1.1.2 Eliminate some win32 dead code
// 1.1.3 Fixed select not resetting causing high cpu usage on linux
+// 1.2.1 inotify (linux) fixes and improvements, added extra functionality header for linux
+// to manually add/remove directories manually to the watch handle, in case of large file sets
//
-#ifndef __DMON_H__
-#define __DMON_H__
#include <stdbool.h>
#include <stdint.h>
@@ -114,8 +117,6 @@ DMON_API_DECL dmon_watch_id dmon_watch(const char* rootdir,
const char* oldfilepath, void* user),
uint32_t flags, void* user_data);
DMON_API_DECL void dmon_unwatch(dmon_watch_id id);
-DMON_API_DECL bool dmon_watch_add(dmon_watch_id id, const char* subdir);
-DMON_API_DECL bool dmon_watch_rm(dmon_watch_id id, const char* watchdir);
#ifdef __cplusplus
}
@@ -322,6 +323,7 @@ _DMON_PRIVATE char* dmon__strcat(char* dst, int dst_sz, const char* src)
// stretchy buffer: https://github.com/nothings/stb/blob/master/stretchy_buffer.h
#define stb_sb_free(a) ((a) ? DMON_FREE(stb__sbraw(a)),0 : 0)
#define stb_sb_push(a,v) (stb__sbmaybegrow(a,1), (a)[stb__sbn(a)++] = (v))
+#define stb_sb_pop(a) (stb__sbn(a)--)
#define stb_sb_count(a) ((a) ? stb__sbn(a) : 0)
#define stb_sb_add(a,n) (stb__sbmaybegrow(a,n), stb__sbn(a)+=(n), &(a)[stb__sbn(a)-(n)])
#define stb_sb_last(a) ((a)[stb__sbn(a)-1])
@@ -763,126 +765,6 @@ _DMON_PRIVATE void dmon__watch_recursive(const char* dirname, int fd, uint32_t m
closedir(dir);
}
-DMON_API_IMPL bool dmon_watch_add(dmon_watch_id id, const char* watchdir)
-{
- DMON_ASSERT(id.id > 0 && id.id <= DMON_MAX_WATCHES);
-
- bool skip_lock = pthread_self() == _dmon.thread_handle;
-
- if (!skip_lock)
- pthread_mutex_lock(&_dmon.mutex);
-
- dmon__watch_state* watch = &_dmon.watches[id.id - 1];
-
- // check if the directory exists
- // if watchdir contains absolute/root-included path, try to strip the rootdir from it
- // else, we assume that watchdir is correct, so save it as it is
- struct stat st;
- dmon__watch_subdir subdir;
- if (stat(watchdir, &st) == 0 && (st.st_mode & S_IFDIR)) {
- dmon__strcpy(subdir.rootdir, sizeof(subdir.rootdir), watchdir);
- if (strstr(subdir.rootdir, watch->rootdir) == subdir.rootdir) {
- dmon__strcpy(subdir.rootdir, sizeof(subdir.rootdir), watchdir + strlen(watch->rootdir));
- }
- } else {
- char fullpath[DMON_MAX_PATH];
- dmon__strcpy(fullpath, sizeof(fullpath), watch->rootdir);
- dmon__strcat(fullpath, sizeof(fullpath), watchdir);
- if (stat(fullpath, &st) != 0 || (st.st_mode & S_IFDIR) == 0) {
- _DMON_LOG_ERRORF("Watch directory '%s' is not valid", watchdir);
- if (!skip_lock)
- pthread_mutex_unlock(&_dmon.mutex);
- return false;
- }
- dmon__strcpy(subdir.rootdir, sizeof(subdir.rootdir), watchdir);
- }
-
- int dirlen = (int)strlen(subdir.rootdir);
- if (subdir.rootdir[dirlen - 1] != '/') {
- subdir.rootdir[dirlen] = '/';
- subdir.rootdir[dirlen + 1] = '\0';
- }
-
- // check that the directory is not already added
- for (int i = 0, c = stb_sb_count(watch->subdirs); i < c; i++) {
- if (strcmp(subdir.rootdir, watch->subdirs[i].rootdir) == 0) {
- _DMON_LOG_ERRORF("Error watching directory '%s', because it is already added.", watchdir);
- if (!skip_lock)
- pthread_mutex_unlock(&_dmon.mutex);
- return false;
- }
- }
-
- const uint32_t inotify_mask = IN_MOVED_TO | IN_CREATE | IN_MOVED_FROM | IN_DELETE | IN_MODIFY;
- char fullpath[DMON_MAX_PATH];
- dmon__strcpy(fullpath, sizeof(fullpath), watch->rootdir);
- dmon__strcat(fullpath, sizeof(fullpath), subdir.rootdir);
- int wd = inotify_add_watch(watch->fd, fullpath, inotify_mask);
- if (wd == -1) {
- _DMON_LOG_ERRORF("Error watching directory '%s'. (inotify_add_watch:err=%d)", watchdir, errno);
- if (!skip_lock)
- pthread_mutex_unlock(&_dmon.mutex);
- return false;
- }
-
- stb_sb_push(watch->subdirs, subdir);
- stb_sb_push(watch->wds, wd);
-
- if (!skip_lock)
- pthread_mutex_unlock(&_dmon.mutex);
-
- return true;
-}
-
-DMON_API_IMPL bool dmon_watch_rm(dmon_watch_id id, const char* watchdir)
-{
- DMON_ASSERT(id.id > 0 && id.id <= DMON_MAX_WATCHES);
-
- bool skip_lock = pthread_self() == _dmon.thread_handle;
-
- if (!skip_lock)
- pthread_mutex_lock(&_dmon.mutex);
-
- dmon__watch_state* watch = &_dmon.watches[id.id - 1];
-
- char subdir[DMON_MAX_PATH];
- dmon__strcpy(subdir, sizeof(subdir), watchdir);
- if (strstr(subdir, watch->rootdir) == subdir) {
- dmon__strcpy(subdir, sizeof(subdir), watchdir + strlen(watch->rootdir));
- }
-
- int dirlen = (int)strlen(subdir);
- if (subdir[dirlen - 1] != '/') {
- subdir[dirlen] = '/';
- subdir[dirlen + 1] = '\0';
- }
-
- int i, c = stb_sb_count(watch->subdirs);
- for (i = 0; i < c; i++) {
- if (strcmp(watch->subdirs[i].rootdir, subdir) == 0) {
- break;
- }
- }
- if (i >= c) {
- _DMON_LOG_ERRORF("Watch directory '%s' is not valid", watchdir);
- if (!skip_lock)
- pthread_mutex_unlock(&_dmon.mutex);
- return false;
- }
- inotify_rm_watch(watch->fd, watch->wds[i]);
-
- for (int j = i; j < c - 1; j++) {
- memcpy(watch->subdirs + j, watch->subdirs + j + 1, sizeof(dmon__watch_subdir));
- memcpy(watch->wds + j, watch->wds + j + 1, sizeof(int));
- }
- stb__sbraw(watch->subdirs)[1] = c - 1;
- stb__sbraw(watch->wds)[1] = c - 1;
-
- if (!skip_lock)
- pthread_mutex_unlock(&_dmon.mutex);
- return true;
-}
-
_DMON_PRIVATE const char* dmon__find_subdir(const dmon__watch_state* watch, int wd)
{
const int* wds = watch->wds;
diff --git a/src/dmon_extra.h b/src/dmon_extra.h
new file mode 100644
index 00000000..4b321034
--- /dev/null
+++ b/src/dmon_extra.h
@@ -0,0 +1,162 @@
+#ifndef __DMON_EXTRA_H__
+#define __DMON_EXTRA_H__
+
+//
+// Copyright 2021 Sepehr Taghdisian (septag@github). All rights reserved.
+// License: https://github.com/septag/dmon#license-bsd-2-clause
+//
+// Extra header functionality for dmon.h for the backend based on inotify
+//
+// Add/Remove directory functions:
+// dmon_watch_add: Adds a sub-directory to already valid watch_id. sub-directories are assumed to be relative to watch root_dir
+// dmon_watch_add: Removes a sub-directory from already valid watch_id. sub-directories are assumed to be relative to watch root_dir
+// Reason: The inotify backend does not work well when watching in recursive mode a root directory of a large tree, it may take
+// quite a while until all inotify watches are established, and events will not be received in this time. Also, since one
+// inotify watch will be established per subdirectory, it is possible that the maximum amount of inotify watches per user
+// will be reached. The default maximum is 8192.
+// When using inotify backend users may turn off the DMON_WATCHFLAGS_RECURSIVE flag and add/remove selectively the
+// sub-directories to be watched based on application-specific logic about which sub-directory actually needs to be watched.
+// The function dmon_watch_add and dmon_watch_rm are used to this purpose.
+//
+
+#ifndef __DMON_H__
+#error "Include 'dmon.h' before including this file"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+DMON_API_DECL bool dmon_watch_add(dmon_watch_id id, const char* subdir);
+DMON_API_DECL bool dmon_watch_rm(dmon_watch_id id, const char* watchdir);
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef DMON_IMPL
+#if DMON_OS_LINUX
+DMON_API_IMPL bool dmon_watch_add(dmon_watch_id id, const char* watchdir)
+{
+ DMON_ASSERT(id.id > 0 && id.id <= DMON_MAX_WATCHES);
+
+ bool skip_lock = pthread_self() == _dmon.thread_handle;
+
+ if (!skip_lock)
+ pthread_mutex_lock(&_dmon.mutex);
+
+ dmon__watch_state* watch = &_dmon.watches[id.id - 1];
+
+ // check if the directory exists
+ // if watchdir contains absolute/root-included path, try to strip the rootdir from it
+ // else, we assume that watchdir is correct, so save it as it is
+ struct stat st;
+ dmon__watch_subdir subdir;
+ if (stat(watchdir, &st) == 0 && (st.st_mode & S_IFDIR)) {
+ dmon__strcpy(subdir.rootdir, sizeof(subdir.rootdir), watchdir);
+ if (strstr(subdir.rootdir, watch->rootdir) == subdir.rootdir) {
+ dmon__strcpy(subdir.rootdir, sizeof(subdir.rootdir), watchdir + strlen(watch->rootdir));
+ }
+ } else {
+ char fullpath[DMON_MAX_PATH];
+ dmon__strcpy(fullpath, sizeof(fullpath), watch->rootdir);
+ dmon__strcat(fullpath, sizeof(fullpath), watchdir);
+ if (stat(fullpath, &st) != 0 || (st.st_mode & S_IFDIR) == 0) {
+ _DMON_LOG_ERRORF("Watch directory '%s' is not valid", watchdir);
+ if (!skip_lock)
+ pthread_mutex_unlock(&_dmon.mutex);
+ return false;
+ }
+ dmon__strcpy(subdir.rootdir, sizeof(subdir.rootdir), watchdir);
+ }
+
+ int dirlen = (int)strlen(subdir.rootdir);
+ if (subdir.rootdir[dirlen - 1] != '/') {
+ subdir.rootdir[dirlen] = '/';
+ subdir.rootdir[dirlen + 1] = '\0';
+ }
+
+ // check that the directory is not already added
+ for (int i = 0, c = stb_sb_count(watch->subdirs); i < c; i++) {
+ if (strcmp(subdir.rootdir, watch->subdirs[i].rootdir) == 0) {
+ _DMON_LOG_ERRORF("Error watching directory '%s', because it is already added.", watchdir);
+ if (!skip_lock)
+ pthread_mutex_unlock(&_dmon.mutex);
+ return false;
+ }
+ }
+
+ const uint32_t inotify_mask = IN_MOVED_TO | IN_CREATE | IN_MOVED_FROM | IN_DELETE | IN_MODIFY;
+ char fullpath[DMON_MAX_PATH];
+ dmon__strcpy(fullpath, sizeof(fullpath), watch->rootdir);
+ dmon__strcat(fullpath, sizeof(fullpath), subdir.rootdir);
+ int wd = inotify_add_watch(watch->fd, fullpath, inotify_mask);
+ if (wd == -1) {
+ _DMON_LOG_ERRORF("Error watching directory '%s'. (inotify_add_watch:err=%d)", watchdir, errno);
+ if (!skip_lock)
+ pthread_mutex_unlock(&_dmon.mutex);
+ return false;
+ }
+
+ stb_sb_push(watch->subdirs, subdir);
+ stb_sb_push(watch->wds, wd);
+
+ if (!skip_lock)
+ pthread_mutex_unlock(&_dmon.mutex);
+
+ return true;
+}
+
+DMON_API_IMPL bool dmon_watch_rm(dmon_watch_id id, const char* watchdir)
+{
+ DMON_ASSERT(id.id > 0 && id.id <= DMON_MAX_WATCHES);
+
+ bool skip_lock = pthread_self() == _dmon.thread_handle;
+
+ if (!skip_lock)
+ pthread_mutex_lock(&_dmon.mutex);
+
+ dmon__watch_state* watch = &_dmon.watches[id.id - 1];
+
+ char subdir[DMON_MAX_PATH];
+ dmon__strcpy(subdir, sizeof(subdir), watchdir);
+ if (strstr(subdir, watch->rootdir) == subdir) {
+ dmon__strcpy(subdir, sizeof(subdir), watchdir + strlen(watch->rootdir));
+ }
+
+ int dirlen = (int)strlen(subdir);
+ if (subdir[dirlen - 1] != '/') {
+ subdir[dirlen] = '/';
+ subdir[dirlen + 1] = '\0';
+ }
+
+ int i, c = stb_sb_count(watch->subdirs);
+ for (i = 0; i < c; i++) {
+ if (strcmp(watch->subdirs[i].rootdir, subdir) == 0) {
+ break;
+ }
+ }
+ if (i >= c) {
+ _DMON_LOG_ERRORF("Watch directory '%s' is not valid", watchdir);
+ if (!skip_lock)
+ pthread_mutex_unlock(&_dmon.mutex);
+ return false;
+ }
+ inotify_rm_watch(watch->fd, watch->wds[i]);
+
+ /* Remove entry from subdirs and wds by swapping position with the last entry */
+ watch->subdirs[i] = stb_sb_last(watch->subdirs);
+ stb_sb_pop(watch->subdirs);
+
+ watch->wds[i] = stb_sb_last(watch->wds);
+ stb_sb_pop(watch->wds);
+
+ if (!skip_lock)
+ pthread_mutex_unlock(&_dmon.mutex);
+ return true;
+}
+#endif // DMON_OS_LINUX
+#endif // DMON_IMPL
+
+#endif // __DMON_EXTRA_H__
+