git ssb

0+

cel / foostudio



Tree: bb4c57ab9509dfe407fa6359c04c79270e64bd18

Files: bb4c57ab9509dfe407fa6359c04c79270e64bd18 / ccdl.c

4663 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) return -1;
58 if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus)) return -1;
59 return 0;
60 }
61}
62
63static int lib_build(struct lib *lib)
64{
65 void *handle = lib->handle;
66 if (!handle) {
67 const char *src_fname = lib->src_fname;
68 if (!src_fname) return -1;
69 const char *lib_fname = my_mktemp();
70 if (!lib_fname) {
71 warn("mktemp");
72 return -1;
73 }
74 if (compile(src_fname, lib_fname)) return -1;
75 dlerror();
76 handle = dlopen(lib_fname, RTLD_NOW);
77 char *err = dlerror();
78 if (unlink(lib_fname) < 0) warn("unlink");
79 if (err) {
80 warnx("dlopen: %s", err);
81 return -1;
82 }
83 lib->handle = handle;
84 }
85 const char *sym_name = lib->sym_name;
86 if (!sym_name) return -1;
87 void *sym = dlsym(handle, sym_name);
88 if (!sym) return -1;
89 lib->sym = sym;
90 printf("built\n");
91 return 0;
92}
93
94static void *lib_get(struct lib *lib)
95{
96 if (!lib->sym) lib_build(lib);
97 return lib->sym;
98}
99
100static void lib_deinit(struct lib *lib)
101{
102 if (lib->handle) {
103 dlclose(lib->handle);
104 lib->handle = NULL;
105 lib->sym = NULL;
106 }
107}
108
109void ccdl_init(struct ccdl *ccdl, const char *src_fname, const char *sym_name)
110{
111 lib_init(&ccdl->libs[0], src_fname, sym_name);
112 lib_init(&ccdl->libs[1], src_fname, sym_name);
113 ccdl->lib = &ccdl->libs[0];
114}
115
116static struct lib *ccdl_get_old_lib(struct ccdl *ccdl)
117{
118 return ccdl->lib == &ccdl->libs[1] ? &ccdl->libs[0] : &ccdl->libs[1];
119}
120
121void *ccdl_get(struct ccdl *ccdl)
122{
123 struct lib *old_lib = ccdl_get_old_lib(ccdl);
124 if (old_lib) {
125 lib_deinit(old_lib);
126 }
127 return lib_get(ccdl->lib);
128}
129
130static int ccdl_watch_run(struct ccdl *ccdl)
131{
132 int ifd = inotify_init();
133 int wd = 0;
134 if (ifd < 0) {
135 warn("inotify_init");
136 return -1;
137 }
138 if (!ccdl || !ccdl->lib || !ccdl->lib->src_fname) {
139 warn("missing lib filename");
140 return -1;
141 }
142 wd = inotify_add_watch(ifd, ccdl->lib->src_fname, IN_MODIFY);
143 if (wd < 0) {
144 warn("watch");
145 return -1;
146 }
147
148 while (1) {
149 struct inotify_event ev;
150 ssize_t len = read(ifd, &ev, sizeof ev);
151 //printf("readed %zd %u %u %u\n", len, sizeof ev, ev.len, ev.mask);
152 if (len < 0) {
153 warn("read");
154 return -1;
155 }
156 if ((size_t)len < sizeof ev) {
157 warn("small read");
158 continue;
159 }
160 if (ev.len > 0) {
161 warn("unexpected name");
162 return -1;
163 }
164 if (ev.mask & IN_MODIFY) {
165 } else if (ev.mask & IN_DELETE_SELF) {
166 printf("deleted\n");
167 } else if (ev.mask & IN_IGNORED) {
168 // file is being replaced. replace the watch
169 wd = inotify_add_watch(ifd, ccdl->lib->src_fname, IN_MODIFY);
170 if (wd < 0) {
171 warn("inotify_add_watch");
172 return -1;
173 }
174 } else {
175 printf("unknown mask: %u\n", ev.mask);
176 }
177 (void)ccdl_rebuild(ccdl);
178 }
179
180 return 0;
181}
182
183static void *ccdl_watch_run_thread(void *ccdl)
184{
185 return (void *)(intptr_t)ccdl_watch_run(ccdl);
186}
187
188int ccdl_watch(struct ccdl *ccdl)
189{
190 pthread_t *id = &ccdl->watcher_thread;
191 if (pthread_create(id, NULL, ccdl_watch_run_thread, ccdl)) return -1;
192 return 0;
193}
194
195static int ccdl_rebuild(struct ccdl *ccdl)
196{
197 struct lib *new_lib = ccdl_get_old_lib(ccdl);
198 lib_deinit(new_lib);
199 if (lib_build(new_lib) < 0) return -1;
200 ccdl->lib = new_lib;
201 return 0;
202}
203
204int ccdl_deinit(struct ccdl *ccdl)
205{
206 pthread_t thread = ccdl->watcher_thread;
207 if (thread) {
208 void *retval;
209 pthread_join(thread, &retval);
210 return (intptr_t)retval;
211 }
212 return 0;
213}
214
215

Built with git-ssb-web