1*aa693e99SJason King /* 2*aa693e99SJason King * Copyright 2016 Jakub Klama <jceel@FreeBSD.org> 3*aa693e99SJason King * All rights reserved 4*aa693e99SJason King * 5*aa693e99SJason King * Redistribution and use in source and binary forms, with or without 6*aa693e99SJason King * modification, are permitted providing that the following conditions 7*aa693e99SJason King * are met: 8*aa693e99SJason King * 1. Redistributions of source code must retain the above copyright 9*aa693e99SJason King * notice, this list of conditions and the following disclaimer. 10*aa693e99SJason King * 2. Redistributions in binary form must reproduce the above copyright 11*aa693e99SJason King * notice, this list of conditions and the following disclaimer in the 12*aa693e99SJason King * documentation and/or other materials provided with the distribution. 13*aa693e99SJason King * 14*aa693e99SJason King * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15*aa693e99SJason King * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16*aa693e99SJason King * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17*aa693e99SJason King * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18*aa693e99SJason King * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19*aa693e99SJason King * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20*aa693e99SJason King * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21*aa693e99SJason King * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22*aa693e99SJason King * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23*aa693e99SJason King * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24*aa693e99SJason King * POSSIBILITY OF SUCH DAMAGE. 25*aa693e99SJason King * 26*aa693e99SJason King */ 27*aa693e99SJason King 28*aa693e99SJason King #ifndef LIB9P_THREADPOOL_H 29*aa693e99SJason King #define LIB9P_THREADPOOL_H 30*aa693e99SJason King 31*aa693e99SJason King #include <stdbool.h> 32*aa693e99SJason King #include <pthread.h> 33*aa693e99SJason King #include <sys/queue.h> 34*aa693e99SJason King #include "lib9p.h" 35*aa693e99SJason King 36*aa693e99SJason King STAILQ_HEAD(l9p_request_queue, l9p_request); 37*aa693e99SJason King 38*aa693e99SJason King /* 39*aa693e99SJason King * Most of the workers in the threadpool run requests. 40*aa693e99SJason King * 41*aa693e99SJason King * One distinguished worker delivers responses from the 42*aa693e99SJason King * response queue. The reason this worker exists is to 43*aa693e99SJason King * guarantee response order, so that flush responses go 44*aa693e99SJason King * after their flushed requests. 45*aa693e99SJason King */ 46*aa693e99SJason King struct l9p_threadpool { 47*aa693e99SJason King struct l9p_connection * ltp_conn; /* the connection */ 48*aa693e99SJason King struct l9p_request_queue ltp_workq; /* requests awaiting a worker */ 49*aa693e99SJason King struct l9p_request_queue ltp_replyq; /* requests that are done */ 50*aa693e99SJason King pthread_mutex_t ltp_mtx; /* locks queues and cond vars */ 51*aa693e99SJason King pthread_cond_t ltp_work_cv; /* to signal regular workers */ 52*aa693e99SJason King pthread_cond_t ltp_reply_cv; /* to signal reply-worker */ 53*aa693e99SJason King LIST_HEAD(, l9p_worker) ltp_workers; /* list of all workers */ 54*aa693e99SJason King }; 55*aa693e99SJason King 56*aa693e99SJason King /* 57*aa693e99SJason King * All workers, including the responder, use this as their 58*aa693e99SJason King * control structure. (The only thing that distinguishes the 59*aa693e99SJason King * responder is that it runs different code and waits on the 60*aa693e99SJason King * reply_cv.) 61*aa693e99SJason King */ 62*aa693e99SJason King struct l9p_worker { 63*aa693e99SJason King struct l9p_threadpool * ltw_tp; 64*aa693e99SJason King pthread_t ltw_thread; 65*aa693e99SJason King bool ltw_exiting; 66*aa693e99SJason King bool ltw_responder; 67*aa693e99SJason King LIST_ENTRY(l9p_worker) ltw_link; 68*aa693e99SJason King }; 69*aa693e99SJason King 70*aa693e99SJason King /* 71*aa693e99SJason King * Each request has a "work state" telling where the request is, 72*aa693e99SJason King * in terms of workers working on it. That is, this tells us 73*aa693e99SJason King * which threadpool queue, if any, the request is in now or would 74*aa693e99SJason King * go in, or what's happening with it. 75*aa693e99SJason King */ 76*aa693e99SJason King enum l9p_workstate { 77*aa693e99SJason King L9P_WS_NOTSTARTED, /* not yet started */ 78*aa693e99SJason King L9P_WS_IMMEDIATE, /* Tflush being done sans worker */ 79*aa693e99SJason King L9P_WS_INPROGRESS, /* worker is working on it */ 80*aa693e99SJason King L9P_WS_RESPQUEUED, /* worker is done, response queued */ 81*aa693e99SJason King L9P_WS_REPLYING, /* responder is in final reply path */ 82*aa693e99SJason King }; 83*aa693e99SJason King 84*aa693e99SJason King /* 85*aa693e99SJason King * Each request has a "flush state", initally NONE meaning no 86*aa693e99SJason King * Tflush affected the request. 87*aa693e99SJason King * 88*aa693e99SJason King * If a Tflush comes in before we ever assign a work thread, 89*aa693e99SJason King * the flush state goes to FLUSH_REQUESTED_PRE_START. 90*aa693e99SJason King * 91*aa693e99SJason King * If a Tflush comes in after we assign a work thread, the 92*aa693e99SJason King * flush state goes to FLUSH_REQUESTED_POST_START. The flush 93*aa693e99SJason King * request may be too late: the request might finish anyway. 94*aa693e99SJason King * Or it might be soon enough to abort. In all cases, though, the 95*aa693e99SJason King * operation requesting the flush (the "flusher") must wait for 96*aa693e99SJason King * the other request (the "flushee") to go through the respond 97*aa693e99SJason King * path. The respond routine gets to decide whether to send a 98*aa693e99SJason King * normal response, send an error, or drop the request 99*aa693e99SJason King * entirely. 100*aa693e99SJason King * 101*aa693e99SJason King * There's one especially annoying case: what if a Tflush comes in 102*aa693e99SJason King * *while* we're sending a response? In this case it's too late: 103*aa693e99SJason King * the flush just waits for the fully-composed response. 104*aa693e99SJason King */ 105*aa693e99SJason King enum l9p_flushstate { 106*aa693e99SJason King L9P_FLUSH_NONE = 0, /* must be zero */ 107*aa693e99SJason King L9P_FLUSH_REQUESTED_PRE_START, /* not even started before flush */ 108*aa693e99SJason King L9P_FLUSH_REQUESTED_POST_START, /* started, then someone said flush */ 109*aa693e99SJason King L9P_FLUSH_TOOLATE /* too late, already responding */ 110*aa693e99SJason King }; 111*aa693e99SJason King 112*aa693e99SJason King void l9p_threadpool_flushee_done(struct l9p_request *); 113*aa693e99SJason King int l9p_threadpool_init(struct l9p_threadpool *, int); 114*aa693e99SJason King void l9p_threadpool_run(struct l9p_threadpool *, struct l9p_request *); 115*aa693e99SJason King int l9p_threadpool_shutdown(struct l9p_threadpool *); 116*aa693e99SJason King int l9p_threadpool_tflush(struct l9p_request *); 117*aa693e99SJason King 118*aa693e99SJason King #endif /* LIB9P_THREADPOOL_H */ 119