git ssb

0+

cel / foostudio



Tree: 1b5aafc84d39bf3a1c4dbe87e27f6d4938aae848

Files: 1b5aafc84d39bf3a1c4dbe87e27f6d4938aae848 / ccdl.c

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

Built with git-ssb-web