From ff86d54ff556161175a94989e69462df9a3ba762 Mon Sep 17 00:00:00 2001 From: Francesco Abbate Date: Sun, 26 Sep 2021 22:37:57 +0200 Subject: [PATCH] Move to dmon.h new version to test By doing so we removed the addition of dmon_watch_rm and the Lua code will no longer compile. --- src/dmon.h | 104 ++++++++++++----------------------------------------- 1 file changed, 22 insertions(+), 82 deletions(-) diff --git a/src/dmon.h b/src/dmon.h index c4c5ca99..6a39523f 100644 --- a/src/dmon.h +++ b/src/dmon.h @@ -5,7 +5,6 @@ // Portable directory monitoring library // watches directories for file or directory changes. // -// clang-format off // Usage: // define DMON_IMPL and include this file to use it: // #define DMON_IMPL @@ -116,7 +115,6 @@ DMON_API_DECL dmon_watch_id dmon_watch(const char* rootdir, 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* subdir); #ifdef __cplusplus } @@ -396,8 +394,6 @@ typedef struct dmon__state { static bool _dmon_init; static dmon__state _dmon; -// clang-format on - _DMON_PRIVATE bool dmon__refresh_watch(dmon__watch_state* watch) { return ReadDirectoryChangesW(watch->dir_handle, watch->buffer, sizeof(watch->buffer), @@ -703,7 +699,6 @@ typedef struct dmon__state { dmon__watch_state watches[DMON_MAX_WATCHES]; dmon__inotify_event* events; int num_watches; - volatile int modify_watches; pthread_t thread_handle; pthread_mutex_t mutex; bool quit; @@ -771,7 +766,11 @@ DMON_API_IMPL bool dmon_watch_add(dmon_watch_id id, const char* watchdir) { DMON_ASSERT(id.id > 0 && id.id <= DMON_MAX_WATCHES); - pthread_mutex_lock(&_dmon.mutex); + 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 @@ -790,7 +789,8 @@ DMON_API_IMPL bool dmon_watch_add(dmon_watch_id id, const char* watchdir) 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); - pthread_mutex_unlock(&_dmon.mutex); + if (!skip_lock) + pthread_mutex_unlock(&_dmon.mutex); return false; } dmon__strcpy(subdir.rootdir, sizeof(subdir.rootdir), watchdir); @@ -802,71 +802,34 @@ DMON_API_IMPL bool dmon_watch_add(dmon_watch_id id, const char* watchdir) 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); - pthread_mutex_unlock(&_dmon.mutex); + if (!skip_lock) + pthread_mutex_unlock(&_dmon.mutex); return false; } stb_sb_push(watch->subdirs, subdir); stb_sb_push(watch->wds, wd); - 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); - - 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++) { - fprintf(stderr, "compare >%s< >%s<\n", watch->subdirs[i].rootdir, subdir); - 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]); -#if 0 - /* FIXME: in theory we should remove the entry but if done we can get a - ** fail in the dmon__thread when looking up for the subdir with - ** dmon__find_subdir */ - 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; -#endif - - pthread_mutex_unlock(&_dmon.mutex); return true; } @@ -1088,15 +1051,8 @@ static void* dmon__thread(void* arg) gettimeofday(&starttm, 0); while (!_dmon.quit) { - - if (_dmon.modify_watches || pthread_mutex_trylock(&_dmon.mutex) != 0) { - nanosleep(&req, &rem); - continue; - } - - if (_dmon.num_watches == 0) { - nanosleep(&req, &rem); - pthread_mutex_unlock(&_dmon.mutex); + nanosleep(&req, &rem); + if (_dmon.num_watches == 0 || pthread_mutex_trylock(&_dmon.mutex) != 0) { continue; } @@ -1110,11 +1066,7 @@ static void* dmon__thread(void* arg) timeout.tv_sec = 0; timeout.tv_usec = 100000; - /* FIXME: the unlock/lock around select are a temporary solution to avoid - ** a deadlock with dmon_watch_add. */ - pthread_mutex_unlock(&_dmon.mutex); if (select(FD_SETSIZE, &rfds, NULL, NULL, &timeout)) { - pthread_mutex_lock(&_dmon.mutex); for (int i = 0; i < _dmon.num_watches; i++) { dmon__watch_state* watch = &_dmon.watches[i]; if (FD_ISSET(watch->fd, &rfds)) { @@ -1204,7 +1156,6 @@ DMON_API_IMPL dmon_watch_id dmon_watch(const char* rootdir, DMON_ASSERT(watch_cb); DMON_ASSERT(rootdir && rootdir[0]); - __sync_lock_test_and_set(&_dmon.modify_watches, 1); pthread_mutex_lock(&_dmon.mutex); DMON_ASSERT(_dmon.num_watches < DMON_MAX_WATCHES); @@ -1221,7 +1172,6 @@ DMON_API_IMPL dmon_watch_id dmon_watch(const char* rootdir, (root_st.st_mode & S_IRUSR) != S_IRUSR) { _DMON_LOG_ERRORF("Could not open/read directory: %s", rootdir); pthread_mutex_unlock(&_dmon.mutex); - __sync_lock_test_and_set(&_dmon.modify_watches, 0); return dmon__make_id(0); } @@ -1238,7 +1188,6 @@ DMON_API_IMPL dmon_watch_id dmon_watch(const char* rootdir, _DMON_LOG_ERRORF("symlinks are unsupported: %s. use DMON_WATCHFLAGS_FOLLOW_SYMLINKS", rootdir); pthread_mutex_unlock(&_dmon.mutex); - __sync_lock_test_and_set(&_dmon.modify_watches, 0); return dmon__make_id(0); } } else { @@ -1256,7 +1205,6 @@ DMON_API_IMPL dmon_watch_id dmon_watch(const char* rootdir, if (watch->fd < -1) { DMON_LOG_ERROR("could not create inotify instance"); pthread_mutex_unlock(&_dmon.mutex); - __sync_lock_test_and_set(&_dmon.modify_watches, 0); return dmon__make_id(0); } @@ -1265,7 +1213,6 @@ DMON_API_IMPL dmon_watch_id dmon_watch(const char* rootdir, if (wd < 0) { _DMON_LOG_ERRORF("Error watching directory '%s'. (inotify_add_watch:err=%d)", watch->rootdir, errno); pthread_mutex_unlock(&_dmon.mutex); - __sync_lock_test_and_set(&_dmon.modify_watches, 0); return dmon__make_id(0); } dmon__watch_subdir subdir; @@ -1281,7 +1228,6 @@ DMON_API_IMPL dmon_watch_id dmon_watch(const char* rootdir, pthread_mutex_unlock(&_dmon.mutex); - __sync_lock_test_and_set(&_dmon.modify_watches, 0); return dmon__make_id(id); } @@ -1289,7 +1235,6 @@ DMON_API_IMPL void dmon_unwatch(dmon_watch_id id) { DMON_ASSERT(id.id > 0); - __sync_lock_test_and_set(&_dmon.modify_watches, 1); pthread_mutex_lock(&_dmon.mutex); int index = id.id - 1; @@ -1302,9 +1247,7 @@ DMON_API_IMPL void dmon_unwatch(dmon_watch_id id) --_dmon.num_watches; pthread_mutex_unlock(&_dmon.mutex); - __sync_lock_test_and_set(&_dmon.modify_watches, 0); } -// clang-format off #elif DMON_OS_MACOS // FSEvents MacOS backend typedef struct dmon__fsevent_event { @@ -1346,7 +1289,6 @@ union dmon__cast_userdata { static bool _dmon_init; static dmon__state _dmon; -// clang-format on _DMON_PRIVATE void* dmon__cf_malloc(CFIndex size, CFOptionFlags hints, void* info) { @@ -1695,9 +1637,7 @@ DMON_API_IMPL void dmon_unwatch(dmon_watch_id id) __sync_lock_test_and_set(&_dmon.modify_watches, 0); } -// clang-format off #endif #endif // DMON_IMPL #endif // __DMON_H__ -// clang-format on