git ssb

0+

cel / foostudio



Tree: 2afb25b2316215a66cf266f58b979bd0ce84e04a

Files: 2afb25b2316215a66cf266f58b979bd0ce84e04a / ccdl.c

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

Built with git-ssb-web