git ssb

0+

cel / foostudio



Tree: b5ebb2a607ac9ea92f525350e5b18580d0e71888

Files: b5ebb2a607ac9ea92f525350e5b18580d0e71888 / ccdl.c

4308 bytesRaw
1#include <stddef.h>
2#include <unistd.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <err.h>
6#include <sys/wait.h>
7#include <sys/inotify.h>
8#include <dlfcn.h>
9#include <pthread.h>
10
11#include "ccdl.h"
12
13static unsigned int tmp_i = 0;
14
15static const char *mktemp()
16{
17 const char *tmpdir = getenv("TMPDIR");
18 if (!tmpdir) tmpdir = "/tmp";
19 static char buf[256];
20 if (snprintf(buf, sizeof(buf), "%s/ccdl-%d-%i.so",
21 tmpdir, getpid(), tmp_i++) < 0) return NULL;
22 return buf;
23}
24
25void lib_init(struct lib *lib, const char *src_fname, const char *sym_name)
26{
27 lib->src_fname = src_fname;
28 lib->lib_fname = NULL;
29 lib->sym_name = sym_name;
30 lib->handle = NULL;
31 lib->sym = NULL;
32}
33
34static int compile(const char *src, const char *lib)
35{
36 if (!src || !lib) return -1;
37 int child = fork();
38 if (child < 0) return -1;
39 if (child == 0) {
40 char *const argv[] = {
41 "cc", (char *)src, "-o", (char *)lib,
42 "-fPIC", "-shared", "-lm",
43 NULL};
44 return execvp(argv[0], argv);
45 } else {
46 int wstatus;
47 if (waitpid(child, &wstatus, 0) < 0) {
48 return -1;
49 } else if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0) {
50 return 0;
51 } else {
52 return -1;
53 }
54 }
55}
56
57int lib_build(struct lib *lib)
58{
59 void *handle = lib->handle;
60 if (!handle) {
61 const char *lib_fname = lib->lib_fname;
62 if (!lib_fname) {
63 const char *src_fname = lib->src_fname;
64 if (!src_fname) return -1;
65 lib_fname = mktemp();
66 if (!lib_fname) return -1;
67 lib->lib_fname = lib_fname;
68 if (compile(src_fname, lib_fname)) return -1;
69 }
70 handle = dlopen(lib_fname, RTLD_NOW);
71 lib->handle = handle;
72 }
73 const char *sym_name = lib->sym_name;
74 if (!sym_name) return -1;
75 void *sym = dlsym(handle, sym_name);
76 if (!sym) return -1;
77 lib->sym = sym;
78 return 0;
79}
80
81void *lib_get(struct lib *lib)
82{
83 if (!lib->sym) lib_build(lib);
84 return lib->sym;
85}
86
87void lib_deinit(struct lib *lib)
88{
89 if (lib->handle) {
90 dlclose(lib->handle);
91 lib->handle = NULL;
92 lib->sym = NULL;
93 }
94 if (lib->lib_fname) {
95 unlink(lib->lib_fname);
96 lib->lib_fname = NULL;
97 }
98}
99
100void ccdl_init(struct ccdl *ccdl, const char *src_fname, const char *sym_name)
101{
102 lib_init(&ccdl->libs[0], src_fname, sym_name);
103 lib_init(&ccdl->libs[1], src_fname, sym_name);
104 ccdl->lib = &ccdl->libs[0];
105}
106
107static struct lib *ccdl_get_old_lib(struct ccdl *ccdl)
108{
109 return ccdl->lib == &ccdl->libs[1] ? &ccdl->libs[0] : &ccdl->libs[1];
110}
111
112void *ccdl_get(struct ccdl *ccdl)
113{
114 struct lib *old_lib = ccdl_get_old_lib(ccdl);
115 if (old_lib) {
116 lib_deinit(old_lib);
117 }
118 return lib_get(ccdl->lib);
119}
120
121static int ccdl_watch_run(struct ccdl *ccdl)
122{
123 int ifd = inotify_init();
124 int wd = 0;
125 if (ifd < 0) {
126 warn("inotify_init");
127 return -1;
128 }
129 if (!ccdl || !ccdl->lib || !ccdl->lib->src_fname) {
130 warn("missing lib filename");
131 return -1;
132 }
133 wd = inotify_add_watch(ifd, ccdl->lib->src_fname, IN_MODIFY);
134 if (wd < 0) {
135 warn("watch");
136 return -1;
137 }
138
139 while (1) {
140 struct inotify_event ev;
141 ssize_t len = read(ifd, &ev, sizeof ev);
142 //printf("readed %zd %u %u %u\n", len, sizeof ev, ev.len, ev.mask);
143 if (len < 0) {
144 warn("read");
145 return -1;
146 }
147 if (len < sizeof ev) {
148 warn("small read");
149 continue;
150 }
151 if (ev.len > 0) {
152 warn("unexpected name");
153 return -1;
154 }
155 if (ev.mask & IN_MODIFY) {
156 } else if (ev.mask & IN_DELETE_SELF) {
157 printf("deleted\n");
158 } else if (ev.mask & IN_IGNORED) {
159 printf("ignored\n");
160 // file is being replaced. replace the watch
161 wd = inotify_add_watch(ifd, ccdl->lib->src_fname, IN_MODIFY);
162 if (wd < 0) {
163 warn("inotify_add_watch");
164 return -1;
165 }
166 } else {
167 printf("unknown mask: %u\n", ev.mask);
168 }
169 (void)ccdl_rebuild(ccdl);
170 }
171
172 return 0;
173}
174
175static void *ccdl_watch_run_thread(void *ccdl)
176{
177 return (void *)ccdl_watch_run(ccdl);
178}
179
180int ccdl_watch(struct ccdl *ccdl)
181{
182 pthread_t *id = &ccdl->watcher_thread;
183 if (pthread_create(id, NULL, ccdl_watch_run_thread, ccdl)) return -1;
184 return 0;
185}
186
187int ccdl_rebuild(struct ccdl *ccdl)
188{
189 struct lib *old_lib, *new_lib;
190 old_lib = ccdl->lib;
191 new_lib = ccdl_get_old_lib(ccdl);
192 lib_deinit(new_lib);
193 if (lib_build(new_lib) < 0) return -1;
194 ccdl->lib = new_lib;
195 return 0;
196}
197
198int ccdl_deinit(struct ccdl *ccdl)
199{
200 pthread_t thread = ccdl->watcher_thread;
201 if (thread) {
202 void *retval;
203 pthread_join(thread, &retval);
204 return (int)retval;
205 }
206 return 0;
207}
208
209

Built with git-ssb-web