From 8fb1c09df1540aa3fca1148bed6a08ffc3090669 Mon Sep 17 00:00:00 2001 From: Dirk Engling Date: Tue, 27 Oct 2026 19:15:22 +0100 Subject: All OSes now do have a cheap monotonic clock, so no caching thread is needed. Also add some relative time helpers --- opentracker.c | 19 +++---------------- ot_accesslist.c | 12 ++++++------ ot_clean.c | 6 +++--- ot_http.c | 6 +++--- ot_livesync.c | 10 +++++----- ot_stats.c | 2 +- ot_udp.c | 8 ++++---- tests/stubs.c | 3 +-- trackerlogic.c | 4 ++-- trackerlogic.h | 29 ++++++++++++++++++++++++++--- 10 files changed, 54 insertions(+), 45 deletions(-) diff --git a/opentracker.c b/opentracker.c index 11da486..6271b9e 100644 --- a/opentracker.c +++ b/opentracker.c @@ -39,7 +39,6 @@ #include "trackerlogic.h" /* Globals */ -time_t g_now_seconds; uint32_t g_tracker_id; volatile int g_opentracker_running = 1; int g_self_pipe[2]; @@ -203,7 +202,7 @@ static void handle_write(const int64_t sock) { waiting to write and go back to waiting for the next request */ http_interest_drop(sock, cookie, EVENT_OUT); http_interest_add(sock, cookie, EVENT_IN); - fdstate_set_expiry(sock, g_now_seconds + OT_CLIENT_TIMEOUT); + fdstate_set_expiry(sock, time_future_seconds(OT_CLIENT_TIMEOUT)); } else handle_dead(sock); } @@ -226,7 +225,7 @@ static void handle_accept(const int64_t serversocket) { memcpy(cookie->ip, ip, sizeof(ot_ip6)); cookie->interest = EVENT_IN; - if (event_add((int)sock, EVENT_IN, fdstate_open(sock, cookie, g_now_seconds + OT_CLIENT_TIMEOUT)) == -1) { + if (event_add((int)sock, EVENT_IN, fdstate_open(sock, cookie, time_future_seconds(OT_CLIENT_TIMEOUT))) == -1) { fdstate_close(sock); free(cookie); close((int)sock); @@ -242,7 +241,7 @@ static void handle_accept(const int64_t serversocket) { static void *server_mainloop(void *args) { struct ot_workstruct ws; - time_t next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL; + time_t next_timeout_check = time_future_seconds(OT_CLIENT_TIMEOUT_CHECKINTERVAL); struct iovec *iovector; size_t iovec_entries; int is_partial; @@ -461,17 +460,7 @@ int drop_privileges(const char *const serveruser, const char *const serverdir) { } /* Maintain our copy of the clock. time() on BSDs is very expensive. */ -static void *time_caching_worker(void *args) { - (void)args; - while (1) { - g_now_seconds = time(NULL); - sleep(5); - } - return NULL; -} - int main(int argc, char **argv) { - pthread_t thread_id; /* time cacher */ random_init(); if (fdstate_init() == -1) @@ -492,8 +481,6 @@ int main(int argc, char **argv) { if (drop_privileges(g_serveruser ? g_serveruser : "nobody", g_serverdir) == -1) panic("drop_privileges failed, exiting. Last error"); - g_now_seconds = time(NULL); - pthread_create(&thread_id, NULL, time_caching_worker, NULL); /* Create our self pipe which allows us to interrupt mainloops wait in case some data is available to send out */ diff --git a/ot_accesslist.c b/ot_accesslist.c index 4bf1701..e8e0476 100644 --- a/ot_accesslist.c +++ b/ot_accesslist.c @@ -93,7 +93,7 @@ static ot_accesslist *accesslist_make(ot_accesslist *next, size_t size) { This will never delete head, because that might still be in use. */ static void accesslist_clean(ot_accesslist *accesslist) { while (accesslist && accesslist->next) { - if (accesslist->next->base + 5 < g_now_minutes) + if (accesslist->next->base + 5 < time_now_minutes()) accesslist->next = accesslist_free(accesslist->next); accesslist = accesslist->next; } @@ -197,7 +197,7 @@ static void accesslist_readfile(void) { /* Mark old accesslist as "needs to live another five minutes" */ if (g_accesslist) - g_accesslist->base = g_now_minutes; + g_accesslist->base = time_now_minutes(); accesslist_new->next = g_accesslist; g_accesslist = accesslist_new; /* Only now set a new list */ @@ -205,11 +205,11 @@ static void accesslist_readfile(void) { /* If we have dynamic accesslists, reloading a new one will always void the add/delete lists. Insert empty ones at the list head */ if (g_accesslist_add && (accesslist_new = accesslist_make(g_accesslist_add, 0)) != NULL) { - g_accesslist_add->base = g_now_minutes; + g_accesslist_add->base = time_now_minutes(); g_accesslist_add = accesslist_new; } if (g_accesslist_delete && (accesslist_new = accesslist_make(g_accesslist_delete, 0)) != NULL) { - g_accesslist_delete->base = g_now_minutes; + g_accesslist_delete->base = time_now_minutes(); g_accesslist_delete = accesslist_new; } #endif @@ -326,7 +326,7 @@ static void *accesslist_adddel_worker(const char *fifoname, ot_accesslist *_ if (accesslist_new) { memcpy(accesslist_new->list, (*removing_from)->list, sizeof(ot_hash) * off); memcpy(accesslist_new->list + off, (*removing_from)->list + off + 1, sizeof(ot_hash) * ((*removing_from)->size - off - 1)); - (*removing_from)->base = g_now_minutes; + (*removing_from)->base = time_now_minutes(); *removing_from = accesslist_new; } } @@ -351,7 +351,7 @@ static void *accesslist_adddel_worker(const char *fifoname, ot_accesslist *_ memcpy(accesslist_new->list, (*adding_to)->list, sizeof(ot_hash) * off); memcpy(accesslist_new->list + off, info_hash, sizeof(info_hash)); memcpy(accesslist_new->list + off + 1, (*adding_to)->list + off, sizeof(ot_hash) * ((*adding_to)->size - off)); - (*adding_to)->base = g_now_minutes; + (*adding_to)->base = time_now_minutes(); *adding_to = accesslist_new; } } diff --git a/ot_clean.c b/ot_clean.c index bf0504c..dbfa04e 100644 --- a/ot_clean.c +++ b/ot_clean.c @@ -46,7 +46,7 @@ static ssize_t clean_single_bucket(ot_peer *peers, size_t peer_count, size_t pee int clean_single_peer_list(ot_peerlist *peer_list, size_t peer_size) { ot_vector *peer_vector = &peer_list->peers; - time_t timedout = (time_t)(g_now_minutes - peer_list->base); + time_t timedout = (time_t)(time_now_minutes() - peer_list->base); size_t num_buckets = 1, removed_seeders = 0; /* No need to clean empty torrent */ @@ -87,11 +87,11 @@ int clean_single_peer_list(ot_peerlist *peer_list, size_t peer_size) { vector_redistribute_buckets(peer_list, peer_size); if (peer_list->peer_count) - peer_list->base = g_now_minutes; + peer_list->base = time_now_minutes(); else { /* When we got here, the last time that torrent has been touched is OT_PEER_TIMEOUT Minutes before */ - peer_list->base = g_now_minutes - OT_PEER_TIMEOUT; + peer_list->base = time_now_minutes() - OT_PEER_TIMEOUT; } return 0; } diff --git a/ot_http.c b/ot_http.c index 2216453..c4f74db 100644 --- a/ot_http.c +++ b/ot_http.c @@ -222,7 +222,7 @@ ssize_t http_sendiovecdata(const int64_t sock, struct ot_workstruct *ws, size_t cookie->flag &= ~STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER; } - fdstate_set_expiry(sock, g_now_seconds + OT_CLIENT_TIMEOUT_SEND); + fdstate_set_expiry(sock, time_future_seconds(OT_CLIENT_TIMEOUT_SEND)); http_interest_add(sock, cookie, EVENT_OUT); return 0; } @@ -359,7 +359,7 @@ static ssize_t http_handle_fullscrape(const int64_t sock, struct ot_workstruct * ot_scrape_log this_peer, *new_peer; int exactmatch; memcpy(this_peer.ip, cookie->ip, sizeof(ot_ip6)); - this_peer.last_fullscrape = g_now_seconds; + this_peer.last_fullscrape = time_now_seconds(); pthread_mutex_lock(&g_modest_fullscrape_mutex); new_peer = vector_find_or_insert(&g_modest_fullscrape_timeouts, &this_peer, sizeof(ot_scrape_log), sizeof(ot_ip6), &exactmatch); if (!new_peer) { @@ -710,7 +710,7 @@ ssize_t http_handle_request(const int64_t sock, struct ot_workstruct *ws) { log->size = ws->request_size; log->data = malloc(ws->request_size); log->next = 0; - log->time = g_now_seconds; + log->time = time_now_seconds(); memcpy(log->ip, cookie->ip, sizeof(ot_ip6)); if (log->data) { memcpy(log->data, ws->request, ws->request_size); diff --git a/ot_livesync.c b/ot_livesync.c index 5a63f3c..fb0bef2 100644 --- a/ot_livesync.c +++ b/ot_livesync.c @@ -70,8 +70,8 @@ void livesync_init(void) { g_v6_buf.fill = sizeof(g_tracker_id) + sizeof(uint32_t); g_v4_buf.fill = sizeof(g_tracker_id) + sizeof(uint32_t); - g_v6_buf.next_packet_time = g_now_seconds + LIVESYNC_MAXDELAY; - g_v4_buf.next_packet_time = g_now_seconds + LIVESYNC_MAXDELAY; + g_v6_buf.next_packet_time = time_future_seconds(LIVESYNC_MAXDELAY); + g_v4_buf.next_packet_time = time_future_seconds(LIVESYNC_MAXDELAY); pthread_create(&thread_id, NULL, livesync_worker, NULL); } @@ -106,7 +106,7 @@ static void livesync_issue_peersync(sync_buffer *buf) { memcpy(mycopy, buf->data, fill); buf->fill = sizeof(g_tracker_id) + sizeof(uint32_t); - buf->next_packet_time = g_now_seconds + LIVESYNC_MAXDELAY; + buf->next_packet_time = time_future_seconds(LIVESYNC_MAXDELAY); /* From now this thread has a local copy of the buffer and has modified the protected element */ @@ -152,13 +152,13 @@ static void livesync_handle_peersync(struct ot_workstruct *ws, size_t peer_size) void livesync_ticker(void) { /* livesync_issue_peersync sets g_next_packet_time */ pthread_mutex_lock(&g_outbuf_mutex); - if (g_now_seconds > g_v6_buf.next_packet_time && g_v6_buf.fill > sizeof(g_tracker_id) + sizeof(uint32_t)) + if (time_now_seconds() > g_v6_buf.next_packet_time && g_v6_buf.fill > sizeof(g_tracker_id) + sizeof(uint32_t)) livesync_issue_peersync(&g_v6_buf); else pthread_mutex_unlock(&g_outbuf_mutex); pthread_mutex_lock(&g_outbuf_mutex); - if (g_now_seconds > g_v4_buf.next_packet_time && g_v4_buf.fill > sizeof(g_tracker_id) + sizeof(uint32_t)) + if (time_now_seconds() > g_v4_buf.next_packet_time && g_v4_buf.fill > sizeof(g_tracker_id) + sizeof(uint32_t)) livesync_issue_peersync(&g_v4_buf); else pthread_mutex_unlock(&g_outbuf_mutex); diff --git a/ot_stats.c b/ot_stats.c index 45dc8db..c6af116 100644 --- a/ot_stats.c +++ b/ot_stats.c @@ -739,7 +739,7 @@ void stats_deliver(int64_t sock, int tasktype) { mutex_workqueue_pushtask(sock, static pthread_t thread_id; void stats_init(void) { - ot_start_time = g_now_seconds; + ot_start_time = time_now_seconds(); pthread_create(&thread_id, NULL, stats_worker, NULL); } diff --git a/ot_udp.c b/ot_udp.c index 4e760bb..19a6c7c 100644 --- a/ot_udp.c +++ b/ot_udp.c @@ -30,7 +30,7 @@ static void udp_generate_rijndael_round_key(void) { rijndaelKeySetupEnc128(g_rijndael_round_key, (uint8_t *)key); g_key_of_the_hour[0] = random_uint32(); - g_hour_of_the_key = g_now_minutes; + g_hour_of_the_key = time_now_minutes(); } /* Generate current and previous connection id for ip */ @@ -39,14 +39,14 @@ static void udp_make_connectionid(uint32_t connid[2], const ot_ip6 remoteip, int int i; uint32_t current_key_of_the_hour; - if (g_now_minutes - g_hour_of_the_key >= 60) { + if (time_now_minutes() - g_hour_of_the_key >= 60) { uint32_t old_key_of_the_hour = g_key_of_the_hour[0]; uint32_t new_key_of_the_hour = random_uint32(); /* If in the meantime another thread has performed key rotation, do not overwrite their results */ - if (g_now_minutes - g_hour_of_the_key >= 60) { + if (time_now_minutes() - g_hour_of_the_key >= 60) { /* Upgrade en bloc */ - g_hour_of_the_key = g_now_minutes; + g_hour_of_the_key = time_now_minutes(); g_key_of_the_hour[0] = new_key_of_the_hour; g_key_of_the_hour[1] = old_key_of_the_hour; } diff --git a/tests/stubs.c b/tests/stubs.c index 09a7312..a8e6962 100644 --- a/tests/stubs.c +++ b/tests/stubs.c @@ -16,8 +16,7 @@ void free_peerlist(ot_peerlist *peer_list) { (void)peer_list; } /* ot_accesslist.c is built with WANT_ACCESSLIST_BLACK so that the hash parser is reachable. These two belong to accesslist_readfile and the reload worker, neither of which any test drives. */ -time_t g_now_seconds; -volatile int g_opentracker_running; +_Atomic int g_opentracker_running; /* ot_mutex.c wakes the main loop through the self pipe when a result is ready. The queue tests never get that far. */ diff --git a/trackerlogic.c b/trackerlogic.c index 1f38f07..aac4448 100644 --- a/trackerlogic.c +++ b/trackerlogic.c @@ -117,8 +117,8 @@ size_t add_peer_to_torrent_and_return_peers(PROTO_FLAG proto, struct ot_workstru } else clean_single_torrent(torrent); - torrent->peer_list6->base = g_now_minutes; - torrent->peer_list4->base = g_now_minutes; + torrent->peer_list6->base = time_now_minutes(); + torrent->peer_list4->base = time_now_minutes(); peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4; diff --git a/trackerlogic.h b/trackerlogic.h index 63abf78..6af5d6a 100644 --- a/trackerlogic.h +++ b/trackerlogic.h @@ -6,6 +6,7 @@ #ifndef OT_TRACKERLOGIC_H__ #define OT_TRACKERLOGIC_H__ +#include #include #include #include @@ -68,9 +69,31 @@ typedef struct { #define RANDOMTORRENTS (1024 * 1024 * 1) /* From opentracker.c */ -extern time_t g_now_seconds; -extern volatile int g_opentracker_running; -#define g_now_minutes (g_now_seconds / 60) +/* The kernel already keeps a coarse wall clock, updated every tick and + published where reading it costs no system call. That is what opentracker + used to keep a thread for, at five second resolution. */ +#if defined(CLOCK_REALTIME_COARSE) +#define OT_CLOCK_CHEAP CLOCK_REALTIME_COARSE /* Linux */ +#elif defined(CLOCK_REALTIME_FAST) +#define OT_CLOCK_CHEAP CLOCK_REALTIME_FAST /* the BSDs */ +#else +#define OT_CLOCK_CHEAP CLOCK_REALTIME /* macOS and whatever else */ +#endif + +static inline ot_time time_now_seconds(void) { + struct timespec now; + clock_gettime(OT_CLOCK_CHEAP, &now); + return (ot_time)now.tv_sec; +} + +static inline ot_time time_now_minutes(void) { return time_now_seconds() / 60; } + +/* For the deadlines the tracker sets on itself, which read better as the + span they allow than as an addition to the current second */ +static inline ot_time time_future_seconds(int span) { return time_now_seconds() + span; } +/* Cleared from the interrupt handler and read by every worker */ +extern _Atomic int g_opentracker_running; + extern uint32_t g_tracker_id; typedef enum { FLAG_TCP, FLAG_UDP, FLAG_MCA, FLAG_SELFPIPE } PROTO_FLAG; -- cgit v1.3