/* This software was written by Dirk Engling It is considered beerware. Prost. Skol. Cheers or whatever. $id$ */ /* System */ #include #include #include #include #include #include #include #include /* Opentracker */ #include "ot_iovec.h" #include "ot_mutex.h" #include "ot_stats.h" #include "trackerlogic.h" /* #define MTX_DBG( STRING ) fprintf( stderr, STRING ) */ #define MTX_DBG(STRING) /* Our global all torrents list */ static ot_vector all_torrents[OT_BUCKET_COUNT]; static pthread_mutex_t bucket_mutex[OT_BUCKET_COUNT]; /* Every bucket's unlock adjusts this, and a bucket lock only keeps other threads out of that one bucket, so the counter needs its own protection */ static _Atomic size_t g_torrent_count; /* Self pipe from opentracker.c */ ot_vector *mutex_bucket_lock(int bucket) { pthread_mutex_lock(bucket_mutex + bucket); return all_torrents + bucket; } /* Torrents are spread over buckets by the first four bytes of their info_hash, which may sit at any alignment, hence the memcpy */ static int bucket_from_hash(ot_hash const hash) { uint32_t bucket; memcpy(&bucket, hash, sizeof(bucket)); return ntohl(bucket) >> OT_BUCKET_COUNT_SHIFT; } ot_vector *mutex_bucket_lock_by_hash(ot_hash const hash) { return mutex_bucket_lock(bucket_from_hash(hash)); } void mutex_bucket_unlock(int bucket, int delta_torrentcount) { pthread_mutex_unlock(bucket_mutex + bucket); if (delta_torrentcount) atomic_fetch_add_explicit(&g_torrent_count, (size_t)delta_torrentcount, memory_order_relaxed); } void mutex_bucket_unlock_by_hash(ot_hash const hash, int delta_torrentcount) { mutex_bucket_unlock(bucket_from_hash(hash), delta_torrentcount); } size_t mutex_get_torrent_count(void) { return atomic_load_explicit(&g_torrent_count, memory_order_relaxed); } void mutex_init(void) { size_t i; for (i = 0; i < OT_BUCKET_COUNT; ++i) pthread_mutex_init(bucket_mutex + i, NULL); memset(all_torrents, 0, sizeof(all_torrents)); } /* Let every worker parked on the queue see that the tracker is stopping */ void mutex_deinit(void) { size_t i; for (i = 0; i < OT_BUCKET_COUNT; ++i) pthread_mutex_destroy(bucket_mutex + i); memset(all_torrents, 0, sizeof(all_torrents)); }