From ed0c9058176161d49b567fcdbe1423d8d2607581 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franz=20Brau=C3=9Fe?= Date: Sat, 31 Aug 2019 17:21:08 +0200 Subject: [PATCH] ref-count and objectify stuff, see also https://github.com/boazsegev/facil.io/issues/72 --- ksc.py | 59 +++++++++++++++++++++++++++---------------- src/ffi.c | 49 ++++++++++++++++++++++-------------- src/ffi.h | 14 +++++------ src/json-store.c | 39 +++++++++++++++++++++++++--- src/json-store.h | 4 ++- src/ksc-ws-private.h | 60 +++++++++++++++++++++++++------------------- src/ksc-ws.c | 11 +++++--- src/test.c | 35 +++++++++----------------- src/utils.c | 12 ++++++--- src/utils.h | 54 ++++++++++++++++++++++++++++++++++----- src/ws-send.c | 39 ++++++++++++---------------- 11 files changed, 239 insertions(+), 137 deletions(-) diff --git a/ksc.py b/ksc.py index 742caf7..6afc6b6 100644 --- a/ksc.py +++ b/ksc.py @@ -22,17 +22,17 @@ class socket(Structure): pass def __init__(self): - self._ksc = CDLL('libksc.so') + self._ksc = CDLL('./libksc.so') - ksc_log_p = POINTER(ksc_ffi.log) + ksc_ffi_log_p = POINTER(ksc_ffi.log) ksc_envelope_p = POINTER(ksc_ffi.envelope) ksc_data_p = POINTER(ksc_ffi.data) ksc_p = POINTER(ksc_ffi.socket) for k, v in { - 'log_create': (ksc_log_p, (c_int, c_char_p)), - 'log_destroy': (c_void_p, (ksc_log_p,)), - 'log_restrict_context': (c_int, (ksc_log_p, c_char_p, c_char_p)), + 'log_create': (ksc_ffi_log_p, (c_int, c_char_p)), + 'log_unref': (c_void_p, (ksc_ffi_log_p,)), + 'log_restrict_context': (c_int, (ksc_ffi_log_p, c_char_p, c_char_p)), 'envelope_get_source': (c_char_p, (ksc_envelope_p,)), 'envelope_get_source_device_id': (c_int64, (ksc_envelope_p,)), 'envelope_get_timestamp': (c_int64, (ksc_envelope_p,)), @@ -45,7 +45,7 @@ def __init__(self): CFUNCTYPE(c_int, ksc_p, ksc_envelope_p, ksc_data_p), # on_data CFUNCTYPE(None, ksc_p), # on_open CFUNCTYPE(None, c_void_p, c_void_p), # on_close - ksc_log_p, + ksc_ffi_log_p, c_char_p, # server_cert_path c_int, # on_close_do_reconnect c_void_p)), @@ -62,18 +62,27 @@ def __init__(self): getattr(self._ksc, k2).argtypes) = v setattr(self, k, getattr(self._ksc, k2)) +class log: + def __init__(self, fd, level, restricted_contexts = {}): + self.fd = fd + self.level = level + self.restricted_contexts = restricted_contexts + + def __del__(self): + print('log __del__') + class ksc: def __init__(self): self._ffi = ksc_ffi() # level is one of 'none', 'error', 'warn', 'info', 'note', 'debug' - def log_create(self, fd, level): + def _log_create(self, fd, level): return self._ffi.log_create(fd, level.encode()) - def log_destroy(self, log): - self._ffi.log_destroy(log) + def _log_unref(self, log): + self._ffi.log_unref(log) - def log_restrict_context(self, log, desc, level): + def _log_restrict_context(self, log, desc, level): return self._ffi.log_restrict_context(log, desc.encode(), level.encode()) @@ -84,14 +93,23 @@ def _zero(obj): def start(self, json_store_path, server_cert_path, log = None, on_receipt = None, on_data = None, on_open = None, on_close = None, on_close_do_reconnect = False, data = None): - return self._ffi.start(json_store_path.encode(), - self._ffi.start.argtypes[1](ksc._zero(on_receipt)), - self._ffi.start.argtypes[2](ksc._zero(on_data)), - self._ffi.start.argtypes[3](ksc._zero(on_open)), - self._ffi.start.argtypes[4](ksc._zero(on_close)), - log, - server_cert_path.encode(), - on_close_do_reconnect, data) + if log is not None: + ffi_log = self._log_create(log.fd, log.level) + for desc, level in log.restricted_contexts.items(): + self._log_restrict_context(ffi_log, desc, level) + else: + ffi_log = None + r = self._ffi.start(json_store_path.encode(), + self._ffi.start.argtypes[1](ksc._zero(on_receipt)), + self._ffi.start.argtypes[2](ksc._zero(on_data)), + self._ffi.start.argtypes[3](ksc._zero(on_open)), + self._ffi.start.argtypes[4](ksc._zero(on_close)), + ffi_log, + server_cert_path.encode(), + on_close_do_reconnect, data) + if ffi_log is not None: + self._log_unref(ffi_log) + return r def stop(self, k): self._ffi.stop(k) @@ -102,10 +120,9 @@ def send_message(self, k, recipient, body, end_session = False, on_response = No data) """ -from ksc import ksc +from ksc import ksc, log k = ksc() -log = k.log_create(2, 'note') -sock = k.start(LOCAL_PATH, 'share/whisper.store.asn1', log = log) +sock = k.start(LOCAL_PATH, 'share/whisper.store.asn1', log = log(2, 'debug')) k.send_message(sock, NUMBER, 'hi from Python') k.stop(sock) """ diff --git a/src/ffi.c b/src/ffi.c index b3dc661..37a40ee 100644 --- a/src/ffi.c +++ b/src/ffi.c @@ -8,22 +8,35 @@ #include "SignalService.pb-c.h" -struct ksc_log * ksc_ffi_log_create(int fd, const char *level) +/* .log.context_lvls contains dynamically allocated .desc strings */ +struct ksc_ffi_log { + struct ksc_log log; +}; + +struct ksc_ffi_log * ksc_ffi_log_create(int fd, const char *level) { - struct ksc_log log = { .fd = fd }; - if (!ksc_log_lvl_parse(level, &log.max_lvl)) + struct ksc_ffi_log log = { { .fd = fd } }; + if (!ksc_log_lvl_parse(level, &log.log.max_lvl)) return NULL; + REF_INIT(&log.log); return ksc_memdup(&log, sizeof(log)); } -void ksc_ffi_log_destroy(struct ksc_log *log) +void ksc_ffi_log_destroy(struct ksc_ffi_log *log) { - if (log) - ksc_log_fini(log); - ksc_free(log); + if (!log) + return; + KSC_DEBUG(DEBUG, "ffi: log-unref with count %zu\n", log->log.ref_counted.cnt); + if (!UNREF(&log->log)) { + for (struct ksc_log__context_lvl *c = log->log.context_lvls; c; + c = c->next) + free((char *)c->desc); + ksc_log_fini(&log->log); + ksc_free(log); + } } -int ksc_ffi_log_restrict_context(struct ksc_log *log, const char *desc, +int ksc_ffi_log_restrict_context(struct ksc_ffi_log *log, const char *desc, const char *level) { if (!log) @@ -34,11 +47,11 @@ int ksc_ffi_log_restrict_context(struct ksc_log *log, const char *desc, if (!ksc_log_lvl_parse(level, &max_lvl)) return -EINVAL; struct ksc_log__context_lvl cl = { - .next = log->context_lvls, - .desc = desc, + .next = log->log.context_lvls, + .desc = strdup(desc), .max_lvl = max_lvl, }; - log->context_lvls = ksc_memdup(&cl, sizeof(cl)); + log->log.context_lvls = ksc_memdup(&cl, sizeof(cl)); return 0; } @@ -103,7 +116,7 @@ struct ksc_ffi { ws_s *ws; struct json_store *js; struct ksc_ws *kws; - struct ksc_log *log; + struct ksc_ffi_log *log; pthread_t thread; int (*on_receipt)(const struct ksc_ffi *, struct ksc_ffi_envelope *e); @@ -159,9 +172,8 @@ static void ffi_on_open(ws_s *ws, struct ksc_ws *kws) static void ffi_destroy(struct ksc_ffi *ffi) { - ksc_ffi_log_destroy(ffi->log); if (ffi->js) - json_store_destroy(ffi->js); + json_store_unref(ffi->js); ksc_free(ffi); } @@ -187,7 +199,7 @@ struct ksc_ffi * ksc_ffi_start(const char *json_store_path, struct ksc_ffi_data *c), void (*on_open)(const struct ksc_ffi *), void (*on_close)(intptr_t uuid, void *udata), - struct ksc_log *log, + struct ksc_ffi_log *log, const char *server_cert_path, int on_close_do_reconnect, void *udata @@ -204,11 +216,10 @@ struct ksc_ffi * ksc_ffi_start(const char *json_store_path, struct ksc_ffi *ffi = ksc_memdup(&ffi_, sizeof(ffi_)); if (!ffi) return NULL; - ffi->js = json_store_create(json_store_path, log); + ffi->js = json_store_create(json_store_path, &log->log); if (!ffi->js) goto error; - ffi->log = ksc_memdup(ffi->log ? ffi->log : &KSC_DEFAULT_LOG, - sizeof(*ffi->log)); + ffi->log = log; struct ksc_ws *kws = ksc_ws_connect_service(ffi->js, .on_receipt = ffi_on_receipt, .on_content = ffi_on_content, @@ -216,7 +227,7 @@ struct ksc_ffi * ksc_ffi_start(const char *json_store_path, .on_close = ffi_on_close, .udata = ffi, .signal_log_ctx = { "signal ctx", "95" /* bright magenta */ }, - .log = log, + .log = &log->log, .server_cert_path = server_cert_path, .on_close_do_reconnect = on_close_do_reconnect, ); diff --git a/src/ffi.h b/src/ffi.h index f9b36fa..f86ef34 100644 --- a/src/ffi.h +++ b/src/ffi.h @@ -16,13 +16,13 @@ /* logging */ -struct ksc_log; +struct ksc_ffi_log; -struct ksc_log * ksc_ffi_log_create(int fd, const char *level); -void ksc_ffi_log_destroy(struct ksc_log *log); -int ksc_ffi_log_restrict_context(struct ksc_log *log, - const char *desc, - const char *level); +struct ksc_ffi_log * ksc_ffi_log_create(int fd, const char *level); +void ksc_ffi_log_destroy(struct ksc_ffi_log *log); +int ksc_ffi_log_restrict_context(struct ksc_ffi_log *log, + const char *desc, + const char *level); /* service connection */ @@ -53,7 +53,7 @@ struct ksc_ffi * ksc_ffi_start(const char *json_store_path, struct ksc_ffi_data *c), void (*on_open)(const struct ksc_ffi *), void (*on_close)(intptr_t uuid, void *udata), - struct ksc_log *log, + struct ksc_ffi_log *log, const char *server_cert_path, int on_close_do_reconnect, void *udata diff --git a/src/json-store.c b/src/json-store.c index 4681e0d..a143335 100644 --- a/src/json-store.c +++ b/src/json-store.c @@ -86,6 +86,7 @@ static void kjson_object_remove(struct kjson_object *obj, struct kjson_object_en } struct json_store { + REF_COUNTED; struct kjson_value cfg; int fd; char *path; @@ -258,14 +259,41 @@ bool json_store_load(struct json_store *js) return r; } -void json_store_destroy(struct json_store *js) +static void json_store_destroy(struct json_store *js) { json_value_fini(&js->cfg); ksc_free(js->path); close(js->fd); /* also releases lockf(3p) lock */ + assert(!js->ref_counted.cnt); + if (!UNREF(js->log)) + ksc_log_fini(js->log); ksc_free(js); } +void json_store_ref(struct json_store *js) { REF(js); } + +void json_store_unref(struct json_store *js) +{ + if (UNREF(js)) + return; + + int r = json_store_save(js); + LOG_(r ? KSC_LOG_ERROR : KSC_LOG_DEBUG, + "json_store_save returned %d\n", r); + if (!r) { + r = json_store_load(js); + LOG_(r ? KSC_LOG_DEBUG : KSC_LOG_ERROR, + "json_store_load returned %d\n", r); + r = !r; + } + if (!r) { + r = json_store_save(js); + LOG_(r ? KSC_LOG_ERROR : KSC_LOG_DEBUG, + "json_store_save returned %d\n", r); + } + json_store_destroy(js); +} + struct json_store * json_store_create(const char *path, struct ksc_log *log) { struct json_store *js = NULL; @@ -283,6 +311,7 @@ struct json_store * json_store_create(const char *path, struct ksc_log *log) LOGL(ERROR, log, "calloc: %s\n", strerror(errno)); goto fail; } + REF(log); js->fd = fd; js->log = log; js->path = strdup(path); @@ -292,14 +321,16 @@ struct json_store * json_store_create(const char *path, struct ksc_log *log) } if (!json_store_load(js)) { LOG(ERROR, "json_store_load: failed\n"); - json_store_destroy(js); - js = NULL; + goto fail_1; } + REF_INIT(js); return js; fail_1: - ksc_free(js); + json_store_destroy(js); + js = NULL; fail: + ksc_free(js); close(fd); return NULL; } diff --git a/src/json-store.h b/src/json-store.h index 478c608..d3583a3 100644 --- a/src/json-store.h +++ b/src/json-store.h @@ -18,9 +18,11 @@ struct json_store; struct ksc_log; struct json_store * json_store_create(const char *path, struct ksc_log *log); -void json_store_destroy(struct json_store *); +// void json_store_destroy(struct json_store *); int json_store_save(struct json_store *); bool json_store_load(struct json_store *); +void json_store_ref(struct json_store *); +void json_store_unref(struct json_store *); const char * json_store_get_username(const struct json_store *); bool json_store_get_device_id(const struct json_store *, int32_t *ret); diff --git a/src/ksc-ws-private.h b/src/ksc-ws-private.h index 1f961ad..4cb302c 100644 --- a/src/ksc-ws-private.h +++ b/src/ksc-ws-private.h @@ -12,8 +12,6 @@ #ifndef KSC_WS_PRIVATE_H #define KSC_WS_PRIVATE_H -#include -#include /* atomic_init() */ #include /* PRI* macros */ #include /* pthread_mutex */ @@ -27,38 +25,48 @@ #define RECEIPT SIGNALSERVICE__ENVELOPE__TYPE__RECEIPT #define UNIDENTIFIED_SENDER SIGNALSERVICE__ENVELOPE__TYPE__UNIDENTIFIED_SENDER -/* ref-counted structs */ - -#ifndef KSC_WARN_UNUSED -# ifdef __GNUC__ -# define KSC_WARN_UNUSED __attribute__((warn_unused_result)) -# else -# define KSC_WARN_UNUSED -# endif -#endif - -struct ref_counted { - _Atomic size_t cnt; +struct object { + REF_COUNTED; + void (*fini)(struct object *); }; -static inline struct ref_counted * ref(struct ref_counted *ref) +static inline void obj_init(struct object *v, void (*fini)(struct object *)) { - ref->cnt++; - return ref; + REF_INIT(v); + v->fini = fini; } -KSC_WARN_UNUSED -static inline size_t unref(struct ref_counted *ref) +static inline void obj_ref(struct object *v) { - assert(ref->cnt); - return --ref->cnt; + KSC_DEBUG(INFO, "obj_ref(%p)\n", v); + REF(v); } -#define REF_COUNTED struct ref_counted ref_counted -#define REF_INIT(ptr,v) atomic_init(&(ptr)->ref_counted.cnt, (v)) -/* only use directly when you know what you're doing: no destructor invoked */ -#define REF(ptr) ref(&(ptr)->ref_counted) -#define UNREF(ptr) unref(&(ptr)->ref_counted) +static inline void obj_unref(struct object *v) +{ + KSC_DEBUG(INFO, "obj_unref(%p)\n", v); + if (!UNREF(v)) + v->fini(v); +} + +#define OBJECT struct object object_base +#define OBJ_OF(ptr) &(ptr)->object_base +#define OBJ_INIT(ptr,fini) obj_init(OBJ_OF(ptr), fini) +#define OBJ_REF(ptr) obj_ref(OBJ_OF(ptr)) +#define OBJ_UNREF(ptr) obj_unref(OBJ_OF(ptr)) +#define OBJ_TO(obj,type) \ + (type *)((char *)(obj) - offsetof(type, object_base)) + +/* helper to automate .on_finish by calling OBJ_UNREF */ +static inline int obj_run_every(int timeout_ms, int repetitions, + void (*on_timeout)(struct object *udata), + struct object *udata) +{ + obj_ref(udata); + return fio_run_every(timeout_ms, repetitions, + (void (*)(void *))on_timeout, udata, + (void (*)(void *))obj_unref); +} struct ksc_ws { REF_COUNTED; diff --git a/src/ksc-ws.c b/src/ksc-ws.c index f7735d4..725aaa4 100644 --- a/src/ksc-ws.c +++ b/src/ksc-ws.c @@ -43,6 +43,10 @@ void ksignal_ctx_destroy(struct ksc_ws *ksc) signal_context_destroy(ksc->ctx); ksc_free(ksc->url); pthread_mutex_destroy(&ksc->signal_mtx); + if (ksc->js) + json_store_unref(ksc->js); + if (!UNREF(ksc->args.log)) + ksc_log_fini(ksc->args.log); ksc_free(ksc); } @@ -791,13 +795,12 @@ static void ctx_unlock(void *user_data) } static struct ksc_ws * ksignal_ctx_create(struct json_store *js, - struct ksc_log *log) + const struct ksc_log *log) { struct ksc_ws *ksc = NULL; ksc = ksc_calloc(1, sizeof(*ksc)); - REF_INIT(ksc, 0); - ksignal_ctx_ref(ksc); + REF_INIT(ksc); pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); @@ -832,6 +835,7 @@ static struct ksc_ws * ksignal_ctx_create(struct json_store *js, goto fail; } + json_store_ref(js); json_store_protocol_store_init(ksc->psctx, js); ksc->js = js; @@ -890,6 +894,7 @@ struct ksc_ws * (ksc_ws_connect_service)(struct json_store *js, return NULL; } ksc->args = args; + REF(args.log); intptr_t uuid = ksc_ws_connect_raw(ksc->url, .on_open = on_open, .handle_request = handle_request, diff --git a/src/test.c b/src/test.c index 5c9f817..da30096 100644 --- a/src/test.c +++ b/src/test.c @@ -319,11 +319,13 @@ static void on_sent(size_t n_failed, uint64_t timestamp, { struct ksc_ctx *ksc = udata; if (devs) - LOG(NOTE, "on_sent to %.*s: failed to build session to %zu of %zu devices\n", - (int)addr->name_len, addr->name, n_failed, devs->n); + LOG(NOTE, "on_sent to %.*s at %" PRIu64 ": failed to build " + "session to %zu of %zu devices\n", + (int)addr->name_len, addr->name, timestamp, n_failed, devs->n); else - LOG(ERROR, "on_sent to %.*s: failed to send messages, timeout?\n", - (int)addr->name_len, addr->name); + LOG(ERROR, "on_sent to %.*s at %" PRIu64 ": failed to send " + "messages, timeout?\n", + (int)addr->name_len, addr->name, timestamp); } static void send_get_profile(ws_s *s, struct ksc_ws *kws) @@ -516,13 +518,15 @@ int main(int argc, char **argv) return 1; } - struct ksc_ctx ctx = { + static struct ksc_ctx ctx; + ctx = (struct ksc_ctx){ .log = log, .message = message, .target = target, .end_session = end_session, .sync_request = sync_request, }; + REF_INIT(&ctx.log); struct json_store *js = NULL; js = json_store_create(cli_path, &ctx.log); LOGL_(js ? KSC_LOG_DEBUG : KSC_LOG_ERROR, &ctx.log, "js: %p\n", (void *)js); @@ -560,22 +564,6 @@ int main(int argc, char **argv) fio_start(.threads=1); - r = json_store_save(js); - LOGL_(r ? KSC_LOG_ERROR : KSC_LOG_DEBUG, &ctx.log, - "json_store_save returned %d\n", r); - if (!r) { - r = json_store_load(js); - LOGL_(r ? KSC_LOG_DEBUG : KSC_LOG_ERROR, &ctx.log, - "json_store_load returned %d\n", r); - r = !r; - } - if (!r) { - r = json_store_save(js); - LOGL_(r ? KSC_LOG_ERROR : KSC_LOG_DEBUG, &ctx.log, - "json_store_save returned %d\n", r); - } - json_store_destroy(js); - #ifdef KSC_DEBUG_MEM_USAGE for (unsigned i=0; icontext_lvls; (it = jt);) { jt = it->next; ksc_free(it); } + log->context_lvls = NULL; } bool ksc_log_lvl_parse(const char *lvl, enum ksc_log_lvl *res) @@ -140,7 +142,7 @@ bool ksc_log_lvl_parse(const char *lvl, enum ksc_log_lvl *res) return false; } -static void ksc_log_desc_msg(struct ksc_log *log, enum ksc_log_lvl level, +static void ksc_log_desc_msg(const struct ksc_log *log, enum ksc_log_lvl level, const struct ksc_log_context *context) { #define BOLD "1;" @@ -177,15 +179,17 @@ bool ksc_log_prints(enum ksc_log_lvl lvl, const struct ksc_log *log, enum ksc_log_lvl max_lvl = log->max_lvl; if (context && context->desc) for (const struct ksc_log__context_lvl *it = log->context_lvls; - it; it = it->next) + it; it = it->next) { + assert(it->desc); if (!strcmp(context->desc, it->desc)) { max_lvl = it->max_lvl; break; } + } return lvl <= max_lvl; } -void ksc_vlog(enum ksc_log_lvl level, struct ksc_log *log, +void ksc_vlog(enum ksc_log_lvl level, const struct ksc_log *log, const struct ksc_log_context *context, const char *fmt, va_list ap) { @@ -203,7 +207,7 @@ void ksc_vlog(enum ksc_log_lvl level, struct ksc_log *log, } __attribute__((format(printf,4,5))) -void ksc_log(enum ksc_log_lvl level, struct ksc_log *log, +void ksc_log(enum ksc_log_lvl level, const struct ksc_log *log, const struct ksc_log_context *context, const char *fmt, ...) { va_list ap; diff --git a/src/utils.h b/src/utils.h index 20cf5d1..b8adabb 100644 --- a/src/utils.h +++ b/src/utils.h @@ -15,6 +15,8 @@ #include #include #include /* va_list */ +#include /* atomic_init() */ +#include #include @@ -115,6 +117,39 @@ MMC_DEF(ld,long double) #define CLAMP(x,low,high) \ _Generic((x)+(intmax_t)0, KSC__MMC_GENERIC_BODY(ksc_clamp))(x,low,high) +/* ref-counted structs */ + +#ifndef KSC_WARN_UNUSED +# ifdef __GNUC__ +# define KSC_WARN_UNUSED __attribute__((warn_unused_result)) +# else +# define KSC_WARN_UNUSED +# endif +#endif + +struct ref_counted { + _Atomic size_t cnt; +}; + +static inline struct ref_counted * ref(struct ref_counted *ref) +{ + ref->cnt++; + return ref; +} + +KSC_WARN_UNUSED +static inline size_t unref(struct ref_counted *ref) +{ + assert(ref->cnt); + return --ref->cnt; +} + +#define REF_COUNTED struct ref_counted ref_counted +#define REF_INIT(ptr) atomic_init(&(ptr)->ref_counted.cnt, 1) +/* only use directly when you know what you're doing: no destructor invoked */ +#define REF(ptr) ref(&(ptr)->ref_counted) +#define UNREF(ptr) unref(&(ptr)->ref_counted) + /* logging */ enum ksc_log_lvl { @@ -128,7 +163,14 @@ enum ksc_log_lvl { bool ksc_log_lvl_parse(const char *lvl, enum ksc_log_lvl *res); +/* .log needs to be allocated dynamically, because the on_exit handlers + * (including those stopping for fio_timed_run_every()) run after main() + * returns. The reason is that fio_lib_destroy(void) (called by + * _dl_fini() e.g. on SIGINT) is declared with + * __attribute__((destructor)). We still need access to this log at that + * point, so make it refcnted. */ struct ksc_log { + REF_COUNTED; enum ksc_log_lvl max_lvl; int fd; struct ksc_log__context_lvl { @@ -139,7 +181,7 @@ struct ksc_log { int override_color; }; -#define KSC_DEFAULT_LOG (struct ksc_log){ INT_MAX, STDERR_FILENO, NULL, 0 } +#define KSC_DEFAULT_LOG (struct ksc_log){ {}, INT_MAX, STDERR_FILENO, NULL, 0 } void ksc_log_fini(struct ksc_log *log); @@ -151,23 +193,23 @@ struct ksc_log_context { bool ksc_log_prints(enum ksc_log_lvl lvl, const struct ksc_log *log, const struct ksc_log_context *context); -void ksc_vlog(enum ksc_log_lvl level, struct ksc_log *log, +void ksc_vlog(enum ksc_log_lvl level, const struct ksc_log *log, const struct ksc_log_context *context, const char *fmt, va_list ap); __attribute__((format(printf,4,5))) -void ksc_log(enum ksc_log_lvl level, struct ksc_log *log, +void ksc_log(enum ksc_log_lvl level, const struct ksc_log *log, const struct ksc_log_context *context, const char *fmt, ...); /* log and context may be empty */ #define KSC_LOG_(level, log, msg_context, ...) \ ksc_log(level, \ - ((struct { struct ksc_log *ptr; }){log}.ptr), \ + ((struct { const struct ksc_log *ptr; }){log}.ptr), \ ((struct { const struct ksc_log_context *ptr; }){msg_context}.ptr),\ __VA_ARGS__) /* lvl is the * abbreviation of KSC_LOG_*, log and context may be empty */ -#define KSC_LOG(lvl, log_ctx, msg_context, ...) \ - KSC_LOG_(KSC_LOG_ ## lvl, log_ctx, msg_context, __VA_ARGS__) +#define KSC_LOG(lvl, log, msg_context, ...) \ + KSC_LOG_(KSC_LOG_ ## lvl, log, msg_context, __VA_ARGS__) #define KSC_DEBUGL(lvl, log, ...) \ KSC_LOG(lvl, log, \ diff --git a/src/ws-send.c b/src/ws-send.c index f6a31ed..0a3ea23 100644 --- a/src/ws-send.c +++ b/src/ws-send.c @@ -167,7 +167,7 @@ struct send_message_data2 { }; struct send_message_data { - REF_COUNTED; + OBJECT; struct ksc_ws *ksc; struct ksc_service_address recipient; @@ -187,17 +187,6 @@ struct send_message_data { bool is_recipient_udpate; }; -static void send_message_data_unref(struct send_message_data *data) -{ - if (UNREF(data)) - return; - ksc_free(data->data2.content); - ksc_free(data->recipient.relay); - ksc_free(data->recipient.name); - ksignal_ctx_unref(data->ksc); - ksc_free(data); -} - static void on_sent_sync_transcript_result(const struct ksc_service_address *recipient, struct ksc_signal_response *response, @@ -279,15 +268,14 @@ static void handle_send_message_result(struct ksc_signal_response *response, data->result.cb_called = true; } -static void on_send_message_response_timeout(void *udata) +static void on_send_message_response_timeout(struct object *udata) { - struct send_message_data *data = udata; + struct send_message_data *data = OBJ_TO(udata, struct send_message_data); struct ksc_ws *ksc = data->ksc; LOG(NOTE, "send message response timeout for recipient %.*s, result: %02x\n", (int)data->recipient.name_len, data->recipient.name, data->result_u8); data->result.timeout = true; handle_send_message_result(NULL, data); - send_message_data_unref(data); } #if 0 /* TODO: handle */ @@ -356,11 +344,16 @@ static int on_send_message_response(ws_s *ws, (void)ws; } -static void on_send_message_unsubscribe(void *udata) +static void send_message_data_fini(struct object *obj) { - struct send_message_data *data = udata; + struct send_message_data *data = OBJ_TO(obj, struct send_message_data); + KSC_DEBUG(INFO, "send_message_data_fini()\n"); handle_send_message_result(NULL, data); - send_message_data_unref(data); + ksc_free(data->data2.content); + ksc_free(data->recipient.relay); + ksc_free(data->recipient.name); + ksignal_ctx_unref(data->ksc); + ksc_free(data); } /* -------------------------------------------------------------------------- @@ -875,6 +868,7 @@ static int send_message_final(const char *recipient, size_t recipient_len, LOG(DEBUG, "sending JSON: %.*s\n", (int)json_c.len, json_c.data); struct send_message_data *cb_data = ksc_calloc(1, sizeof(*cb_data)); + OBJ_INIT(cb_data, send_message_data_fini); /* initial ref for .on_unsubscribe */ ksignal_ctx_ref(ksc); cb_data->ksc = ksc; cb_data->recipient.name = strndup(recipient, recipient_len); @@ -887,22 +881,21 @@ static int send_message_final(const char *recipient, size_t recipient_len, static char *headers[] = { "Content-Type: application/json", }; - REF(cb_data); /* for .on_unsubscribe */ + assert(!ksc->args.log->context_lvls); r = ksc_ws_send_request(data.ws, "PUT", path, .size = json_c.len, .body = json_c.data, .headers = headers, .n_headers = KSC_ARRAY_SIZE(headers), .on_response = on_send_message_response, - .on_unsubscribe = on_send_message_unsubscribe, + .on_unsubscribe = (void (*)(void *))obj_unref, .udata = cb_data); if (r) cb_data = NULL; if (!r) { - REF(cb_data); - fio_run_every(SEND_MESSAGE_RESPONSE_TIMEOUT * 1000, 1, - on_send_message_response_timeout, cb_data, NULL); + obj_run_every(SEND_MESSAGE_RESPONSE_TIMEOUT * 1000, 1, + on_send_message_response_timeout, OBJ_OF(cb_data)); if (data.args.on_sent) { struct ksc_service_address rec = { .name = (char *)recipient,