]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/lib9p/threadpool.h
login(1): when exporting variables check the result of setenv(3)
[FreeBSD/FreeBSD.git] / contrib / lib9p / threadpool.h
1 /*
2  * Copyright 2016 Jakub Klama <jceel@FreeBSD.org>
3  * All rights reserved
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted providing that the following conditions
7  * are met:
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.
13  *
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.
25  *
26  */
27
28 #ifndef LIB9P_THREADPOOL_H
29 #define LIB9P_THREADPOOL_H
30
31 #include <stdbool.h>
32 #include <pthread.h>
33 #include <sys/queue.h>
34 #include "lib9p.h"
35
36 STAILQ_HEAD(l9p_request_queue, l9p_request);
37
38 /*
39  * Most of the workers in the threadpool run requests.
40  *
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.
45  */
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 */
54 };
55
56 /*
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
60  * reply_cv.)
61  */
62 struct l9p_worker {
63     struct l9p_threadpool *     ltw_tp;
64     pthread_t                   ltw_thread;
65     bool                        ltw_exiting;
66     bool                        ltw_responder;
67     LIST_ENTRY(l9p_worker)      ltw_link;
68 };
69
70 /*
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.
75  */
76 enum l9p_workstate {
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 */
82 };
83
84 /*
85  * Each request has a "flush state", initally NONE meaning no
86  * Tflush affected the request.
87  *
88  * If a Tflush comes in before we ever assign a work thread,
89  * the flush state goes to FLUSH_REQUESTED_PRE_START.
90  *
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
99  * entirely.
100  *
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.
104  */
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 */
110 };
111
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 *);
117
118 #endif  /* LIB9P_THREADPOOL_H  */