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