diff options
Diffstat (limited to 'ot_mutex.c')
| -rw-r--r-- | ot_mutex.c | 25 |
1 files changed, 20 insertions, 5 deletions
| @@ -6,6 +6,7 @@ | |||
| 6 | /* System */ | 6 | /* System */ |
| 7 | #include <arpa/inet.h> | 7 | #include <arpa/inet.h> |
| 8 | #include <pthread.h> | 8 | #include <pthread.h> |
| 9 | #include <stdatomic.h> | ||
| 9 | #include <stdio.h> | 10 | #include <stdio.h> |
| 10 | #include <stdlib.h> | 11 | #include <stdlib.h> |
| 11 | #include <unistd.h> | 12 | #include <unistd.h> |
| @@ -25,7 +26,9 @@ | |||
| 25 | /* Our global all torrents list */ | 26 | /* Our global all torrents list */ |
| 26 | static ot_vector all_torrents[OT_BUCKET_COUNT]; | 27 | static ot_vector all_torrents[OT_BUCKET_COUNT]; |
| 27 | static pthread_mutex_t bucket_mutex[OT_BUCKET_COUNT]; | 28 | static pthread_mutex_t bucket_mutex[OT_BUCKET_COUNT]; |
| 28 | static size_t g_torrent_count; | 29 | /* Every bucket's unlock adjusts this, and a bucket lock only keeps other |
| 30 | threads out of that one bucket, so the counter needs its own protection */ | ||
| 31 | static _Atomic size_t g_torrent_count; | ||
| 29 | 32 | ||
| 30 | /* Self pipe from opentracker.c */ | 33 | /* Self pipe from opentracker.c */ |
| 31 | extern int g_self_pipe[2]; | 34 | extern int g_self_pipe[2]; |
| @@ -47,14 +50,15 @@ ot_vector *mutex_bucket_lock_by_hash(ot_hash const hash) { return mutex_bucket_l | |||
| 47 | 50 | ||
| 48 | void mutex_bucket_unlock(int bucket, int delta_torrentcount) { | 51 | void mutex_bucket_unlock(int bucket, int delta_torrentcount) { |
| 49 | pthread_mutex_unlock(bucket_mutex + bucket); | 52 | pthread_mutex_unlock(bucket_mutex + bucket); |
| 50 | g_torrent_count += delta_torrentcount; | 53 | if (delta_torrentcount) |
| 54 | atomic_fetch_add_explicit(&g_torrent_count, (size_t)delta_torrentcount, memory_order_relaxed); | ||
| 51 | } | 55 | } |
| 52 | 56 | ||
| 53 | void mutex_bucket_unlock_by_hash(ot_hash const hash, int delta_torrentcount) { | 57 | void mutex_bucket_unlock_by_hash(ot_hash const hash, int delta_torrentcount) { |
| 54 | mutex_bucket_unlock(bucket_from_hash(hash), delta_torrentcount); | 58 | mutex_bucket_unlock(bucket_from_hash(hash), delta_torrentcount); |
| 55 | } | 59 | } |
| 56 | 60 | ||
| 57 | size_t mutex_get_torrent_count(void) { return g_torrent_count; } | 61 | size_t mutex_get_torrent_count(void) { return atomic_load_explicit(&g_torrent_count, memory_order_relaxed); } |
| 58 | 62 | ||
| 59 | /* TaskQueue Magic */ | 63 | /* TaskQueue Magic */ |
| 60 | 64 | ||
| @@ -145,9 +149,13 @@ ot_taskid mutex_workqueue_poptask(ot_tasktype *tasktype) { | |||
| 145 | break; | 149 | break; |
| 146 | } | 150 | } |
| 147 | 151 | ||
| 148 | /* Wait until the next task is being fed */ | 152 | /* Wait until the next task is being fed, unless the tracker is on its |
| 149 | if (!taskid) | 153 | way out, in which case the worker is meant to leave rather than wait */ |
| 154 | if (!taskid) { | ||
| 155 | if (!g_opentracker_running) | ||
| 156 | break; | ||
| 150 | pthread_cond_wait(&tasklist_being_filled, &tasklist_mutex); | 157 | pthread_cond_wait(&tasklist_being_filled, &tasklist_mutex); |
| 158 | } | ||
| 151 | } | 159 | } |
| 152 | 160 | ||
| 153 | /* Release lock */ | 161 | /* Release lock */ |
| @@ -271,6 +279,13 @@ void mutex_init(void) { | |||
| 271 | memset(all_torrents, 0, sizeof(all_torrents)); | 279 | memset(all_torrents, 0, sizeof(all_torrents)); |
| 272 | } | 280 | } |
| 273 | 281 | ||
| 282 | /* Let every worker parked on the queue see that the tracker is stopping */ | ||
| 283 | void mutex_workqueue_wakeall(void) { | ||
| 284 | pthread_mutex_lock(&tasklist_mutex); | ||
| 285 | pthread_cond_broadcast(&tasklist_being_filled); | ||
| 286 | pthread_mutex_unlock(&tasklist_mutex); | ||
| 287 | } | ||
| 288 | |||
| 274 | void mutex_deinit(void) { | 289 | void mutex_deinit(void) { |
| 275 | size_t i; | 290 | size_t i; |
| 276 | for (i = 0; i < OT_BUCKET_COUNT; ++i) | 291 | for (i = 0; i < OT_BUCKET_COUNT; ++i) |
