Commit fd156cd03b6fce3c933ce1edb725e8e6e74e7be4
Live reload without delay
cel committed on 10/24/2016, 9:09:53 PMParent: 4be6db6a6163e3a0ccd85e7e193f54406c80a29a
Files changed
Makefile | changed |
studio.c | changed |
tune.c | changed |
tune.h | changed |
ccdl.c | added |
ccdl.h | added |
Makefile | ||
---|---|---|
@@ -1,16 +1,8 @@ | ||
1 | 1 … | CFLAGS = -std=c99 |
2 | -LIB_CFLAGS = -fPIC | |
3 | -LDLIBS = -ldl -lasound -lm | |
4 | -LIB_LDLIBS = -lm | |
2 … | +LDLIBS = -ldl -lasound -lm -lpthread | |
5 | 3 … | |
6 | -all: studio tune.so | |
4 … | +studio: studio.o ccdl.o | |
7 | 5 … | |
8 | -studio: studio.c tune.h | |
9 | - $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LDLIBS) | |
10 | - | |
11 | -tune.so : tune.c tune.h | |
12 | - $(CC) $(LIB_CFLAGS) -shared $(LDFLAGS) -o $@ $< $(LIB_LDLIBS) | |
13 | - | |
14 | 6 … | clean: |
15 | 7 … | $(RM) *.o *.so studio |
16 | 8 … |
studio.c | ||
---|---|---|
@@ -8,55 +8,15 @@ | ||
8 | 8 … | |
9 | 9 … | |
10 | 10 … | |
11 | 11 … | |
12 … | + | |
12 | 13 … | |
13 | -struct tune_dl { | |
14 | - void *handle; | |
15 | - ino_t inode; | |
16 | - struct tune *tune; | |
17 | -}; | |
18 | - | |
19 | 14 … | static unsigned int rate = 44100; |
20 | 15 … | static unsigned int channels = 1; |
21 | 16 … | static unsigned int latency = 500000; /* ring buffer length in us */ |
22 | 17 … | static snd_pcm_format_t format = SND_PCM_FORMAT_FLOAT; |
23 | -static const char *dl_fname = "./tune.so"; | |
24 | 18 … | |
25 | -static int tune_dl_load(struct tune_dl *dl, const char *libfname) | |
26 | -{ | |
27 | - struct stat st; | |
28 | - if (stat(libfname, &st) < 0) { | |
29 | - warn("stat"); | |
30 | - return -1; | |
31 | - } | |
32 | - if (dl->inode == st.st_ino) { | |
33 | - // file unchanged | |
34 | - return 0; | |
35 | - } | |
36 | - // reload the library | |
37 | - if (dl->handle) { | |
38 | - dlclose(dl->handle); | |
39 | - dl->inode = 0; | |
40 | - } | |
41 | - dl->handle = dlopen(libfname, RTLD_NOW); | |
42 | - if (dl->handle == NULL) { | |
43 | - // warnx("dlopen: %s", dlerror()); | |
44 | - return 0; | |
45 | - } | |
46 | - dl->tune = dlsym(dl->handle, "TUNE"); | |
47 | - if (dl->tune == NULL) { | |
48 | - warn("dlsym"); | |
49 | - dlclose(dl->handle); | |
50 | - return 0; | |
51 | - } | |
52 | - dl->inode = st.st_ino; | |
53 | - if (dl->tune->reload) { | |
54 | - dl->tune->reload(dl->tune); | |
55 | - } | |
56 | - return 0; | |
57 | -} | |
58 | - | |
59 | 19 … | /* |
60 | 20 … | * Underrun and suspend recovery, from alsa-lib/test/pcm.c |
61 | 21 … | */ |
62 | 22 … | |
@@ -79,9 +39,9 @@ | ||
79 | 39 … | } |
80 | 40 … | return err; |
81 | 41 … | } |
82 | 42 … | |
83 | -static void generate(struct tune_dl *dl, | |
43 … | +static void generate(struct ccdl *ccdl, | |
84 | 44 … | const snd_pcm_channel_area_t *areas, |
85 | 45 … | snd_pcm_uframes_t offset, |
86 | 46 … | int count, double *_phase) |
87 | 47 … | { |
@@ -109,19 +69,19 @@ | ||
109 | 69 … | steps[chn] = areas[chn].step / 8; |
110 | 70 … | samples[chn] += offset * steps[chn]; |
111 | 71 … | } |
112 | 72 … | |
113 | - tune_dl_load(dl, dl_fname); | |
73 … | + struct tune *tune = ccdl_get(ccdl); | |
114 | 74 … | |
115 | 75 … | /* fill the channel areas */ |
116 | 76 … | while (count-- > 0) { |
117 | 77 … | union { |
118 | 78 … | float f; |
119 | 79 … | int i; |
120 | 80 … | } fval; |
121 | 81 … | int res, i; |
122 | - if (dl->handle && dl->tune->play) { | |
123 | - fval.f = dl->tune->play(dl->tune, phase); | |
82 … | + if (tune && tune->play) { | |
83 … | + fval.f = tune->play(tune, phase); | |
124 | 84 … | } else { |
125 | 85 … | fval.f = 0; |
126 | 86 … | } |
127 | 87 … | res = fval.i; |
@@ -149,19 +109,21 @@ | ||
149 | 109 … | |
150 | 110 … | |
151 | 111 … | int main(int argc, char *argv[]) |
152 | 112 … | { |
153 | - struct tune_dl dl = {0}; | |
113 … | + struct ccdl ccdl; | |
154 | 114 … | int err; |
155 | 115 … | snd_pcm_t *pcm_out; |
116 … | + const char *src_fname = "tune.c"; | |
156 | 117 … | const char *device_out = "default"; |
157 | 118 … | |
158 | - if (argc > 2) { | |
159 | - device_out = argv[2]; | |
160 | - } | |
119 … | + if (argc > 1) src_fname = argv[1]; | |
120 … | + if (argc > 2) device_out = argv[2]; | |
161 | 121 … | |
162 | - if (tune_dl_load(&dl, dl_fname) < 0) { | |
163 | - return 1; | |
122 … | + ccdl_init(&ccdl, src_fname, "TUNE"); | |
123 … | + | |
124 … | + if (ccdl_watch(&ccdl)) { | |
125 … | + errx(1, "ccdl_watch"); | |
164 | 126 … | } |
165 | 127 … | |
166 | 128 … | if ((err = snd_pcm_open(&pcm_out, device_out, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { |
167 | 129 … | warnx("Playback open error: %s", snd_strerror(err)); |
@@ -178,12 +140,8 @@ | ||
178 | 140 … | warnx("Playback open error: %s", snd_strerror(err)); |
179 | 141 … | return 1; |
180 | 142 … | } |
181 | 143 … | |
182 | - if (dl.tune->init) { | |
183 | - dl.tune->init(dl.tune); | |
184 | - } | |
185 | - | |
186 | 144 … | snd_pcm_uframes_t buffer_size; |
187 | 145 … | snd_pcm_uframes_t period_size; |
188 | 146 … | if ((err = snd_pcm_get_params(pcm_out, &buffer_size, &period_size)) < 0) { |
189 | 147 … | warnx("Playback get params error: %s", snd_strerror(err)); |
@@ -253,9 +211,9 @@ | ||
253 | 211 … | exit(EXIT_FAILURE); |
254 | 212 … | } |
255 | 213 … | first = 1; |
256 | 214 … | } |
257 | - generate(&dl, my_areas, offset, frames, &phase); | |
215 … | + generate(&ccdl, my_areas, offset, frames, &phase); | |
258 | 216 … | // generate_sine(my_areas, offset, frames, &phase); |
259 | 217 … | commitres = snd_pcm_mmap_commit(pcm_out, offset, frames); |
260 | 218 … | if (commitres < 0 || (snd_pcm_uframes_t)commitres != frames) { |
261 | 219 … | if ((err = xrun_recovery(pcm_out, commitres >= 0 ? -EPIPE : commitres)) < 0) { |
@@ -267,10 +225,8 @@ | ||
267 | 225 … | size -= frames; |
268 | 226 … | } |
269 | 227 … | |
270 | 228 … | } |
271 | - if (dl.tune->deinit) { | |
272 | - dl.tune->deinit(dl.tune); | |
273 | - } | |
274 | 229 … | |
275 | 230 … | snd_pcm_close(pcm_out); |
231 … | + return ccdl_deinit(&ccdl); | |
276 | 232 … | } |
tune.c | ||
---|---|---|
@@ -1,26 +1,11 @@ | ||
1 | 1 … | |
2 | 2 … | |
3 | 3 … | |
4 | -static void tune_init(struct tune *tune) | |
5 | -{ | |
6 | -} | |
7 | - | |
8 | -static void tune_reload(struct tune *tune) | |
9 | -{ | |
10 | -} | |
11 | - | |
12 | 4 … | static float tune_play(struct tune *tune, double time) |
13 | 5 … | { |
14 | 6 … | return 0.99 * sin(time*440); |
15 | 7 … | } |
16 | 8 … | |
17 | -static void tune_deinit(struct tune *tune) | |
18 | -{ | |
19 | -} | |
20 | - | |
21 | 9 … | const struct tune TUNE = { |
22 | - .init = tune_init, | |
23 | - .reload = tune_reload, | |
24 | 10 … | .play = tune_play, |
25 | - .deinit = tune_deinit, | |
26 | 11 … | }; |
tune.h | ||
---|---|---|
@@ -1,10 +1,7 @@ | ||
1 | 1 … | |
2 | 2 … | |
3 | 3 … | struct tune { |
4 | - void (*init)(struct tune *); | |
5 | - void (*deinit)(struct tune *); | |
6 | - void (*reload)(struct tune *); | |
7 | 4 … | float (*play)(struct tune *, double time); |
8 | 5 … | }; |
9 | 6 … | |
10 | 7 … | extern const struct tune TUNE; |
ccdl.c | ||
---|---|---|
@@ -1,0 +1,197 @@ | ||
1 … | + | |
2 … | + | |
3 … | + | |
4 … | + | |
5 … | + | |
6 … | + | |
7 … | + | |
8 … | + | |
9 … | + | |
10 … | + | |
11 … | + | |
12 … | + | |
13 … | +static unsigned int tmp_i = 0; | |
14 … | + | |
15 … | +static 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 … | + | |
25 … | +void 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 … | + | |
34 … | +static 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 … | + | |
57 … | +int 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 … | + | |
81 … | +void *lib_get(struct lib *lib) | |
82 … | +{ | |
83 … | + if (!lib->sym) lib_build(lib); | |
84 … | + return lib->sym; | |
85 … | +} | |
86 … | + | |
87 … | +void 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 … | + | |
100 … | +void 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 … | + | |
107 … | +static 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 … | + | |
112 … | +void *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 … | + | |
121 … | +static 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 … | + | |
164 … | +static void *ccdl_watch_run_thread(void *ccdl) | |
165 … | +{ | |
166 … | + return (void *)ccdl_watch_run(ccdl); | |
167 … | +} | |
168 … | + | |
169 … | +int 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 … | + | |
176 … | +int 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 … | + | |
187 … | +int 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 … | + |
ccdl.h | ||
---|---|---|
@@ -1,0 +1,27 @@ | ||
1 … | + | |
2 … | + | |
3 … | + | |
4 … | + | |
5 … | +struct lib { | |
6 … | + const char *src_fname; | |
7 … | + const char *lib_fname; | |
8 … | + const char *sym_name; | |
9 … | + void *handle; | |
10 … | + void *sym; | |
11 … | +}; | |
12 … | + | |
13 … | +struct ccdl { | |
14 … | + struct lib libs[2], *lib; | |
15 … | + pthread_t watcher_thread; | |
16 … | +}; | |
17 … | + | |
18 … | +void lib_init(struct lib *, const char *src_fname, const char *sym_name); | |
19 … | +int lib_build(struct lib *); | |
20 … | +void *lib_get(struct lib *); | |
21 … | +void lib_deinit(struct lib *); | |
22 … | + | |
23 … | +void ccdl_init(struct ccdl *, const char *src_fname, const char *sym_name); | |
24 … | +void *ccdl_get(struct ccdl *); | |
25 … | +int ccdl_watch(struct ccdl *); | |
26 … | +int ccdl_rebuild(struct ccdl *); | |
27 … | +int ccdl_deinit(struct ccdl *); |
Built with git-ssb-web