Skip to content

Commit 32477c8

Browse files
committed
apple: darwin frontend driver path change watcher
1 parent 9685cd3 commit 32477c8

1 file changed

Lines changed: 171 additions & 2 deletions

File tree

frontend/drivers/platform_darwin.m

Lines changed: 171 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@
1919
#include <stddef.h>
2020
#include <string.h>
2121
#include <unistd.h>
22+
#include <fcntl.h>
2223

2324
#include <sys/utsname.h>
2425

2526
#include <mach/mach.h>
27+
#include <dispatch/dispatch.h>
2628

2729
#include <CoreFoundation/CoreFoundation.h>
2830
#include <CoreFoundation/CFArray.h>
@@ -125,6 +127,23 @@
125127

126128
static char darwin_cpu_model_name[64] = {0};
127129

130+
/* Directory watching implementation using GCD dispatch sources */
131+
typedef struct darwin_watch_entry
132+
{
133+
int fd; /* File descriptor opened with O_EVTONLY */
134+
dispatch_source_t source; /* GCD dispatch source for monitoring */
135+
char *path; /* Watched file path */
136+
} darwin_watch_entry_t;
137+
138+
typedef struct darwin_watch_data
139+
{
140+
dispatch_queue_t queue; /* Dispatch queue for event handlers */
141+
darwin_watch_entry_t *watches; /* Array of watch entries */
142+
size_t watch_count; /* Number of active watches */
143+
volatile int32_t has_changes; /* Atomic flag indicating changes occurred */
144+
int flags; /* Event flags to monitor */
145+
} darwin_watch_data_t;
146+
128147
static void CFSearchPathForDirectoriesInDomains(
129148
char *s, size_t len)
130149
{
@@ -932,6 +951,156 @@ static bool accessibility_speak_macos(int speed,
932951

933952
#endif
934953

954+
static void frontend_darwin_watch_path_for_changes(
955+
struct string_list *list, int flags,
956+
path_change_data_t **change_data)
957+
{
958+
darwin_watch_data_t *watch_data = NULL;
959+
960+
/* Cleanup mode - free existing watch data */
961+
if (!list)
962+
{
963+
if (!change_data || !*change_data)
964+
return;
965+
966+
watch_data = (darwin_watch_data_t*)((*change_data)->data);
967+
if (watch_data)
968+
{
969+
size_t i;
970+
/* Cancel and release all dispatch sources, close file descriptors */
971+
for (i = 0; i < watch_data->watch_count; i++)
972+
{
973+
if (watch_data->watches[i].source)
974+
{
975+
dispatch_source_cancel(watch_data->watches[i].source);
976+
#if !__has_feature(objc_arc)
977+
dispatch_release(watch_data->watches[i].source);
978+
#endif
979+
}
980+
if (watch_data->watches[i].fd >= 0)
981+
close(watch_data->watches[i].fd);
982+
if (watch_data->watches[i].path)
983+
free(watch_data->watches[i].path);
984+
}
985+
#if !__has_feature(objc_arc)
986+
if (watch_data->queue)
987+
dispatch_release(watch_data->queue);
988+
#endif
989+
if (watch_data->watches)
990+
free(watch_data->watches);
991+
free(watch_data);
992+
}
993+
free(*change_data);
994+
*change_data = NULL;
995+
return;
996+
}
997+
998+
/* Setup mode - create new watch data */
999+
watch_data = (darwin_watch_data_t*)calloc(1, sizeof(*watch_data));
1000+
if (!watch_data)
1001+
return;
1002+
1003+
watch_data->queue = dispatch_get_global_queue(
1004+
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
1005+
watch_data->watch_count = list->size;
1006+
watch_data->watches = (darwin_watch_entry_t*)calloc(
1007+
list->size, sizeof(darwin_watch_entry_t));
1008+
watch_data->flags = flags;
1009+
watch_data->has_changes = 0;
1010+
1011+
if (!watch_data->watches)
1012+
{
1013+
free(watch_data);
1014+
return;
1015+
}
1016+
1017+
/* Convert generic flags to GCD dispatch VNODE flags */
1018+
{
1019+
unsigned long vnode_flags = 0;
1020+
size_t i;
1021+
1022+
if (flags & PATH_CHANGE_TYPE_MODIFIED)
1023+
vnode_flags |= DISPATCH_VNODE_WRITE;
1024+
if (flags & PATH_CHANGE_TYPE_WRITE_FILE_CLOSED)
1025+
vnode_flags |= DISPATCH_VNODE_ATTRIB; /* mtime changes on close */
1026+
if (flags & PATH_CHANGE_TYPE_FILE_MOVED)
1027+
vnode_flags |= DISPATCH_VNODE_RENAME;
1028+
if (flags & PATH_CHANGE_TYPE_FILE_DELETED)
1029+
vnode_flags |= DISPATCH_VNODE_DELETE;
1030+
1031+
/* Set up watch for each file in the list */
1032+
for (i = 0; i < list->size; i++)
1033+
{
1034+
const char *path = list->elems[i].data;
1035+
int fd = open(path, O_EVTONLY);
1036+
1037+
watch_data->watches[i].fd = fd;
1038+
watch_data->watches[i].source = NULL;
1039+
watch_data->watches[i].path = NULL;
1040+
1041+
if (fd >= 0)
1042+
{
1043+
dispatch_source_t source;
1044+
1045+
watch_data->watches[i].path = strdup(path);
1046+
1047+
/* Create dispatch source for monitoring file events */
1048+
source = dispatch_source_create(
1049+
DISPATCH_SOURCE_TYPE_VNODE,
1050+
fd,
1051+
vnode_flags,
1052+
watch_data->queue);
1053+
1054+
if (source)
1055+
{
1056+
/* Set up event handler - sets atomic flag when changes occur */
1057+
dispatch_source_set_event_handler(source, ^{
1058+
OSAtomicCompareAndSwap32(0, 1, &watch_data->has_changes);
1059+
});
1060+
1061+
/* Set up cancellation handler to prevent fd leak */
1062+
dispatch_source_set_cancel_handler(source, ^{
1063+
/* File descriptor is closed in cleanup function */
1064+
});
1065+
1066+
watch_data->watches[i].source = source;
1067+
dispatch_resume(source);
1068+
}
1069+
else
1070+
{
1071+
/* Failed to create dispatch source, close fd */
1072+
close(fd);
1073+
watch_data->watches[i].fd = -1;
1074+
}
1075+
}
1076+
}
1077+
}
1078+
1079+
/* Allocate and return change_data structure */
1080+
*change_data = (path_change_data_t*)calloc(1, sizeof(path_change_data_t));
1081+
if (*change_data)
1082+
(*change_data)->data = watch_data;
1083+
else
1084+
{
1085+
/* Failed to allocate change_data, cleanup */
1086+
frontend_darwin_watch_path_for_changes(NULL, 0, &(path_change_data_t*){watch_data});
1087+
}
1088+
}
1089+
1090+
static bool frontend_darwin_check_for_path_changes(
1091+
path_change_data_t *change_data)
1092+
{
1093+
darwin_watch_data_t *watch_data = NULL;
1094+
1095+
if (!change_data || !change_data->data)
1096+
return false;
1097+
1098+
watch_data = (darwin_watch_data_t*)(change_data->data);
1099+
1100+
/* Atomically read and clear the flag */
1101+
return OSAtomicCompareAndSwap32(1, 0, &watch_data->has_changes);
1102+
}
1103+
9351104
static bool frontend_darwin_is_narrator_running(void)
9361105
{
9371106
if (@available(macOS 10.14, iOS 7, tvOS 9, *))
@@ -1018,8 +1187,8 @@ static void frontend_darwin_content_loaded(void)
10181187
NULL, /* detach_console */
10191188
NULL, /* get_lakka_version */
10201189
NULL, /* set_screen_brightness */
1021-
NULL, /* watch_path_for_changes */
1022-
NULL, /* check_for_path_changes */
1190+
frontend_darwin_watch_path_for_changes, /* watch_path_for_changes */
1191+
frontend_darwin_check_for_path_changes, /* check_for_path_changes */
10231192
NULL, /* set_sustained_performance_mode */
10241193
frontend_darwin_get_cpu_model_name, /* get_cpu_model_name */
10251194
frontend_darwin_get_user_language, /* get_user_language */

0 commit comments

Comments
 (0)