xref: /freebsd-src/contrib/lib9p/threadpool.h (revision 134e17798c9af53632b372348ab828e75e65bf46)
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