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