Download mosesdecoder/contrib/lmserver/thread.c from suricodes/hindi-sindhi-docker: direct link, hf CLI and curl.
- Browser
- Download file 16.4 kB
-
https://huggingface.co/spaces/suricodes/hindi-sindhi-docker/resolve/main/mosesdecoder/contrib/lmserver/thread.c
- Command line
-
hf download hf://spaces/suricodes/hindi-sindhi-docker/mosesdecoder/contrib/lmserver/thread.c
-
curl -L -o thread.c https://huggingface.co/spaces/suricodes/hindi-sindhi-docker/resolve/main/mosesdecoder/contrib/lmserver/thread.c
16.4 kB
| /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ | |
| /* | |
| * Thread management for memcached. | |
| * | |
| * $Id$ | |
| */ | |
| /* An item in the connection queue. */ | |
| typedef struct conn_queue_item CQ_ITEM; | |
| struct conn_queue_item { | |
| int sfd; | |
| int init_state; | |
| int event_flags; | |
| int read_buffer_size; | |
| int is_udp; | |
| CQ_ITEM *next; | |
| }; | |
| /* A connection queue. */ | |
| typedef struct conn_queue CQ; | |
| struct conn_queue { | |
| CQ_ITEM *head; | |
| CQ_ITEM *tail; | |
| pthread_mutex_t lock; | |
| pthread_cond_t cond; | |
| }; | |
| /* Lock for connection freelist */ | |
| static pthread_mutex_t conn_lock; | |
| /* Lock for alternative item suffix freelist */ | |
| static pthread_mutex_t suffix_lock; | |
| /* Lock for cache operations (item_*, assoc_*) */ | |
| static pthread_mutex_t cache_lock; | |
| /* Lock for slab allocator operations */ | |
| static pthread_mutex_t slabs_lock; | |
| /* Lock for global stats */ | |
| static pthread_mutex_t stats_lock; | |
| /* Free list of CQ_ITEM structs */ | |
| static CQ_ITEM *cqi_freelist; | |
| static pthread_mutex_t cqi_freelist_lock; | |
| /* | |
| * Each libevent instance has a wakeup pipe, which other threads | |
| * can use to signal that they've put a new connection on its queue. | |
| */ | |
| typedef struct { | |
| pthread_t thread_id; /* unique ID of this thread */ | |
| struct event_base *base; /* libevent handle this thread uses */ | |
| struct event notify_event; /* listen event for notify pipe */ | |
| int notify_receive_fd; /* receiving end of notify pipe */ | |
| int notify_send_fd; /* sending end of notify pipe */ | |
| CQ new_conn_queue; /* queue of new connections to handle */ | |
| } LIBEVENT_THREAD; | |
| static LIBEVENT_THREAD *threads; | |
| /* | |
| * Number of threads that have finished setting themselves up. | |
| */ | |
| static int init_count = 0; | |
| static pthread_mutex_t init_lock; | |
| static pthread_cond_t init_cond; | |
| static void thread_libevent_process(int fd, short which, void *arg); | |
| /* | |
| * Initializes a connection queue. | |
| */ | |
| static void cq_init(CQ *cq) { | |
| pthread_mutex_init(&cq->lock, NULL); | |
| pthread_cond_init(&cq->cond, NULL); | |
| cq->head = NULL; | |
| cq->tail = NULL; | |
| } | |
| /* | |
| * Waits for work on a connection queue. | |
| */ | |
| static CQ_ITEM *cq_pop(CQ *cq) { | |
| CQ_ITEM *item; | |
| pthread_mutex_lock(&cq->lock); | |
| while (NULL == cq->head) | |
| pthread_cond_wait(&cq->cond, &cq->lock); | |
| item = cq->head; | |
| cq->head = item->next; | |
| if (NULL == cq->head) | |
| cq->tail = NULL; | |
| pthread_mutex_unlock(&cq->lock); | |
| return item; | |
| } | |
| /* | |
| * Looks for an item on a connection queue, but doesn't block if there isn't | |
| * one. | |
| * Returns the item, or NULL if no item is available | |
| */ | |
| static CQ_ITEM *cq_peek(CQ *cq) { | |
| CQ_ITEM *item; | |
| pthread_mutex_lock(&cq->lock); | |
| item = cq->head; | |
| if (NULL != item) { | |
| cq->head = item->next; | |
| if (NULL == cq->head) | |
| cq->tail = NULL; | |
| } | |
| pthread_mutex_unlock(&cq->lock); | |
| return item; | |
| } | |
| /* | |
| * Adds an item to a connection queue. | |
| */ | |
| static void cq_push(CQ *cq, CQ_ITEM *item) { | |
| item->next = NULL; | |
| pthread_mutex_lock(&cq->lock); | |
| if (NULL == cq->tail) | |
| cq->head = item; | |
| else | |
| cq->tail->next = item; | |
| cq->tail = item; | |
| pthread_cond_signal(&cq->cond); | |
| pthread_mutex_unlock(&cq->lock); | |
| } | |
| /* | |
| * Returns a fresh connection queue item. | |
| */ | |
| static CQ_ITEM *cqi_new() { | |
| CQ_ITEM *item = NULL; | |
| pthread_mutex_lock(&cqi_freelist_lock); | |
| if (cqi_freelist) { | |
| item = cqi_freelist; | |
| cqi_freelist = item->next; | |
| } | |
| pthread_mutex_unlock(&cqi_freelist_lock); | |
| if (NULL == item) { | |
| int i; | |
| /* Allocate a bunch of items at once to reduce fragmentation */ | |
| item = malloc(sizeof(CQ_ITEM) * ITEMS_PER_ALLOC); | |
| if (NULL == item) | |
| return NULL; | |
| /* | |
| * Link together all the new items except the first one | |
| * (which we'll return to the caller) for placement on | |
| * the freelist. | |
| */ | |
| for (i = 2; i < ITEMS_PER_ALLOC; i++) | |
| item[i - 1].next = &item[i]; | |
| pthread_mutex_lock(&cqi_freelist_lock); | |
| item[ITEMS_PER_ALLOC - 1].next = cqi_freelist; | |
| cqi_freelist = &item[1]; | |
| pthread_mutex_unlock(&cqi_freelist_lock); | |
| } | |
| return item; | |
| } | |
| /* | |
| * Frees a connection queue item (adds it to the freelist.) | |
| */ | |
| static void cqi_free(CQ_ITEM *item) { | |
| pthread_mutex_lock(&cqi_freelist_lock); | |
| item->next = cqi_freelist; | |
| cqi_freelist = item; | |
| pthread_mutex_unlock(&cqi_freelist_lock); | |
| } | |
| /* | |
| * Creates a worker thread. | |
| */ | |
| static void create_worker(void *(*func)(void *), void *arg) { | |
| pthread_t thread; | |
| pthread_attr_t attr; | |
| int ret; | |
| pthread_attr_init(&attr); | |
| if ((ret = pthread_create(&thread, &attr, func, arg)) != 0) { | |
| fprintf(stderr, "Can't create thread: %s\n", | |
| strerror(ret)); | |
| exit(1); | |
| } | |
| } | |
| /* | |
| * Pulls a conn structure from the freelist, if one is available. | |
| */ | |
| conn *mt_conn_from_freelist() { | |
| conn *c; | |
| pthread_mutex_lock(&conn_lock); | |
| c = do_conn_from_freelist(); | |
| pthread_mutex_unlock(&conn_lock); | |
| return c; | |
| } | |
| /* | |
| * Adds a conn structure to the freelist. | |
| * | |
| * Returns 0 on success, 1 if the structure couldn't be added. | |
| */ | |
| bool mt_conn_add_to_freelist(conn *c) { | |
| bool result; | |
| pthread_mutex_lock(&conn_lock); | |
| result = do_conn_add_to_freelist(c); | |
| pthread_mutex_unlock(&conn_lock); | |
| return result; | |
| } | |
| /* | |
| * Pulls a suffix buffer from the freelist, if one is available. | |
| */ | |
| char *mt_suffix_from_freelist() { | |
| char *s; | |
| pthread_mutex_lock(&suffix_lock); | |
| s = do_suffix_from_freelist(); | |
| pthread_mutex_unlock(&suffix_lock); | |
| return s; | |
| } | |
| /* | |
| * Adds a suffix buffer to the freelist. | |
| * | |
| * Returns 0 on success, 1 if the buffer couldn't be added. | |
| */ | |
| bool mt_suffix_add_to_freelist(char *s) { | |
| bool result; | |
| pthread_mutex_lock(&suffix_lock); | |
| result = do_suffix_add_to_freelist(s); | |
| pthread_mutex_unlock(&suffix_lock); | |
| return result; | |
| } | |
| /****************************** LIBEVENT THREADS *****************************/ | |
| /* | |
| * Set up a thread's information. | |
| */ | |
| static void setup_thread(LIBEVENT_THREAD *me) { | |
| if (! me->base) { | |
| me->base = event_init(); | |
| if (! me->base) { | |
| fprintf(stderr, "Can't allocate event base\n"); | |
| exit(1); | |
| } | |
| } | |
| /* Listen for notifications from other threads */ | |
| event_set(&me->notify_event, me->notify_receive_fd, | |
| EV_READ | EV_PERSIST, thread_libevent_process, me); | |
| event_base_set(me->base, &me->notify_event); | |
| if (event_add(&me->notify_event, 0) == -1) { | |
| fprintf(stderr, "Can't monitor libevent notify pipe\n"); | |
| exit(1); | |
| } | |
| cq_init(&me->new_conn_queue); | |
| } | |
| /* | |
| * Worker thread: main event loop | |
| */ | |
| static void *worker_libevent(void *arg) { | |
| LIBEVENT_THREAD *me = arg; | |
| /* Any per-thread setup can happen here; thread_init() will block until | |
| * all threads have finished initializing. | |
| */ | |
| pthread_mutex_lock(&init_lock); | |
| init_count++; | |
| pthread_cond_signal(&init_cond); | |
| pthread_mutex_unlock(&init_lock); | |
| return (void*) event_base_loop(me->base, 0); | |
| } | |
| /* | |
| * Processes an incoming "handle a new connection" item. This is called when | |
| * input arrives on the libevent wakeup pipe. | |
| */ | |
| static void thread_libevent_process(int fd, short which, void *arg) { | |
| LIBEVENT_THREAD *me = arg; | |
| CQ_ITEM *item; | |
| char buf[1]; | |
| if (read(fd, buf, 1) != 1) | |
| if (settings.verbose > 0) | |
| fprintf(stderr, "Can't read from libevent pipe\n"); | |
| item = cq_peek(&me->new_conn_queue); | |
| if (NULL != item) { | |
| conn *c = conn_new(item->sfd, item->init_state, item->event_flags, | |
| item->read_buffer_size, item->is_udp, me->base); | |
| if (c == NULL) { | |
| if (item->is_udp) { | |
| fprintf(stderr, "Can't listen for events on UDP socket\n"); | |
| exit(1); | |
| } else { | |
| if (settings.verbose > 0) { | |
| fprintf(stderr, "Can't listen for events on fd %d\n", | |
| item->sfd); | |
| } | |
| close(item->sfd); | |
| } | |
| } | |
| cqi_free(item); | |
| } | |
| } | |
| /* Which thread we assigned a connection to most recently. */ | |
| static int last_thread = -1; | |
| /* | |
| * Dispatches a new connection to another thread. This is only ever called | |
| * from the main thread, either during initialization (for UDP) or because | |
| * of an incoming connection. | |
| */ | |
| void dispatch_conn_new(int sfd, int init_state, int event_flags, | |
| int read_buffer_size, int is_udp) { | |
| CQ_ITEM *item = cqi_new(); | |
| int thread = (last_thread + 1) % settings.num_threads; | |
| last_thread = thread; | |
| item->sfd = sfd; | |
| item->init_state = init_state; | |
| item->event_flags = event_flags; | |
| item->read_buffer_size = read_buffer_size; | |
| item->is_udp = is_udp; | |
| cq_push(&threads[thread].new_conn_queue, item); | |
| MEMCACHED_CONN_DISPATCH(sfd, threads[thread].thread_id); | |
| if (write(threads[thread].notify_send_fd, "", 1) != 1) { | |
| perror("Writing to thread notify pipe"); | |
| } | |
| } | |
| /* | |
| * Returns true if this is the thread that listens for new TCP connections. | |
| */ | |
| int mt_is_listen_thread() { | |
| return pthread_self() == threads[0].thread_id; | |
| } | |
| /********************************* ITEM ACCESS *******************************/ | |
| /* | |
| * Walks through the list of deletes that have been deferred because the items | |
| * were locked down at the tmie. | |
| */ | |
| void mt_run_deferred_deletes() { | |
| pthread_mutex_lock(&cache_lock); | |
| do_run_deferred_deletes(); | |
| pthread_mutex_unlock(&cache_lock); | |
| } | |
| /* | |
| * Allocates a new item. | |
| */ | |
| item *mt_item_alloc(char *key, size_t nkey, int flags, rel_time_t exptime, int nbytes) { | |
| item *it; | |
| pthread_mutex_lock(&cache_lock); | |
| it = do_item_alloc(key, nkey, flags, exptime, nbytes); | |
| pthread_mutex_unlock(&cache_lock); | |
| return it; | |
| } | |
| /* | |
| * Returns an item if it hasn't been marked as expired or deleted, | |
| * lazy-expiring as needed. | |
| */ | |
| item *mt_item_get_notedeleted(const char *key, const size_t nkey, bool *delete_locked) { | |
| item *it; | |
| pthread_mutex_lock(&cache_lock); | |
| it = do_item_get_notedeleted(key, nkey, delete_locked); | |
| pthread_mutex_unlock(&cache_lock); | |
| return it; | |
| } | |
| /* | |
| * Links an item into the LRU and hashtable. | |
| */ | |
| int mt_item_link(item *item) { | |
| int ret; | |
| pthread_mutex_lock(&cache_lock); | |
| ret = do_item_link(item); | |
| pthread_mutex_unlock(&cache_lock); | |
| return ret; | |
| } | |
| /* | |
| * Decrements the reference count on an item and adds it to the freelist if | |
| * needed. | |
| */ | |
| void mt_item_remove(item *item) { | |
| pthread_mutex_lock(&cache_lock); | |
| do_item_remove(item); | |
| pthread_mutex_unlock(&cache_lock); | |
| } | |
| /* | |
| * Replaces one item with another in the hashtable. | |
| */ | |
| int mt_item_replace(item *old, item *new) { | |
| int ret; | |
| pthread_mutex_lock(&cache_lock); | |
| ret = do_item_replace(old, new); | |
| pthread_mutex_unlock(&cache_lock); | |
| return ret; | |
| } | |
| /* | |
| * Unlinks an item from the LRU and hashtable. | |
| */ | |
| void mt_item_unlink(item *item) { | |
| pthread_mutex_lock(&cache_lock); | |
| do_item_unlink(item); | |
| pthread_mutex_unlock(&cache_lock); | |
| } | |
| /* | |
| * Moves an item to the back of the LRU queue. | |
| */ | |
| void mt_item_update(item *item) { | |
| pthread_mutex_lock(&cache_lock); | |
| do_item_update(item); | |
| pthread_mutex_unlock(&cache_lock); | |
| } | |
| /* | |
| * Adds an item to the deferred-delete list so it can be reaped later. | |
| */ | |
| char *mt_defer_delete(item *item, time_t exptime) { | |
| char *ret; | |
| pthread_mutex_lock(&cache_lock); | |
| ret = do_defer_delete(item, exptime); | |
| pthread_mutex_unlock(&cache_lock); | |
| return ret; | |
| } | |
| /* | |
| * Does arithmetic on a numeric item value. | |
| */ | |
| char *mt_add_delta(conn *c, item *item, int incr, const int64_t delta, | |
| char *buf) { | |
| char *ret; | |
| pthread_mutex_lock(&cache_lock); | |
| ret = do_add_delta(c, item, incr, delta, buf); | |
| pthread_mutex_unlock(&cache_lock); | |
| return ret; | |
| } | |
| /* | |
| * Stores an item in the cache (high level, obeys set/add/replace semantics) | |
| */ | |
| int mt_store_item(item *item, int comm) { | |
| int ret; | |
| pthread_mutex_lock(&cache_lock); | |
| ret = do_store_item(item, comm); | |
| pthread_mutex_unlock(&cache_lock); | |
| return ret; | |
| } | |
| /* | |
| * Flushes expired items after a flush_all call | |
| */ | |
| void mt_item_flush_expired() { | |
| pthread_mutex_lock(&cache_lock); | |
| do_item_flush_expired(); | |
| pthread_mutex_unlock(&cache_lock); | |
| } | |
| /* | |
| * Dumps part of the cache | |
| */ | |
| char *mt_item_cachedump(unsigned int slabs_clsid, unsigned int limit, unsigned int *bytes) { | |
| char *ret; | |
| pthread_mutex_lock(&cache_lock); | |
| ret = do_item_cachedump(slabs_clsid, limit, bytes); | |
| pthread_mutex_unlock(&cache_lock); | |
| return ret; | |
| } | |
| /* | |
| * Dumps statistics about slab classes | |
| */ | |
| char *mt_item_stats(int *bytes) { | |
| char *ret; | |
| pthread_mutex_lock(&cache_lock); | |
| ret = do_item_stats(bytes); | |
| pthread_mutex_unlock(&cache_lock); | |
| return ret; | |
| } | |
| /* | |
| * Dumps a list of objects of each size in 32-byte increments | |
| */ | |
| char *mt_item_stats_sizes(int *bytes) { | |
| char *ret; | |
| pthread_mutex_lock(&cache_lock); | |
| ret = do_item_stats_sizes(bytes); | |
| pthread_mutex_unlock(&cache_lock); | |
| return ret; | |
| } | |
| /****************************** HASHTABLE MODULE *****************************/ | |
| void mt_assoc_move_next_bucket() { | |
| pthread_mutex_lock(&cache_lock); | |
| do_assoc_move_next_bucket(); | |
| pthread_mutex_unlock(&cache_lock); | |
| } | |
| /******************************* SLAB ALLOCATOR ******************************/ | |
| void *mt_slabs_alloc(size_t size, unsigned int id) { | |
| void *ret; | |
| pthread_mutex_lock(&slabs_lock); | |
| ret = do_slabs_alloc(size, id); | |
| pthread_mutex_unlock(&slabs_lock); | |
| return ret; | |
| } | |
| void mt_slabs_free(void *ptr, size_t size, unsigned int id) { | |
| pthread_mutex_lock(&slabs_lock); | |
| do_slabs_free(ptr, size, id); | |
| pthread_mutex_unlock(&slabs_lock); | |
| } | |
| char *mt_slabs_stats(int *buflen) { | |
| char *ret; | |
| pthread_mutex_lock(&slabs_lock); | |
| ret = do_slabs_stats(buflen); | |
| pthread_mutex_unlock(&slabs_lock); | |
| return ret; | |
| } | |
| int mt_slabs_reassign(unsigned char srcid, unsigned char dstid) { | |
| int ret; | |
| pthread_mutex_lock(&slabs_lock); | |
| ret = do_slabs_reassign(srcid, dstid); | |
| pthread_mutex_unlock(&slabs_lock); | |
| return ret; | |
| } | |
| /******************************* GLOBAL STATS ******************************/ | |
| void mt_stats_lock() { | |
| pthread_mutex_lock(&stats_lock); | |
| } | |
| void mt_stats_unlock() { | |
| pthread_mutex_unlock(&stats_lock); | |
| } | |
| /* | |
| * Initializes the thread subsystem, creating various worker threads. | |
| * | |
| * nthreads Number of event handler threads to spawn | |
| * main_base Event base for main thread | |
| */ | |
| void thread_init(int nthreads, struct event_base *main_base) { | |
| int i; | |
| pthread_mutex_init(&cache_lock, NULL); | |
| pthread_mutex_init(&conn_lock, NULL); | |
| pthread_mutex_init(&slabs_lock, NULL); | |
| pthread_mutex_init(&stats_lock, NULL); | |
| pthread_mutex_init(&init_lock, NULL); | |
| pthread_cond_init(&init_cond, NULL); | |
| pthread_mutex_init(&cqi_freelist_lock, NULL); | |
| cqi_freelist = NULL; | |
| threads = malloc(sizeof(LIBEVENT_THREAD) * nthreads); | |
| if (! threads) { | |
| perror("Can't allocate thread descriptors"); | |
| exit(1); | |
| } | |
| threads[0].base = main_base; | |
| threads[0].thread_id = pthread_self(); | |
| for (i = 0; i < nthreads; i++) { | |
| int fds[2]; | |
| if (pipe(fds)) { | |
| perror("Can't create notify pipe"); | |
| exit(1); | |
| } | |
| threads[i].notify_receive_fd = fds[0]; | |
| threads[i].notify_send_fd = fds[1]; | |
| setup_thread(&threads[i]); | |
| } | |
| /* Create threads after we've done all the libevent setup. */ | |
| for (i = 1; i < nthreads; i++) { | |
| create_worker(worker_libevent, &threads[i]); | |
| } | |
| /* Wait for all the threads to set themselves up before returning. */ | |
| pthread_mutex_lock(&init_lock); | |
| init_count++; /* main thread */ | |
| while (init_count < nthreads) { | |
| pthread_cond_wait(&init_cond, &init_lock); | |
| } | |
| pthread_mutex_unlock(&init_lock); | |
| } | |