diff --git a/.cirrus.yml b/.cirrus.yml index 1aab9e64c98..9a97e2ddea5 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -1,7 +1,7 @@ --- -cirrus-ci_task: +bazel-release_task: container: - image: toxchat/toktok-stack:0.0.31-third_party + image: toxchat/toktok-stack:0.0.31-release cpu: 2 memory: 2G configure_script: @@ -19,7 +19,7 @@ cirrus-ci_task: cimple_task: container: - image: toxchat/toktok-stack:0.0.31-third_party + image: toxchat/toktok-stack:0.0.31-release cpu: 2 memory: 4G configure_script: diff --git a/.github/settings.yml b/.github/settings.yml index 87e46041a3b..56f06edfa09 100644 --- a/.github/settings.yml +++ b/.github/settings.yml @@ -12,6 +12,7 @@ branches: protection: required_status_checks: contexts: + - bazel-release - build-bootstrapd-docker - build-macos - build-nacl @@ -25,7 +26,6 @@ branches: - "ci/circleci: static-analysis" - "ci/circleci: tsan" - cimple - - cirrus-ci - code-review/reviewable - continuous-integration/appveyor/pr diff --git a/.travis/flags-clang.sh b/.travis/flags-clang.sh index f362b357340..42279096eaf 100644 --- a/.travis/flags-clang.sh +++ b/.travis/flags-clang.sh @@ -8,6 +8,7 @@ add_flag -Wextra add_flag -Weverything # Disable specific warning flags for both C and C++. +add_flag -Wno-c11-extensions # Very verbose, not very useful. This warns about things like int -> uint # conversions that change sign without a cast and narrowing conversions. diff --git a/.travis/flags.sh b/.travis/flags.sh index 30284d38c1f..f2af31d441c 100644 --- a/.travis/flags.sh +++ b/.travis/flags.sh @@ -31,7 +31,7 @@ add_flag -O3 -march=native # Warn on non-ISO C. add_c_flag -pedantic -add_c_flag -std=c99 +add_c_flag -std=c11 add_cxx_flag -std=c++11 add_flag -g3 diff --git a/auto_tests/tox_loop_test.c b/auto_tests/tox_loop_test.c index 66dc716bdcd..e9839ff99aa 100644 --- a/auto_tests/tox_loop_test.c +++ b/auto_tests/tox_loop_test.c @@ -1,15 +1,14 @@ #include #include #include -#include #include "../toxcore/tox.h" #include "check_compat.h" +#include "../testing/misc_tools.h" + +#define TCP_RELAY_PORT 33449 -#define TCP_RELAY_PORT 33448 -/* The Travis-CI container responds poorly to ::1 as a localhost address - * You're encouraged to -D FORCE_TESTS_IPV6 on a local test */ #ifdef FORCE_TESTS_IPV6 #define TOX_LOCALHOST "::1" #else @@ -23,79 +22,95 @@ typedef struct Loop_Test { Tox *tox; } Loop_Test; -static void tox_loop_cb_start(Tox *tox, void *user_data) +static void tox_loop_cb_start(Tox *tox, void *data) { - Loop_Test *userdata = (Loop_Test *)user_data; + Loop_Test *userdata = (Loop_Test *)data; pthread_mutex_lock(&userdata->mutex); - userdata->start_count++; + ++userdata->start_count; } -static void tox_loop_cb_stop(Tox *tox, void *user_data) +static void tox_loop_cb_stop(Tox *tox, void *data) { - Loop_Test *userdata = (Loop_Test *) user_data; - userdata->stop_count++; + Loop_Test *userdata = (Loop_Test *)data; + ++userdata->stop_count; pthread_mutex_unlock(&userdata->mutex); } static void *tox_loop_worker(void *data) { - Loop_Test *userdata = (Loop_Test *) data; - tox_loop(userdata->tox, data, nullptr); + Loop_Test *userdata = (Loop_Test *)data; + Tox_Err_Loop err; + tox_loop(userdata->tox, userdata, &err); + ck_assert_msg(err == TOX_ERR_LOOP_OK, "tox_loop error: %d", err); return nullptr; } static void test_tox_loop(void) { pthread_t worker, worker_tcp; - struct Tox_Options *opts = tox_options_new(nullptr); - Loop_Test userdata; + Tox_Err_Options_New err_opts; + struct Tox_Options *opts = tox_options_new(&err_opts); + ck_assert_msg(err_opts == TOX_ERR_OPTIONS_NEW_OK, "tox_options_new: %d\n", err_opts); + tox_options_set_experimental_thread_safety(opts, true); + + Loop_Test *userdata = calloc(1, sizeof(Loop_Test)); + ck_assert(userdata != nullptr); uint8_t dpk[TOX_PUBLIC_KEY_SIZE]; - int retval; - userdata.start_count = 0; - userdata.stop_count = 0; - pthread_mutex_init(&userdata.mutex, nullptr); + userdata->start_count = 0; + userdata->stop_count = 0; + pthread_mutex_init(&userdata->mutex, nullptr); tox_options_set_tcp_port(opts, TCP_RELAY_PORT); - userdata.tox = tox_new(opts, nullptr); - tox_callback_loop_begin(userdata.tox, tox_loop_cb_start); - tox_callback_loop_end(userdata.tox, tox_loop_cb_stop); - pthread_create(&worker, nullptr, tox_loop_worker, &userdata); + Tox_Err_New err_new; + userdata->tox = tox_new(opts, &err_new); + ck_assert_msg(err_new == TOX_ERR_NEW_OK, "tox_new: %d\n", err_new); + tox_callback_loop_begin(userdata->tox, tox_loop_cb_start); + tox_callback_loop_end(userdata->tox, tox_loop_cb_stop); + pthread_create(&worker, nullptr, tox_loop_worker, userdata); - tox_self_get_dht_id(userdata.tox, dpk); + tox_self_get_dht_id(userdata->tox, dpk); tox_options_default(opts); + tox_options_set_experimental_thread_safety(opts, true); Loop_Test userdata_tcp; userdata_tcp.start_count = 0; userdata_tcp.stop_count = 0; pthread_mutex_init(&userdata_tcp.mutex, nullptr); - userdata_tcp.tox = tox_new(opts, nullptr); + userdata_tcp.tox = tox_new(opts, &err_new); + ck_assert_msg(err_new == TOX_ERR_NEW_OK, "tox_new: %d\n", err_new); tox_callback_loop_begin(userdata_tcp.tox, tox_loop_cb_start); tox_callback_loop_end(userdata_tcp.tox, tox_loop_cb_stop); pthread_create(&worker_tcp, nullptr, tox_loop_worker, &userdata_tcp); pthread_mutex_lock(&userdata_tcp.mutex); - TOX_ERR_BOOTSTRAP error; + Tox_Err_Bootstrap error; ck_assert_msg(tox_add_tcp_relay(userdata_tcp.tox, TOX_LOCALHOST, TCP_RELAY_PORT, dpk, &error), "Add relay error, %i", error); ck_assert_msg(tox_bootstrap(userdata_tcp.tox, TOX_LOCALHOST, 33445, dpk, &error), "Bootstrap error, %i", error); pthread_mutex_unlock(&userdata_tcp.mutex); - sleep(10); + c_sleep(1000); - tox_loop_stop(userdata.tox); - pthread_join(worker, (void **)(void *)&retval); - ck_assert_msg(retval == 0, "tox_loop didn't return 0"); + tox_loop_stop(userdata->tox); + void *retval = nullptr; + pthread_join(worker, &retval); + ck_assert_msg((uintptr_t)retval == 0, "tox_loop didn't return 0"); - tox_kill(userdata.tox); - ck_assert_msg(userdata.start_count == userdata.stop_count, "start and stop must match"); + tox_kill(userdata->tox); + ck_assert_msg(userdata->start_count == userdata->stop_count, "start and stop must match (start = %d, stop = %d)", + userdata->start_count, userdata->stop_count); tox_loop_stop(userdata_tcp.tox); - pthread_join(worker_tcp, (void **)(void *)&retval); - ck_assert_msg(retval == 0, "tox_loop didn't return 0"); + pthread_join(worker_tcp, &retval); + ck_assert_msg((uintptr_t)retval == 0, "tox_loop didn't return 0"); tox_kill(userdata_tcp.tox); - ck_assert_msg(userdata_tcp.start_count == userdata_tcp.stop_count, "start and stop must match"); + ck_assert_msg(userdata_tcp.start_count == userdata_tcp.stop_count, "start and stop must match (start = %d, stop = %d)", + userdata_tcp.start_count, userdata_tcp.stop_count); + + tox_options_free(opts); + free(userdata); } int main(int argc, char *argv[]) diff --git a/toxcore/LAN_discovery.c b/toxcore/LAN_discovery.c index b136ecd70a7..f448cb5e11d 100644 --- a/toxcore/LAN_discovery.c +++ b/toxcore/LAN_discovery.c @@ -47,8 +47,8 @@ * behaviour. Consider storing the data in per-instance variables instead. */ //!TOKSTYLE- // No global mutable state in Tokstyle. -static int broadcast_count = -1; -static IP_Port broadcast_ip_ports[MAX_INTERFACES]; +static _Thread_local int broadcast_count = -1; +static _Thread_local IP_Port broadcast_ip_ports[MAX_INTERFACES]; //!TOKSTYLE+ #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) @@ -209,7 +209,8 @@ static void fetch_broadcast_info(uint16_t port) #endif -/* Send packet to all IPv4 broadcast addresses +/** + * Send packet to all IPv4 broadcast addresses * * return 1 if sent to at least one broadcast target. * return 0 on failure to find any valid broadcast target. @@ -233,7 +234,7 @@ static uint32_t send_broadcasts(Networking_Core *net, uint16_t port, const uint8 return 1; } -/* Return the broadcast ip. */ +/** Return the broadcast ip. */ static IP broadcast_ip(Family family_socket, Family family_broadcast) { IP ip; @@ -266,7 +267,9 @@ static bool ip4_is_local(IP4 ip4) return ip4.uint8[0] == 127; } -/* Is IP a local ip or not. */ +/** + * Is IP a local ip or not. + */ bool ip_is_local(IP ip) { if (net_family_is_ipv4(ip.family)) { diff --git a/toxcore/LAN_discovery.h b/toxcore/LAN_discovery.h index dcb9e532f8f..feb5c7a52a9 100644 --- a/toxcore/LAN_discovery.h +++ b/toxcore/LAN_discovery.h @@ -17,7 +17,7 @@ #define LAN_DISCOVERY_INTERVAL 10 /** - * Send a LAN discovery pcaket to the broadcast address with port port. + * Send a LAN discovery packet to the broadcast address with port port. */ int32_t lan_discovery_send(uint16_t port, DHT *dht); diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c index 70fa348fda4..fc4ef198518 100644 --- a/toxcore/Messenger.c +++ b/toxcore/Messenger.c @@ -1895,11 +1895,6 @@ Messenger *new_messenger(Mono_Time *mono_time, Messenger_Options *options, unsig #ifdef HAVE_LIBEV m->dispatcher = ev_loop_new(0); -#else - m->loop_run = false; -#endif // HAVE_LIBEV - -#if defined(HAVE_LIBEV) if (m->dispatcher == nullptr) { free(m); diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h index 6a729a8c127..4b4b155acc4 100644 --- a/toxcore/Messenger.h +++ b/toxcore/Messenger.h @@ -298,8 +298,6 @@ struct Messenger { #ifdef HAVE_LIBEV struct ev_loop *dispatcher; ev_async stop_loop; -#else - bool loop_run; #endif Messenger_Options options; diff --git a/toxcore/TCP_client.c b/toxcore/TCP_client.c index e0a20b6b03f..257a92b7902 100644 --- a/toxcore/TCP_client.c +++ b/toxcore/TCP_client.c @@ -102,6 +102,32 @@ TCP_Client_Status tcp_con_status(const TCP_Client_Connection *con) { return con->status; } + +#ifdef HAVE_LIBEV +bool tcp_con_ev_is_active(TCP_Client_Connection *con) +{ + return ev_is_active(&con->sock_listener.listener) + || ev_is_pending(&con->sock_listener.listener); +} + +void tcp_con_ev_listen(TCP_Client_Connection *con, struct ev_loop *dispatcher, tcp_con_ev_listen_cb *callback, + void *data) +{ + con->sock_listener.dispatcher = dispatcher; + con->sock_listener.listener.data = data; + + ev_io_init(&con->sock_listener.listener, callback, con->sock.socket, EV_READ); + ev_io_start(dispatcher, &con->sock_listener.listener); +} +#endif + +void tcp_con_ev_stop(TCP_Client_Connection *con) +{ +#ifdef HAVE_LIBEV + ev_io_stop(con->sock_listener.dispatcher, &con->sock_listener.listener); +#endif +} + void *tcp_con_custom_object(const TCP_Client_Connection *con) { return con->custom_object; diff --git a/toxcore/TCP_client.h b/toxcore/TCP_client.h index c221daf5b8d..73a213388e1 100644 --- a/toxcore/TCP_client.h +++ b/toxcore/TCP_client.h @@ -12,6 +12,10 @@ #include "TCP_server.h" #include "crypto_core.h" +#ifdef HAVE_LIBEV +#include +#endif + #define TCP_CONNECTION_TIMEOUT 10 typedef enum TCP_Proxy_Type { @@ -43,6 +47,15 @@ IP_Port tcp_con_ip_port(const TCP_Client_Connection *con); Socket tcp_con_sock(const TCP_Client_Connection *con); TCP_Client_Status tcp_con_status(const TCP_Client_Connection *con); +#ifdef HAVE_LIBEV +bool tcp_con_ev_is_active(TCP_Client_Connection *con); + +typedef void tcp_con_ev_listen_cb(struct ev_loop *dispatcher, ev_io *sock_listener, int events); +void tcp_con_ev_listen(TCP_Client_Connection *con, struct ev_loop *dispatcher, tcp_con_ev_listen_cb *callback, + void *data); +#endif +void tcp_con_ev_stop(TCP_Client_Connection *con); + void *tcp_con_custom_object(const TCP_Client_Connection *con); uint32_t tcp_con_custom_uint(const TCP_Client_Connection *con); void tcp_con_set_custom_object(TCP_Client_Connection *con, void *object); diff --git a/toxcore/network.c b/toxcore/network.c index 6b345680645..e8c129f51ce 100644 --- a/toxcore/network.c +++ b/toxcore/network.c @@ -521,6 +521,29 @@ Socket net_sock(const Networking_Core *net) return net->sock; } +#ifdef HAVE_LIBEV +bool net_ev_is_active(Networking_Core *net) +{ + return ev_is_active(&net->sock_listener.listener) || ev_is_pending(&net->sock_listener.listener); +} + +void net_ev_listen(Networking_Core *net, struct ev_loop *dispatcher, net_ev_listen_cb *callback, void *data) +{ + net->sock_listener.dispatcher = dispatcher; + net->sock_listener.listener.data = data; + + ev_io_init(&net->sock_listener.listener, callback, net->sock.socket, EV_READ); + ev_io_start(dispatcher, &net->sock_listener.listener); +} +#endif + +void net_ev_stop(Networking_Core *net) +{ +#ifdef HAVE_LIBEV + ev_io_stop(net->sock_listener.dispatcher, &net->sock_listener.listener); +#endif +} + /* Basic network functions: */ @@ -1023,9 +1046,7 @@ void kill_networking(Networking_Core *net) } -#ifdef HAVE_LIBEV - ev_io_stop(net->sock_listener.dispatcher, &net->sock_listener.listener); -#endif + net_ev_stop(net); free(net); } diff --git a/toxcore/network.h b/toxcore/network.h index 378e863ebbb..82db948ccc7 100644 --- a/toxcore/network.h +++ b/toxcore/network.h @@ -15,6 +15,10 @@ #include // size_t #include // uint*_t +#ifdef HAVE_LIBEV +#include // uint*_t +#endif + #ifdef __cplusplus extern "C" { #endif @@ -324,6 +328,14 @@ Family net_family(const Networking_Core *net); uint16_t net_port(const Networking_Core *net); Socket net_sock(const Networking_Core *net); +#ifdef HAVE_LIBEV +bool net_ev_is_active(Networking_Core *net); + +typedef void net_ev_listen_cb(struct ev_loop *dispatcher, ev_io *sock_listener, int events); +void net_ev_listen(Networking_Core *net, struct ev_loop *dispatcher, net_ev_listen_cb *callback, void *data); +#endif +void net_ev_stop(Networking_Core *net); + /** Run this before creating sockets. * * return 0 on success diff --git a/toxcore/tox.c b/toxcore/tox.c index bd432bf56d5..26725f77818 100644 --- a/toxcore/tox.c +++ b/toxcore/tox.c @@ -58,19 +58,13 @@ static_assert(TOX_MAX_NAME_LENGTH == MAX_NAME_LENGTH, static_assert(TOX_MAX_STATUS_MESSAGE_LENGTH == MAX_STATUSMESSAGE_LENGTH, "TOX_MAX_STATUS_MESSAGE_LENGTH is assumed to be equal to MAX_STATUSMESSAGE_LENGTH"); -#if defined(HAVE_LIBEV) -typedef struct Event_Arg { - Tox *tox; - void *user_data; -} Event_Arg; -#endif - struct Tox { // XXX: Messenger *must* be the first member, because toxav casts its // `Tox *` to `Messenger **`. Messenger *m; Mono_Time *mono_time; pthread_mutex_t *mutex; + bool loop_run; tox_self_connection_status_cb *self_connection_status_callback; tox_friend_name_cb *friend_name_callback; @@ -114,6 +108,21 @@ static void unlock(const Tox *tox) } } +static bool locked(const Tox *tox, bool *value) +{ + lock(tox); + bool res = *value; + unlock(tox); + return res; +} + +static void locked_set(const Tox *tox, bool *value, bool new_value) +{ + lock(tox); + *value = new_value; + unlock(tox); +} + struct Tox_Userdata { Tox *tox; void *user_data; @@ -630,9 +639,10 @@ void tox_kill(Tox *tox) return; } + tox_loop_stop(tox); + lock(tox); LOGGER_ASSERT(tox->m->log, tox->m->msi_packet == nullptr, "Attempted to kill tox while toxav is still alive"); - tox_loop_stop(tox); kill_groupchats(tox->m->conferences_object); kill_messenger(tox->m); mono_time_free(tox->mono_time); @@ -840,19 +850,13 @@ void tox_iterate(Tox *tox, void *user_data) void tox_callback_loop_begin(Tox *tox, tox_loop_begin_cb *callback) { - if (tox == nullptr) { - return; - } - + assert(tox != nullptr); tox->loop_begin_callback = callback; } void tox_callback_loop_end(Tox *tox, tox_loop_end_cb *callback) { - if (tox == nullptr) { - return; - } - + assert(tox != nullptr); tox->loop_end_callback = callback; } @@ -863,11 +867,11 @@ static void tox_stop_loop_async(struct ev_loop *dispatcher, ev_async *listener, return; } - Event_Arg *tmp = (Event_Arg *) listener->data; - Messenger *m = tmp->tox; + Tox_Userdata *tmp = (Tox_Userdata *)listener->data; + Messenger *m = tmp->tox->m; - if (ev_is_active(&m->net->sock_listener.listener) || ev_is_pending(&m->net->sock_listener.listener)) { - ev_io_stop(dispatcher, &m->net->sock_listener.listener); + if (net_ev_is_active(m->net)) { + net_ev_stop(m->net); } uint32_t len = tcp_connections_length(nc_get_tcp_c(m->net_crypto)); @@ -875,9 +879,8 @@ static void tox_stop_loop_async(struct ev_loop *dispatcher, ev_async *listener, for (uint32_t i = 0; i < len; ++i) { const TCP_con *conn = tcp_connections_connection_at(nc_get_tcp_c(m->net_crypto), i); - if (ev_is_active(&conn->connection->sock_listener.listener) - || ev_is_pending(&conn->connection->sock_listener.listener)) { - ev_io_stop(dispatcher, &conn->connection->sock_listener.listener); + if (tcp_con_ev_is_active(conn->connection)) { + tcp_con_ev_stop(conn->connection); } } @@ -892,8 +895,9 @@ static void tox_do_iterate(struct ev_loop *dispatcher, ev_io *sock_listener, int return; } - Event_Arg *tmp = (Event_Arg *)sock_listener->data; - Messenger *m = tmp->tox->m; + Tox_Userdata *tmp = (Tox_Userdata *)sock_listener->data; + Tox *tox = tmp->tox; + Messenger *m = tox->m; if (tmp->tox->loop_begin_callback) { tmp->tox->loop_begin_callback(tmp->tox, tmp->user_data); @@ -901,11 +905,8 @@ static void tox_do_iterate(struct ev_loop *dispatcher, ev_io *sock_listener, int tox_iterate(tmp->tox, tmp->user_data); - if (!ev_is_active(&m->net->sock_listener.listener) && !ev_is_pending(&m->net->sock_listener.listener)) { - m->net->sock_listener.dispatcher = dispatcher; - ev_io_init(&m->net->sock_listener.listener, tox_do_iterate, net_sock(m->net), EV_READ); - m->net->sock_listener.listener.data = sock_listener->data; - ev_io_start(dispatcher, &m->net->sock_listener.listener); + if (!net_ev_is_active(m->net)) { + net_ev_listen(m->net, dispatcher, tox_do_iterate, tmp); } uint32_t len = tcp_connections_length(nc_get_tcp_c(m->net_crypto)); @@ -913,17 +914,13 @@ static void tox_do_iterate(struct ev_loop *dispatcher, ev_io *sock_listener, int for (uint32_t i = 0; i < len; ++i) { const TCP_con *conn = tcp_connections_connection_at(nc_get_tcp_c(m->net_crypto), i); - if (!ev_is_active(&conn->connection->sock_listener.listener) - && !ev_is_pending(&conn->connection->sock_listener.listener)) { - conn->connection->sock_listener.dispatcher = dispatcher; - ev_io_init(&conn->connection->sock_listener.listener, tox_do_iterate, tcp_con_sock(conn->connection), EV_READ); - conn->connection->sock_listener.listener.data = sock_listener->data; - ev_io_start(m->dispatcher, &conn->connection->sock_listener.listener); + if (!tcp_con_ev_is_active(conn->connection)) { + tcp_con_ev_listen(conn->connection, dispatcher, tox_do_iterate, tmp); } } - if (m->loop_end_callback) { - m->loop_end_callback(m, tmp->user_data); + if (tox->loop_end_callback) { + tox->loop_end_callback(tox, tmp->user_data); } } #else @@ -938,7 +935,9 @@ static void tox_do_iterate(struct ev_loop *dispatcher, ev_io *sock_listener, int */ static bool tox_fds(Messenger *m, Socket **sockets, uint32_t *sockets_num) { - if (m == nullptr || sockets == nullptr || sockets_num == nullptr) { + assert(m != nullptr); + + if (sockets == nullptr || sockets_num == nullptr) { return false; } @@ -981,11 +980,13 @@ static bool tox_fds(Messenger *m, Socket **sockets, uint32_t *sockets_num) bool tox_loop(Tox *tox, void *user_data, Tox_Err_Loop *error) { + assert(tox != nullptr); + Messenger *m = tox->m; #ifdef HAVE_LIBEV bool ret = true; - Event_Arg *tmp = (Event_Arg *) calloc(1, sizeof(Event_Arg)); + Tox_Userdata *tmp = (Tox_Userdata *) calloc(1, sizeof(Tox_Userdata)); if (tmp == nullptr) { SET_ERROR_PARAMETER(error, TOX_ERR_LOOP_MALLOC); @@ -1028,13 +1029,13 @@ bool tox_loop(Tox *tox, void *user_data, Tox_Err_Loop *error) uint32_t fdcount = 0; Socket *fdlist = nullptr; - m->loop_run = true; + locked_set(tox, &tox->loop_run, true); - while (m->loop_run) { + while (locked(tox, &tox->loop_run)) { Socket maxfd; fd_set readable; - if (tox->loop_begin_callback) { + if (tox->loop_begin_callback != nullptr) { tox->loop_begin_callback(tox, user_data); } @@ -1050,7 +1051,7 @@ bool tox_loop(Tox *tox, void *user_data, Tox_Err_Loop *error) if (fdcount == 0 && !tox_fds(m, &fdlist, &fdcount)) { // We must stop because maxfd won't be set. // TODO(cleverca22): should we call loop_end_callback() on error? - if (tox->loop_end_callback) { + if (tox->loop_end_callback != nullptr) { tox->loop_end_callback(tox, user_data); } @@ -1103,17 +1104,17 @@ bool tox_loop(Tox *tox, void *user_data, Tox_Err_Loop *error) void tox_loop_stop(Tox *tox) { - if (tox == nullptr) { - return; - } + assert(tox != nullptr); + lock(tox); +#ifdef HAVE_LIBEV Messenger *m = tox->m; -#ifdef HAVE_LIBEV ev_async_send(m->dispatcher, &m->stop_loop); #else - m->loop_run = false; + tox->loop_run = false; #endif + unlock(tox); } void tox_self_get_address(const Tox *tox, uint8_t *address)