git ssb

0+

cel / foostudio



Tree: fd156cd03b6fce3c933ce1edb725e8e6e74e7be4

Files: fd156cd03b6fce3c933ce1edb725e8e6e74e7be4 / ccdl.c

3996 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", "-std=c99",
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 if (ifd < 0) {
125 warn("inotify_init");
126 return -1;
127 }
128 if (!ccdl || !ccdl->lib || !ccdl->lib->src_fname) {
129 warn("missing lib filename");
130 return -1;
131 }
132 if (inotify_add_watch(ifd, ccdl->lib->src_fname, IN_MODIFY) < 0) {
133 warn("watch");
134 return -1;
135 }
136
137 while (1) {
138 struct inotify_event ev;
139 ssize_t len = read(ifd, &ev, sizeof ev);
140 //printf("readed %zd %u %u %u\n", len, sizeof ev, ev.len, ev.mask);
141 if (len < 0) {
142 warn("read");
143 return -1;
144 }
145 if (len < sizeof ev) {
146 warn("small read");
147 continue;
148 }
149 if (ev.len > 0) {
150 warn("unexpected name");
151 return -1;
152 }
153 if (!(ev.mask & IN_MODIFY)) {
154 printf("unknown mask: %u\n", ev.mask);
155 continue;
156 }
157
158 (void)ccdl_rebuild(ccdl);
159 }
160
161 return 0;
162}
163
164static void *ccdl_watch_run_thread(void *ccdl)
165{
166 return (void *)ccdl_watch_run(ccdl);
167}
168
169int ccdl_watch(struct ccdl *ccdl)
170{
171 pthread_t *id = &ccdl->watcher_thread;
172 if (pthread_create(id, NULL, ccdl_watch_run_thread, ccdl)) return -1;
173 return 0;
174}
175
176int ccdl_rebuild(struct ccdl *ccdl)
177{
178 struct lib *old_lib, *new_lib;
179 old_lib = ccdl->lib;
180 new_lib = ccdl_get_old_lib(ccdl);
181 lib_deinit(new_lib);
182 if (lib_build(new_lib) < 0) return -1;
183 ccdl->lib = new_lib;
184 return 0;
185}
186
187int ccdl_deinit(struct ccdl *ccdl)
188{
189 pthread_t thread = ccdl->watcher_thread;
190 if (thread) {
191 void *retval;
192 pthread_join(thread, &retval);
193 return (int)retval;
194 }
195 return 0;
196}
197
198

Built with git-ssb-web