diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/dynstorage.c | 86 | ||||
-rw-r--r-- | src/server/dynstorage.h | 11 | ||||
-rw-r--r-- | src/server/s6-rcd.h | 13 | ||||
-rw-r--r-- | src/server/state.c | 135 | ||||
-rw-r--r-- | src/server/state.h | 12 |
5 files changed, 216 insertions, 41 deletions
diff --git a/src/server/dynstorage.c b/src/server/dynstorage.c new file mode 100644 index 0000000..c17e8e6 --- /dev/null +++ b/src/server/dynstorage.c @@ -0,0 +1,86 @@ +/* ISC license. */ + +#include <stdint.h> +#include <string.h> +#include <stdlib.h> + +#include <skalibs/gensetdyn.h> +#include <skalibs/avltree.h> + +#include "dynstorage.h" + +/* + This is probably way overengineered, we could strdup the instance parameters + into the instances themselves; there would be a little param duplication, but + likely not much, and chances are we would save memory. + However, a fundamental principle of C memory management is: separate structure + from storage. Failing to abide by it leads to spaghettification of storage + paths, and ultimately memory leaks. + So, we store all our dynamic strings (i.e. user-provided strings that only + appear in transient storage like buffers but that need a longer lifetime) here, + and nowhere else. Duplication is prevented via refcounting. +*/ + +typedef struct cell_s cell_t, *cell_t_ref ; +struct cell_s +{ + char *s ; + uint32_t refcount ; +} ; +#define CELL_ZERO { .s = 0, .refcount = 0 } ; + +static gensetdyn cells = GENSETDYN_INIT(cell_t, 3, 3, 8) ; + +static void *dynstorage_dtok (uint32_t d, void *data) +{ + return GENSETDYN_P(cell_t, (gensetdyn *)data, d)->s ; +} + +static int dynstorage_cmp (void const *a, void const *b, void *data) +{ + (void)data ; + return strcmp((char const *)a, (char const *)b) ; +} + +static avltree dynstorage = AVLTREE_INIT(3, 3, 8, &dynstorage_dtok, &dynstorage_cmp, &cells) ; + +char const *dynstorage_add (char const *s) +{ + cell_t *p ; + uint32_t d ; + if (avltree_search(&dynstorage, s, &d)) + { + p = GENSETDYN_P(cell_t, &cells, d) ; + p->refcount++ ; + return p->s ; + } + + if (!gensetdyn_new(&cells, &d)) return 0 ; + p = GENSETDYN_P(cell_t, &cells, d) ; + p->s = strdup(s) ; + if (!p->s) goto err0 ; + p->refcount = 1 ; + if (!avltree_insert(&dynstorage, d)) goto err1 ; + return p->s ; + + err1: + free(p->s) ; + err0: + gensetdyn_delete(&cells, d) ; + return 0 ; +} + +void dynstorage_remove (char const *s) +{ + uint32_t d ; + if (avltree_search(&dynstorage, s, &d) + { + cell_t *p = GENSETDYN_P(cell_t, &cells, d) ; + if (!--p->refcount) + { + avltree_delete(&dynstorage, s) ; + free(p->s) ; + gensetdyn_delete(&cells, d) ; + } + } +} diff --git a/src/server/dynstorage.h b/src/server/dynstorage.h new file mode 100644 index 0000000..b935cc9 --- /dev/null +++ b/src/server/dynstorage.h @@ -0,0 +1,11 @@ +/* ISC license. */ + +#ifndef S6RCD_DYNSTORAGE_H +#define S6RCD_DYNSTORAGE_H + + /* Storage for dynamic strings such as instance parameters */ + +extern char const *dynstorage_add (char const *) ; +extern void dynstorage_remove (char const *) ; + +#endif diff --git a/src/server/s6-rcd.h b/src/server/s6-rcd.h index 2436c54..ca0867a 100644 --- a/src/server/s6-rcd.h +++ b/src/server/s6-rcd.h @@ -3,15 +3,16 @@ #ifndef S6RCD_H #define S6RCD_H -#include "ep.h" -#include "ev.h" -#include "transition.h" -#include "clientrules.h" #include "client.h" +#include "clientrules.h" #include "command.h" -#include "livedir.h" #include "db.h" -#include "signals.h" +#include "dynstorage.h" +#include "ep.h" +#include "ev.h" +#include "livedir.h" #include "main.h" +#include "signals.h" +#include "state.h" #endif diff --git a/src/server/state.c b/src/server/state.c index 0e2afe3..c6fb2d0 100644 --- a/src/server/state.c +++ b/src/server/state.c @@ -11,32 +11,53 @@ #include <skalibs/djbunix.h> #include <s6-rc/db.h> +#include "dynstorage.h" #include "state.h" +static stateatom_t const stateatom_zero = STATEATOM_ZERO ; + +void instance_free (instance_t *ins) +{ + dynstorage_remove(ins->param) ; +} + +int instance_new (instance_t *ins, stateatom_t const *state, char const *param) ; +{ + char const *s = dynstorage_add(param) ; + if (!s) return 0 ; + ins->state = state ; + inst->param = s ; + return 1 ; +} + void state_free (state_t *st, uint32_t const *dbn) { for (s6rc_stype_t type = S6RC_STYPE_LONGRUN ; type < S6RC_STYPE_PHAIL ; type++) { alloc_free(st->sta[type]) ; for (size_t i = 0 ; i < dbn[S6RC_STYPE_PHAIL + type] ; i++) + { + for (size_t j = 0 ; j < genalloc_len(instance_t, st->dyn[type] + i) ; j++) + instance_free(genalloc_s(instance_t, st->dyn[type] + i) + j) ; genalloc_free(instance_t, st->dyn[type] + i) ; + } alloc_free(st->dyn[type]) ; } } -int state_ready (state_t *st, uint32_t const *dbn) +int state_init (state_t *st, uint32_t const *dbn) { s6rc_stype_t type = 0 ; for (; type < S6RC_STYPE_PHAIL ; type++) { - genalloc *q ; - stateatom_t *p = alloc(sizeof(stateatom_t) * dbn[type]) ; - if (!p) goto err ; - q = alloc(sizeof(genalloc) * dbn[S6RC_STYPE_PHAIL + type]) ; - if (!q) { alloc_free(p) ; goto err ; } - st->sta[type] = p ; - for (size_t i = 0 ; i < dbn[S6RC_STYPE_PHAIL + type] ; i++) q[i] = genalloc_zero ; - st->dyn[type] = q ; + st->sta[type] = alloc(sizeof(stateatom_t) * dbn[type]) ; + if (!st->sta[type]) goto err ; + st->dyn[type] = alloc(sizeof(genalloc) * dbn[S6RC_STYPE_PHAIL + type]) ; + if (!st->dyn[type]) { alloc_free(st->sta[type]) ; goto err ; } + for (uint32_t i = 0 ; i < dbn[type] ; i++) + st->sta[type][i] = stateatom_zero ; + for (size_t i = 0 ; i < dbn[S6RC_STYPE_PHAIL + type] ; i++) + st->dyn[type][i] = genalloc_zero ; } return 1 ; @@ -49,19 +70,6 @@ int state_ready (state_t *st, uint32_t const *dbn) return 0 ; } -stateatom_t *state_atom (state_t const *st, s6rc_sid_t const *id) -{ - if (id->param) - { - size_t n = genalloc_len(instance_t, st->dyn[id->stype] + id->i) ; - instance_t *instances = genalloc_s(instance_t, st->dyn[id->stype] + id->i) ; - for (size_t i = 0 ; i < n ; i++) - if (!strcmp(id->param, instances[i].param)) return &instances[i].state ; - return 0 ; - } - else return st->sta[id->stype] + id->i ; -} - static int atom_write (buffer *b, stateatom_t const *state) { char c = state->wanted | (state->current << 1) | (state->transitioning << 2) ; @@ -82,15 +90,10 @@ int state_write (char const *file, state_t const *st, uint32_t const *dbn) buffer_init(&b, &buffer_write, fd, buf, 1024) ; for (s6rc_stype_t type = 0 ; type < S6RC_STYPE_PHAIL ; type++) - { - char pack[4] ; - uint32_pack_big(pack, dbn[type]) ; - if (buffer_put(&b, pack, 4) < 4) goto err ; - } - for (s6rc_stype_t type = 0 ; type < S6RC_STYPE_PHAIL ; type++) - { for (uint32_t i = 0 ; i < dbn[type] ; i++) if (!atom_write(&b, st->sta[type] + i)) goto err ; + + for (s6rc_stype_t type = 0 ; type < S6RC_STYPE_PHAIL ; type++) for (uint32_t i = 0 ; i < dbn[S6RC_STYPE_PHAIL + type] ; i++) { uint32_t n = genalloc_len(instance_t, st->dyn[type] + i) ; @@ -107,7 +110,6 @@ int state_write (char const *file, state_t const *st, uint32_t const *dbn) if (buffer_put(&b, p[j].param, len+1) < len+1) goto err ; } } - } if (!buffer_flush(&b)) goto err ; fd_close(fd) ; @@ -120,3 +122,76 @@ int state_write (char const *file, state_t const *st, uint32_t const *dbn) unlink_void(fn) ; return 0 ; } + +static int atom_read (buffer *b, stateatom_t *state) +{ + char c ; + if (buffer_get(b, &c, 1) < 1) return 0 ; + state->wanted = c & 1 ; + state->current = !!(c & 2) ; + state->transitioning = !!(c & 4) ; + return 1 ; +} + +int state_read (char const *file, state_t *st, uint32_t const *dbn) +{ + int fd ; + buffer b ; + char buf[1024] ; + if (!state_init(st, dbn)) return 0 ; + fd = openc_read(file) ; + if (fd == -1) goto err0 ; + buffer_init(&b, &buffer_read, fd, buf, 1024) ; + + for (s6rc_stype_t type = 0 ; type < S6RC_STYPE_PHAIL ; type++) + for (uint32_t i = 0 ; i < dbn[type] ; i++) + if (!atom_read(&b, st->sta[type] + i)) goto err ; + + for (s6rc_stype_t type = 0 ; type < S6RC_STYPE_PHAIL ; type++) + for (uint32_t i = 0 ; i < dbn[S6RC_STYPE_PHAIL + type] ; i++) + { + uint32_t n ; + char pack[4] ; + if (buffer_get(&b, pack, 4) < 4) goto err ; + uint32_unpack_big(pack, &n) ; + if (!genalloc_ready(instance_t, st->dyn[type] + i, n)) goto err ; + for (uint32_t j = 0 ; i < n ; j++) + { + uint32_t len ; + instance_t *ins = genalloc_s(instance_t, st->dyn[type] + i) + j ; + if (!atom_read(&b, &ins->state)) goto err ; + if (buffer_get(&b, pack, 4) < 4) goto err ; + uint32_unpack_big(pack, &len) ; + { + char param[len + 1] ; + if (buffer_get(&b, param, len + 1) < len + 1) goto err ; + if (param[len]) { errno = EINVAL ; goto err ; } + ins->param = dynstorage_add(param) ; + if (!ins_param) goto err ; + } + } + genalloc_setlen(instance_t, st->dyn[type] + i, n) ; + } + + fd_close(fd) ; + return 1 ; + + err: + fd_close(fd) ; + err0: + state_free(st, dbn) ; + return 0 ; +} + +stateatom_t *state_atom (state_t const *st, s6rc_sid_t const *id) +{ + if (id->param) + { + size_t n = genalloc_len(instance_t, st->dyn[id->stype] + id->i) ; + instance_t *instances = genalloc_s(instance_t, st->dyn[id->stype] + id->i) ; + for (size_t i = 0 ; i < n ; i++) + if (!strcmp(id->param, instances[i].param)) return &instances[i].state ; + return 0 ; + } + else return st->sta[id->stype] + id->i ; +} diff --git a/src/server/state.h b/src/server/state.h index f0149bc..f49ffb4 100644 --- a/src/server/state.h +++ b/src/server/state.h @@ -17,11 +17,12 @@ struct stateatom_s uint8_t current : 1 ; uint8_t transitioning : 1 ; } ; +#define STATEATOM_ZERO { .wanted = 0, .current = 0, .transitioning = 0 } typedef struct instance_s instance_t, *instance_t_ref ; struct instance_s { - char const *param ; + char const *param ; /* refcounted pointer to dynstorage */ stateatom_t state ; } ; @@ -32,14 +33,15 @@ struct state_s genalloc *dyn[S6RC_STYPE_PHAIL] ; /* every genalloc is a list of instance_t */ } ; +extern void instance_free (instance_t *) ; +extern int instance_new (instance_t *, stateatom_t const *, char const *) ; + extern void state_free (state_t *, uint32_t const *) ; -extern int state_ready (state_t *, uint32_t const *) ; +extern int state_init (state_t *, uint32_t const *) ; extern int state_write (char const *, state_t const *, uint32_t const *) ; -extern int state_read (char const *, state_t *, uint32_t const *) ; - +extern int state_read (char const *, state_t *, uint32_t const *) ; /* also inits */ extern stateatom_t *state_atom (s6rc_db_t const *, state_t const *, s6rc_sid_t const *) ; - #endif |