git ssb

0+

cel / foostudio



Tree: 7603bddceeba3b2835ae0944abac262064c76801

Files: 7603bddceeba3b2835ae0944abac262064c76801 / ccdl.c

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

Built with git-ssb-web