/*1* Copyright 2016 Jakub Klama <[email protected]>2* All rights reserved3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted providing that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12*13* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR14* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED15* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE16* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY17* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL18* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS19* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)20* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,21* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING22* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE23* POSSIBILITY OF SUCH DAMAGE.24*25*/2627#ifndef LIB9P_THREADPOOL_H28#define LIB9P_THREADPOOL_H2930#include <stdbool.h>31#include <pthread.h>32#include <sys/queue.h>33#include "lib9p.h"3435STAILQ_HEAD(l9p_request_queue, l9p_request);3637/*38* Most of the workers in the threadpool run requests.39*40* One distinguished worker delivers responses from the41* response queue. The reason this worker exists is to42* guarantee response order, so that flush responses go43* after their flushed requests.44*/45struct l9p_threadpool {46struct l9p_connection * ltp_conn; /* the connection */47struct l9p_request_queue ltp_workq; /* requests awaiting a worker */48struct l9p_request_queue ltp_replyq; /* requests that are done */49pthread_mutex_t ltp_mtx; /* locks queues and cond vars */50pthread_cond_t ltp_work_cv; /* to signal regular workers */51pthread_cond_t ltp_reply_cv; /* to signal reply-worker */52LIST_HEAD(, l9p_worker) ltp_workers; /* list of all workers */53};5455/*56* All workers, including the responder, use this as their57* control structure. (The only thing that distinguishes the58* responder is that it runs different code and waits on the59* reply_cv.)60*/61struct l9p_worker {62struct l9p_threadpool * ltw_tp;63pthread_t ltw_thread;64bool ltw_exiting;65bool ltw_responder;66LIST_ENTRY(l9p_worker) ltw_link;67};6869/*70* Each request has a "work state" telling where the request is,71* in terms of workers working on it. That is, this tells us72* which threadpool queue, if any, the request is in now or would73* go in, or what's happening with it.74*/75enum l9p_workstate {76L9P_WS_NOTSTARTED, /* not yet started */77L9P_WS_IMMEDIATE, /* Tflush being done sans worker */78L9P_WS_INPROGRESS, /* worker is working on it */79L9P_WS_RESPQUEUED, /* worker is done, response queued */80L9P_WS_REPLYING, /* responder is in final reply path */81};8283/*84* Each request has a "flush state", initally NONE meaning no85* Tflush affected the request.86*87* If a Tflush comes in before we ever assign a work thread,88* the flush state goes to FLUSH_REQUESTED_PRE_START.89*90* If a Tflush comes in after we assign a work thread, the91* flush state goes to FLUSH_REQUESTED_POST_START. The flush92* request may be too late: the request might finish anyway.93* Or it might be soon enough to abort. In all cases, though, the94* operation requesting the flush (the "flusher") must wait for95* the other request (the "flushee") to go through the respond96* path. The respond routine gets to decide whether to send a97* normal response, send an error, or drop the request98* entirely.99*100* There's one especially annoying case: what if a Tflush comes in101* *while* we're sending a response? In this case it's too late:102* the flush just waits for the fully-composed response.103*/104enum l9p_flushstate {105L9P_FLUSH_NONE = 0, /* must be zero */106L9P_FLUSH_REQUESTED_PRE_START, /* not even started before flush */107L9P_FLUSH_REQUESTED_POST_START, /* started, then someone said flush */108L9P_FLUSH_TOOLATE /* too late, already responding */109};110111void l9p_threadpool_flushee_done(struct l9p_request *);112int l9p_threadpool_init(struct l9p_threadpool *, int);113void l9p_threadpool_run(struct l9p_threadpool *, struct l9p_request *);114int l9p_threadpool_shutdown(struct l9p_threadpool *);115int l9p_threadpool_tflush(struct l9p_request *);116117#endif /* LIB9P_THREADPOOL_H */118119120