xref: /aosp_15_r20/external/libfuse/lib/fuse_loop_mt.c (revision 9e5649576b786774a32d7b0252c9cd8c6538fa49)
1*9e564957SAndroid Build Coastguard Worker /*
2*9e564957SAndroid Build Coastguard Worker   FUSE: Filesystem in Userspace
3*9e564957SAndroid Build Coastguard Worker   Copyright (C) 2001-2007  Miklos Szeredi <[email protected]>
4*9e564957SAndroid Build Coastguard Worker 
5*9e564957SAndroid Build Coastguard Worker   Implementation of the multi-threaded FUSE session loop.
6*9e564957SAndroid Build Coastguard Worker 
7*9e564957SAndroid Build Coastguard Worker   This program can be distributed under the terms of the GNU LGPLv2.
8*9e564957SAndroid Build Coastguard Worker   See the file COPYING.LIB.
9*9e564957SAndroid Build Coastguard Worker */
10*9e564957SAndroid Build Coastguard Worker 
11*9e564957SAndroid Build Coastguard Worker #include "fuse_config.h"
12*9e564957SAndroid Build Coastguard Worker #include "fuse_lowlevel.h"
13*9e564957SAndroid Build Coastguard Worker #include "fuse_misc.h"
14*9e564957SAndroid Build Coastguard Worker #include "fuse_kernel.h"
15*9e564957SAndroid Build Coastguard Worker #include "fuse_i.h"
16*9e564957SAndroid Build Coastguard Worker 
17*9e564957SAndroid Build Coastguard Worker #include <stdio.h>
18*9e564957SAndroid Build Coastguard Worker #include <stdlib.h>
19*9e564957SAndroid Build Coastguard Worker #include <string.h>
20*9e564957SAndroid Build Coastguard Worker #include <unistd.h>
21*9e564957SAndroid Build Coastguard Worker #include <signal.h>
22*9e564957SAndroid Build Coastguard Worker #include <semaphore.h>
23*9e564957SAndroid Build Coastguard Worker #include <errno.h>
24*9e564957SAndroid Build Coastguard Worker #include <sys/time.h>
25*9e564957SAndroid Build Coastguard Worker #include <sys/ioctl.h>
26*9e564957SAndroid Build Coastguard Worker #include <assert.h>
27*9e564957SAndroid Build Coastguard Worker #include <limits.h>
28*9e564957SAndroid Build Coastguard Worker 
29*9e564957SAndroid Build Coastguard Worker /* Environment var controlling the thread stack size */
30*9e564957SAndroid Build Coastguard Worker #define ENVNAME_THREAD_STACK "FUSE_THREAD_STACK"
31*9e564957SAndroid Build Coastguard Worker 
32*9e564957SAndroid Build Coastguard Worker #define FUSE_LOOP_MT_V2_IDENTIFIER	 INT_MAX - 2
33*9e564957SAndroid Build Coastguard Worker #define FUSE_LOOP_MT_DEF_CLONE_FD	 0
34*9e564957SAndroid Build Coastguard Worker #define FUSE_LOOP_MT_DEF_MAX_THREADS 10
35*9e564957SAndroid Build Coastguard Worker #define FUSE_LOOP_MT_DEF_IDLE_THREADS -1 /* thread destruction is disabled
36*9e564957SAndroid Build Coastguard Worker                                           * by default */
37*9e564957SAndroid Build Coastguard Worker 
38*9e564957SAndroid Build Coastguard Worker /* an arbitrary large value that cannot be valid */
39*9e564957SAndroid Build Coastguard Worker #define FUSE_LOOP_MT_MAX_THREADS      (100U * 1000)
40*9e564957SAndroid Build Coastguard Worker 
41*9e564957SAndroid Build Coastguard Worker struct fuse_worker {
42*9e564957SAndroid Build Coastguard Worker 	struct fuse_worker *prev;
43*9e564957SAndroid Build Coastguard Worker 	struct fuse_worker *next;
44*9e564957SAndroid Build Coastguard Worker 	pthread_t thread_id;
45*9e564957SAndroid Build Coastguard Worker 
46*9e564957SAndroid Build Coastguard Worker 	// We need to include fuse_buf so that we can properly free
47*9e564957SAndroid Build Coastguard Worker 	// it when a thread is terminated by pthread_cancel().
48*9e564957SAndroid Build Coastguard Worker 	struct fuse_buf fbuf;
49*9e564957SAndroid Build Coastguard Worker 	struct fuse_chan *ch;
50*9e564957SAndroid Build Coastguard Worker 	struct fuse_mt *mt;
51*9e564957SAndroid Build Coastguard Worker };
52*9e564957SAndroid Build Coastguard Worker 
53*9e564957SAndroid Build Coastguard Worker struct fuse_mt {
54*9e564957SAndroid Build Coastguard Worker 	pthread_mutex_t lock;
55*9e564957SAndroid Build Coastguard Worker 	int numworker;
56*9e564957SAndroid Build Coastguard Worker 	int numavail;
57*9e564957SAndroid Build Coastguard Worker 	struct fuse_session *se;
58*9e564957SAndroid Build Coastguard Worker 	struct fuse_worker main;
59*9e564957SAndroid Build Coastguard Worker 	sem_t finish;
60*9e564957SAndroid Build Coastguard Worker 	int exit;
61*9e564957SAndroid Build Coastguard Worker 	int error;
62*9e564957SAndroid Build Coastguard Worker 	int clone_fd;
63*9e564957SAndroid Build Coastguard Worker 	int max_idle;
64*9e564957SAndroid Build Coastguard Worker 	int max_threads;
65*9e564957SAndroid Build Coastguard Worker };
66*9e564957SAndroid Build Coastguard Worker 
fuse_chan_new(int fd)67*9e564957SAndroid Build Coastguard Worker static struct fuse_chan *fuse_chan_new(int fd)
68*9e564957SAndroid Build Coastguard Worker {
69*9e564957SAndroid Build Coastguard Worker 	struct fuse_chan *ch = (struct fuse_chan *) malloc(sizeof(*ch));
70*9e564957SAndroid Build Coastguard Worker 	if (ch == NULL) {
71*9e564957SAndroid Build Coastguard Worker 		fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate channel\n");
72*9e564957SAndroid Build Coastguard Worker 		return NULL;
73*9e564957SAndroid Build Coastguard Worker 	}
74*9e564957SAndroid Build Coastguard Worker 
75*9e564957SAndroid Build Coastguard Worker 	memset(ch, 0, sizeof(*ch));
76*9e564957SAndroid Build Coastguard Worker 	ch->fd = fd;
77*9e564957SAndroid Build Coastguard Worker 	ch->ctr = 1;
78*9e564957SAndroid Build Coastguard Worker 	pthread_mutex_init(&ch->lock, NULL);
79*9e564957SAndroid Build Coastguard Worker 
80*9e564957SAndroid Build Coastguard Worker 	return ch;
81*9e564957SAndroid Build Coastguard Worker }
82*9e564957SAndroid Build Coastguard Worker 
fuse_chan_get(struct fuse_chan * ch)83*9e564957SAndroid Build Coastguard Worker struct fuse_chan *fuse_chan_get(struct fuse_chan *ch)
84*9e564957SAndroid Build Coastguard Worker {
85*9e564957SAndroid Build Coastguard Worker 	assert(ch->ctr > 0);
86*9e564957SAndroid Build Coastguard Worker 	pthread_mutex_lock(&ch->lock);
87*9e564957SAndroid Build Coastguard Worker 	ch->ctr++;
88*9e564957SAndroid Build Coastguard Worker 	pthread_mutex_unlock(&ch->lock);
89*9e564957SAndroid Build Coastguard Worker 
90*9e564957SAndroid Build Coastguard Worker 	return ch;
91*9e564957SAndroid Build Coastguard Worker }
92*9e564957SAndroid Build Coastguard Worker 
fuse_chan_put(struct fuse_chan * ch)93*9e564957SAndroid Build Coastguard Worker void fuse_chan_put(struct fuse_chan *ch)
94*9e564957SAndroid Build Coastguard Worker {
95*9e564957SAndroid Build Coastguard Worker 	if (ch == NULL)
96*9e564957SAndroid Build Coastguard Worker 		return;
97*9e564957SAndroid Build Coastguard Worker 	pthread_mutex_lock(&ch->lock);
98*9e564957SAndroid Build Coastguard Worker 	ch->ctr--;
99*9e564957SAndroid Build Coastguard Worker 	if (!ch->ctr) {
100*9e564957SAndroid Build Coastguard Worker 		pthread_mutex_unlock(&ch->lock);
101*9e564957SAndroid Build Coastguard Worker 		close(ch->fd);
102*9e564957SAndroid Build Coastguard Worker 		pthread_mutex_destroy(&ch->lock);
103*9e564957SAndroid Build Coastguard Worker 		free(ch);
104*9e564957SAndroid Build Coastguard Worker 	} else
105*9e564957SAndroid Build Coastguard Worker 		pthread_mutex_unlock(&ch->lock);
106*9e564957SAndroid Build Coastguard Worker }
107*9e564957SAndroid Build Coastguard Worker 
list_add_worker(struct fuse_worker * w,struct fuse_worker * next)108*9e564957SAndroid Build Coastguard Worker static void list_add_worker(struct fuse_worker *w, struct fuse_worker *next)
109*9e564957SAndroid Build Coastguard Worker {
110*9e564957SAndroid Build Coastguard Worker 	struct fuse_worker *prev = next->prev;
111*9e564957SAndroid Build Coastguard Worker 	w->next = next;
112*9e564957SAndroid Build Coastguard Worker 	w->prev = prev;
113*9e564957SAndroid Build Coastguard Worker 	prev->next = w;
114*9e564957SAndroid Build Coastguard Worker 	next->prev = w;
115*9e564957SAndroid Build Coastguard Worker }
116*9e564957SAndroid Build Coastguard Worker 
list_del_worker(struct fuse_worker * w)117*9e564957SAndroid Build Coastguard Worker static void list_del_worker(struct fuse_worker *w)
118*9e564957SAndroid Build Coastguard Worker {
119*9e564957SAndroid Build Coastguard Worker 	struct fuse_worker *prev = w->prev;
120*9e564957SAndroid Build Coastguard Worker 	struct fuse_worker *next = w->next;
121*9e564957SAndroid Build Coastguard Worker 	prev->next = next;
122*9e564957SAndroid Build Coastguard Worker 	next->prev = prev;
123*9e564957SAndroid Build Coastguard Worker }
124*9e564957SAndroid Build Coastguard Worker 
125*9e564957SAndroid Build Coastguard Worker static int fuse_loop_start_thread(struct fuse_mt *mt);
126*9e564957SAndroid Build Coastguard Worker 
fuse_do_work(void * data)127*9e564957SAndroid Build Coastguard Worker static void *fuse_do_work(void *data)
128*9e564957SAndroid Build Coastguard Worker {
129*9e564957SAndroid Build Coastguard Worker 	struct fuse_worker *w = (struct fuse_worker *) data;
130*9e564957SAndroid Build Coastguard Worker 	struct fuse_mt *mt = w->mt;
131*9e564957SAndroid Build Coastguard Worker 
132*9e564957SAndroid Build Coastguard Worker 	while (!fuse_session_exited(mt->se)) {
133*9e564957SAndroid Build Coastguard Worker 		int isforget = 0;
134*9e564957SAndroid Build Coastguard Worker 		int res;
135*9e564957SAndroid Build Coastguard Worker 
136*9e564957SAndroid Build Coastguard Worker 		pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
137*9e564957SAndroid Build Coastguard Worker 		res = fuse_session_receive_buf_int(mt->se, &w->fbuf, w->ch);
138*9e564957SAndroid Build Coastguard Worker 		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
139*9e564957SAndroid Build Coastguard Worker 		if (res == -EINTR)
140*9e564957SAndroid Build Coastguard Worker 			continue;
141*9e564957SAndroid Build Coastguard Worker 		if (res <= 0) {
142*9e564957SAndroid Build Coastguard Worker 			if (res < 0) {
143*9e564957SAndroid Build Coastguard Worker 				fuse_session_exit(mt->se);
144*9e564957SAndroid Build Coastguard Worker 				mt->error = res;
145*9e564957SAndroid Build Coastguard Worker 			}
146*9e564957SAndroid Build Coastguard Worker 			break;
147*9e564957SAndroid Build Coastguard Worker 		}
148*9e564957SAndroid Build Coastguard Worker 
149*9e564957SAndroid Build Coastguard Worker 		pthread_mutex_lock(&mt->lock);
150*9e564957SAndroid Build Coastguard Worker 		if (mt->exit) {
151*9e564957SAndroid Build Coastguard Worker 			pthread_mutex_unlock(&mt->lock);
152*9e564957SAndroid Build Coastguard Worker 			return NULL;
153*9e564957SAndroid Build Coastguard Worker 		}
154*9e564957SAndroid Build Coastguard Worker 
155*9e564957SAndroid Build Coastguard Worker 		/*
156*9e564957SAndroid Build Coastguard Worker 		 * This disgusting hack is needed so that zillions of threads
157*9e564957SAndroid Build Coastguard Worker 		 * are not created on a burst of FORGET messages
158*9e564957SAndroid Build Coastguard Worker 		 */
159*9e564957SAndroid Build Coastguard Worker 		if (!(w->fbuf.flags & FUSE_BUF_IS_FD)) {
160*9e564957SAndroid Build Coastguard Worker 			struct fuse_in_header *in = w->fbuf.mem;
161*9e564957SAndroid Build Coastguard Worker 
162*9e564957SAndroid Build Coastguard Worker 			if (in->opcode == FUSE_FORGET ||
163*9e564957SAndroid Build Coastguard Worker 			    in->opcode == FUSE_BATCH_FORGET)
164*9e564957SAndroid Build Coastguard Worker 				isforget = 1;
165*9e564957SAndroid Build Coastguard Worker 		}
166*9e564957SAndroid Build Coastguard Worker 
167*9e564957SAndroid Build Coastguard Worker 		if (!isforget)
168*9e564957SAndroid Build Coastguard Worker 			mt->numavail--;
169*9e564957SAndroid Build Coastguard Worker 		if (mt->numavail == 0 && mt->numworker < mt->max_threads)
170*9e564957SAndroid Build Coastguard Worker 			fuse_loop_start_thread(mt);
171*9e564957SAndroid Build Coastguard Worker 		pthread_mutex_unlock(&mt->lock);
172*9e564957SAndroid Build Coastguard Worker 
173*9e564957SAndroid Build Coastguard Worker 		fuse_session_process_buf_int(mt->se, &w->fbuf, w->ch);
174*9e564957SAndroid Build Coastguard Worker 
175*9e564957SAndroid Build Coastguard Worker 		pthread_mutex_lock(&mt->lock);
176*9e564957SAndroid Build Coastguard Worker 		if (!isforget)
177*9e564957SAndroid Build Coastguard Worker 			mt->numavail++;
178*9e564957SAndroid Build Coastguard Worker 
179*9e564957SAndroid Build Coastguard Worker 		/* creating and destroying threads is rather expensive - and there is
180*9e564957SAndroid Build Coastguard Worker 		 * not much gain from destroying existing threads. It is therefore
181*9e564957SAndroid Build Coastguard Worker 		 * discouraged to set max_idle to anything else than -1. If there
182*9e564957SAndroid Build Coastguard Worker 		 * is indeed a good reason to destruct threads it should be done
183*9e564957SAndroid Build Coastguard Worker 		 * delayed, a moving average might be useful for that.
184*9e564957SAndroid Build Coastguard Worker 		 */
185*9e564957SAndroid Build Coastguard Worker 		if (mt->max_idle != -1 && mt->numavail > mt->max_idle && mt->numworker > 1) {
186*9e564957SAndroid Build Coastguard Worker 			if (mt->exit) {
187*9e564957SAndroid Build Coastguard Worker 				pthread_mutex_unlock(&mt->lock);
188*9e564957SAndroid Build Coastguard Worker 				return NULL;
189*9e564957SAndroid Build Coastguard Worker 			}
190*9e564957SAndroid Build Coastguard Worker 			list_del_worker(w);
191*9e564957SAndroid Build Coastguard Worker 			mt->numavail--;
192*9e564957SAndroid Build Coastguard Worker 			mt->numworker--;
193*9e564957SAndroid Build Coastguard Worker 			pthread_mutex_unlock(&mt->lock);
194*9e564957SAndroid Build Coastguard Worker 
195*9e564957SAndroid Build Coastguard Worker 			pthread_detach(w->thread_id);
196*9e564957SAndroid Build Coastguard Worker 			free(w->fbuf.mem);
197*9e564957SAndroid Build Coastguard Worker 			fuse_chan_put(w->ch);
198*9e564957SAndroid Build Coastguard Worker 			free(w);
199*9e564957SAndroid Build Coastguard Worker 			return NULL;
200*9e564957SAndroid Build Coastguard Worker 		}
201*9e564957SAndroid Build Coastguard Worker 		pthread_mutex_unlock(&mt->lock);
202*9e564957SAndroid Build Coastguard Worker 	}
203*9e564957SAndroid Build Coastguard Worker 
204*9e564957SAndroid Build Coastguard Worker 	sem_post(&mt->finish);
205*9e564957SAndroid Build Coastguard Worker 
206*9e564957SAndroid Build Coastguard Worker 	return NULL;
207*9e564957SAndroid Build Coastguard Worker }
208*9e564957SAndroid Build Coastguard Worker 
fuse_start_thread(pthread_t * thread_id,void * (* func)(void *),void * arg)209*9e564957SAndroid Build Coastguard Worker int fuse_start_thread(pthread_t *thread_id, void *(*func)(void *), void *arg)
210*9e564957SAndroid Build Coastguard Worker {
211*9e564957SAndroid Build Coastguard Worker 	sigset_t oldset;
212*9e564957SAndroid Build Coastguard Worker 	sigset_t newset;
213*9e564957SAndroid Build Coastguard Worker 	int res;
214*9e564957SAndroid Build Coastguard Worker 	pthread_attr_t attr;
215*9e564957SAndroid Build Coastguard Worker 	char *stack_size;
216*9e564957SAndroid Build Coastguard Worker 
217*9e564957SAndroid Build Coastguard Worker 	/* Override default stack size
218*9e564957SAndroid Build Coastguard Worker 	 * XXX: This should ideally be a parameter option. It is rather
219*9e564957SAndroid Build Coastguard Worker 	 *      well hidden here.
220*9e564957SAndroid Build Coastguard Worker 	 */
221*9e564957SAndroid Build Coastguard Worker 	pthread_attr_init(&attr);
222*9e564957SAndroid Build Coastguard Worker 	stack_size = getenv(ENVNAME_THREAD_STACK);
223*9e564957SAndroid Build Coastguard Worker 	if (stack_size && pthread_attr_setstacksize(&attr, atoi(stack_size)))
224*9e564957SAndroid Build Coastguard Worker 		fuse_log(FUSE_LOG_ERR, "fuse: invalid stack size: %s\n", stack_size);
225*9e564957SAndroid Build Coastguard Worker 
226*9e564957SAndroid Build Coastguard Worker 	/* Disallow signal reception in worker threads */
227*9e564957SAndroid Build Coastguard Worker 	sigemptyset(&newset);
228*9e564957SAndroid Build Coastguard Worker 	sigaddset(&newset, SIGTERM);
229*9e564957SAndroid Build Coastguard Worker 	sigaddset(&newset, SIGINT);
230*9e564957SAndroid Build Coastguard Worker 	sigaddset(&newset, SIGHUP);
231*9e564957SAndroid Build Coastguard Worker 	sigaddset(&newset, SIGQUIT);
232*9e564957SAndroid Build Coastguard Worker 	pthread_sigmask(SIG_BLOCK, &newset, &oldset);
233*9e564957SAndroid Build Coastguard Worker 	res = pthread_create(thread_id, &attr, func, arg);
234*9e564957SAndroid Build Coastguard Worker 	pthread_sigmask(SIG_SETMASK, &oldset, NULL);
235*9e564957SAndroid Build Coastguard Worker 	pthread_attr_destroy(&attr);
236*9e564957SAndroid Build Coastguard Worker 	if (res != 0) {
237*9e564957SAndroid Build Coastguard Worker 		fuse_log(FUSE_LOG_ERR, "fuse: error creating thread: %s\n",
238*9e564957SAndroid Build Coastguard Worker 			strerror(res));
239*9e564957SAndroid Build Coastguard Worker 		return -1;
240*9e564957SAndroid Build Coastguard Worker 	}
241*9e564957SAndroid Build Coastguard Worker 
242*9e564957SAndroid Build Coastguard Worker 	return 0;
243*9e564957SAndroid Build Coastguard Worker }
244*9e564957SAndroid Build Coastguard Worker 
fuse_clone_chan_fd_default(struct fuse_session * se)245*9e564957SAndroid Build Coastguard Worker static int fuse_clone_chan_fd_default(struct fuse_session *se)
246*9e564957SAndroid Build Coastguard Worker {
247*9e564957SAndroid Build Coastguard Worker 	int res;
248*9e564957SAndroid Build Coastguard Worker 	int clonefd;
249*9e564957SAndroid Build Coastguard Worker 	uint32_t masterfd;
250*9e564957SAndroid Build Coastguard Worker 	const char *devname = "/dev/fuse";
251*9e564957SAndroid Build Coastguard Worker 
252*9e564957SAndroid Build Coastguard Worker #ifndef O_CLOEXEC
253*9e564957SAndroid Build Coastguard Worker #define O_CLOEXEC 0
254*9e564957SAndroid Build Coastguard Worker #endif
255*9e564957SAndroid Build Coastguard Worker 	clonefd = open(devname, O_RDWR | O_CLOEXEC);
256*9e564957SAndroid Build Coastguard Worker 	if (clonefd == -1) {
257*9e564957SAndroid Build Coastguard Worker 		fuse_log(FUSE_LOG_ERR, "fuse: failed to open %s: %s\n", devname,
258*9e564957SAndroid Build Coastguard Worker 			strerror(errno));
259*9e564957SAndroid Build Coastguard Worker 		return -1;
260*9e564957SAndroid Build Coastguard Worker 	}
261*9e564957SAndroid Build Coastguard Worker #ifndef O_CLOEXEC
262*9e564957SAndroid Build Coastguard Worker 	fcntl(clonefd, F_SETFD, FD_CLOEXEC);
263*9e564957SAndroid Build Coastguard Worker #endif
264*9e564957SAndroid Build Coastguard Worker 
265*9e564957SAndroid Build Coastguard Worker 	masterfd = se->fd;
266*9e564957SAndroid Build Coastguard Worker 	res = ioctl(clonefd, FUSE_DEV_IOC_CLONE, &masterfd);
267*9e564957SAndroid Build Coastguard Worker 	if (res == -1) {
268*9e564957SAndroid Build Coastguard Worker 		fuse_log(FUSE_LOG_ERR, "fuse: failed to clone device fd: %s\n",
269*9e564957SAndroid Build Coastguard Worker 			strerror(errno));
270*9e564957SAndroid Build Coastguard Worker 		close(clonefd);
271*9e564957SAndroid Build Coastguard Worker 		return -1;
272*9e564957SAndroid Build Coastguard Worker 	}
273*9e564957SAndroid Build Coastguard Worker 	return clonefd;
274*9e564957SAndroid Build Coastguard Worker }
275*9e564957SAndroid Build Coastguard Worker 
fuse_clone_chan(struct fuse_mt * mt)276*9e564957SAndroid Build Coastguard Worker static struct fuse_chan *fuse_clone_chan(struct fuse_mt *mt)
277*9e564957SAndroid Build Coastguard Worker {
278*9e564957SAndroid Build Coastguard Worker 	int clonefd;
279*9e564957SAndroid Build Coastguard Worker 	struct fuse_session *se = mt->se;
280*9e564957SAndroid Build Coastguard Worker 	struct fuse_chan *newch;
281*9e564957SAndroid Build Coastguard Worker 
282*9e564957SAndroid Build Coastguard Worker 	if (se->io != NULL) {
283*9e564957SAndroid Build Coastguard Worker 		if (se->io->clone_fd != NULL)
284*9e564957SAndroid Build Coastguard Worker 			clonefd = se->io->clone_fd(se->fd);
285*9e564957SAndroid Build Coastguard Worker 		else
286*9e564957SAndroid Build Coastguard Worker 			return NULL;
287*9e564957SAndroid Build Coastguard Worker 	} else {
288*9e564957SAndroid Build Coastguard Worker 		clonefd = fuse_clone_chan_fd_default(se);
289*9e564957SAndroid Build Coastguard Worker 	}
290*9e564957SAndroid Build Coastguard Worker 	if (clonefd < 0)
291*9e564957SAndroid Build Coastguard Worker 		return NULL;
292*9e564957SAndroid Build Coastguard Worker 
293*9e564957SAndroid Build Coastguard Worker 	newch = fuse_chan_new(clonefd);
294*9e564957SAndroid Build Coastguard Worker 	if (newch == NULL)
295*9e564957SAndroid Build Coastguard Worker 		close(clonefd);
296*9e564957SAndroid Build Coastguard Worker 
297*9e564957SAndroid Build Coastguard Worker 	return newch;
298*9e564957SAndroid Build Coastguard Worker }
299*9e564957SAndroid Build Coastguard Worker 
fuse_loop_start_thread(struct fuse_mt * mt)300*9e564957SAndroid Build Coastguard Worker static int fuse_loop_start_thread(struct fuse_mt *mt)
301*9e564957SAndroid Build Coastguard Worker {
302*9e564957SAndroid Build Coastguard Worker 	int res;
303*9e564957SAndroid Build Coastguard Worker 
304*9e564957SAndroid Build Coastguard Worker 	struct fuse_worker *w = malloc(sizeof(struct fuse_worker));
305*9e564957SAndroid Build Coastguard Worker 	if (!w) {
306*9e564957SAndroid Build Coastguard Worker 		fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate worker structure\n");
307*9e564957SAndroid Build Coastguard Worker 		return -1;
308*9e564957SAndroid Build Coastguard Worker 	}
309*9e564957SAndroid Build Coastguard Worker 	memset(w, 0, sizeof(struct fuse_worker));
310*9e564957SAndroid Build Coastguard Worker 	w->fbuf.mem = NULL;
311*9e564957SAndroid Build Coastguard Worker 	w->mt = mt;
312*9e564957SAndroid Build Coastguard Worker 
313*9e564957SAndroid Build Coastguard Worker 	w->ch = NULL;
314*9e564957SAndroid Build Coastguard Worker 	if (mt->clone_fd) {
315*9e564957SAndroid Build Coastguard Worker 		w->ch = fuse_clone_chan(mt);
316*9e564957SAndroid Build Coastguard Worker 		if(!w->ch) {
317*9e564957SAndroid Build Coastguard Worker 			/* Don't attempt this again */
318*9e564957SAndroid Build Coastguard Worker 			fuse_log(FUSE_LOG_ERR, "fuse: trying to continue "
319*9e564957SAndroid Build Coastguard Worker 				"without -o clone_fd.\n");
320*9e564957SAndroid Build Coastguard Worker 			mt->clone_fd = 0;
321*9e564957SAndroid Build Coastguard Worker 		}
322*9e564957SAndroid Build Coastguard Worker 	}
323*9e564957SAndroid Build Coastguard Worker 
324*9e564957SAndroid Build Coastguard Worker 	res = fuse_start_thread(&w->thread_id, fuse_do_work, w);
325*9e564957SAndroid Build Coastguard Worker 	if (res == -1) {
326*9e564957SAndroid Build Coastguard Worker 		fuse_chan_put(w->ch);
327*9e564957SAndroid Build Coastguard Worker 		free(w);
328*9e564957SAndroid Build Coastguard Worker 		return -1;
329*9e564957SAndroid Build Coastguard Worker 	}
330*9e564957SAndroid Build Coastguard Worker 	list_add_worker(w, &mt->main);
331*9e564957SAndroid Build Coastguard Worker 	mt->numavail ++;
332*9e564957SAndroid Build Coastguard Worker 	mt->numworker ++;
333*9e564957SAndroid Build Coastguard Worker 
334*9e564957SAndroid Build Coastguard Worker 	return 0;
335*9e564957SAndroid Build Coastguard Worker }
336*9e564957SAndroid Build Coastguard Worker 
fuse_join_worker(struct fuse_mt * mt,struct fuse_worker * w)337*9e564957SAndroid Build Coastguard Worker static void fuse_join_worker(struct fuse_mt *mt, struct fuse_worker *w)
338*9e564957SAndroid Build Coastguard Worker {
339*9e564957SAndroid Build Coastguard Worker 	pthread_join(w->thread_id, NULL);
340*9e564957SAndroid Build Coastguard Worker 	pthread_mutex_lock(&mt->lock);
341*9e564957SAndroid Build Coastguard Worker 	list_del_worker(w);
342*9e564957SAndroid Build Coastguard Worker 	pthread_mutex_unlock(&mt->lock);
343*9e564957SAndroid Build Coastguard Worker 	free(w->fbuf.mem);
344*9e564957SAndroid Build Coastguard Worker 	fuse_chan_put(w->ch);
345*9e564957SAndroid Build Coastguard Worker 	free(w);
346*9e564957SAndroid Build Coastguard Worker }
347*9e564957SAndroid Build Coastguard Worker 
348*9e564957SAndroid Build Coastguard Worker int fuse_session_loop_mt_312(struct fuse_session *se, struct fuse_loop_config *config);
349*9e564957SAndroid Build Coastguard Worker FUSE_SYMVER("fuse_session_loop_mt_312", "fuse_session_loop_mt@@FUSE_3.12")
fuse_session_loop_mt_312(struct fuse_session * se,struct fuse_loop_config * config)350*9e564957SAndroid Build Coastguard Worker int fuse_session_loop_mt_312(struct fuse_session *se, struct fuse_loop_config *config)
351*9e564957SAndroid Build Coastguard Worker {
352*9e564957SAndroid Build Coastguard Worker int err;
353*9e564957SAndroid Build Coastguard Worker 	struct fuse_mt mt;
354*9e564957SAndroid Build Coastguard Worker 	struct fuse_worker *w;
355*9e564957SAndroid Build Coastguard Worker 	int created_config = 0;
356*9e564957SAndroid Build Coastguard Worker 
357*9e564957SAndroid Build Coastguard Worker 	if (config) {
358*9e564957SAndroid Build Coastguard Worker 		err = fuse_loop_cfg_verify(config);
359*9e564957SAndroid Build Coastguard Worker 		if (err)
360*9e564957SAndroid Build Coastguard Worker 			return err;
361*9e564957SAndroid Build Coastguard Worker 	} else {
362*9e564957SAndroid Build Coastguard Worker 		/* The caller does not care about parameters - use the default */
363*9e564957SAndroid Build Coastguard Worker 		config = fuse_loop_cfg_create();
364*9e564957SAndroid Build Coastguard Worker 		created_config = 1;
365*9e564957SAndroid Build Coastguard Worker 	}
366*9e564957SAndroid Build Coastguard Worker 
367*9e564957SAndroid Build Coastguard Worker 
368*9e564957SAndroid Build Coastguard Worker 	memset(&mt, 0, sizeof(struct fuse_mt));
369*9e564957SAndroid Build Coastguard Worker 	mt.se = se;
370*9e564957SAndroid Build Coastguard Worker 	mt.clone_fd = config->clone_fd;
371*9e564957SAndroid Build Coastguard Worker 	mt.error = 0;
372*9e564957SAndroid Build Coastguard Worker 	mt.numworker = 0;
373*9e564957SAndroid Build Coastguard Worker 	mt.numavail = 0;
374*9e564957SAndroid Build Coastguard Worker 	mt.max_idle = config->max_idle_threads;
375*9e564957SAndroid Build Coastguard Worker 	mt.max_threads = config->max_threads;
376*9e564957SAndroid Build Coastguard Worker 	mt.main.thread_id = pthread_self();
377*9e564957SAndroid Build Coastguard Worker 	mt.main.prev = mt.main.next = &mt.main;
378*9e564957SAndroid Build Coastguard Worker 	sem_init(&mt.finish, 0, 0);
379*9e564957SAndroid Build Coastguard Worker 	pthread_mutex_init(&mt.lock, NULL);
380*9e564957SAndroid Build Coastguard Worker 
381*9e564957SAndroid Build Coastguard Worker 	pthread_mutex_lock(&mt.lock);
382*9e564957SAndroid Build Coastguard Worker 	err = fuse_loop_start_thread(&mt);
383*9e564957SAndroid Build Coastguard Worker 	pthread_mutex_unlock(&mt.lock);
384*9e564957SAndroid Build Coastguard Worker 	if (!err) {
385*9e564957SAndroid Build Coastguard Worker 		/* sem_wait() is interruptible */
386*9e564957SAndroid Build Coastguard Worker 		while (!fuse_session_exited(se))
387*9e564957SAndroid Build Coastguard Worker 			sem_wait(&mt.finish);
388*9e564957SAndroid Build Coastguard Worker 
389*9e564957SAndroid Build Coastguard Worker 		pthread_mutex_lock(&mt.lock);
390*9e564957SAndroid Build Coastguard Worker 		for (w = mt.main.next; w != &mt.main; w = w->next)
391*9e564957SAndroid Build Coastguard Worker 			pthread_cancel(w->thread_id);
392*9e564957SAndroid Build Coastguard Worker 		mt.exit = 1;
393*9e564957SAndroid Build Coastguard Worker 		pthread_mutex_unlock(&mt.lock);
394*9e564957SAndroid Build Coastguard Worker 
395*9e564957SAndroid Build Coastguard Worker 		while (mt.main.next != &mt.main)
396*9e564957SAndroid Build Coastguard Worker 			fuse_join_worker(&mt, mt.main.next);
397*9e564957SAndroid Build Coastguard Worker 
398*9e564957SAndroid Build Coastguard Worker 		err = mt.error;
399*9e564957SAndroid Build Coastguard Worker 	}
400*9e564957SAndroid Build Coastguard Worker 
401*9e564957SAndroid Build Coastguard Worker 	pthread_mutex_destroy(&mt.lock);
402*9e564957SAndroid Build Coastguard Worker 	sem_destroy(&mt.finish);
403*9e564957SAndroid Build Coastguard Worker 	if(se->error != 0)
404*9e564957SAndroid Build Coastguard Worker 		err = se->error;
405*9e564957SAndroid Build Coastguard Worker 	fuse_session_reset(se);
406*9e564957SAndroid Build Coastguard Worker 
407*9e564957SAndroid Build Coastguard Worker 	if (created_config) {
408*9e564957SAndroid Build Coastguard Worker 		fuse_loop_cfg_destroy(config);
409*9e564957SAndroid Build Coastguard Worker 		config = NULL;
410*9e564957SAndroid Build Coastguard Worker 	}
411*9e564957SAndroid Build Coastguard Worker 
412*9e564957SAndroid Build Coastguard Worker 	return err;
413*9e564957SAndroid Build Coastguard Worker }
414*9e564957SAndroid Build Coastguard Worker 
415*9e564957SAndroid Build Coastguard Worker int fuse_session_loop_mt_32(struct fuse_session *se, struct fuse_loop_config_v1 *config_v1);
416*9e564957SAndroid Build Coastguard Worker FUSE_SYMVER("fuse_session_loop_mt_32", "fuse_session_loop_mt@FUSE_3.2")
fuse_session_loop_mt_32(struct fuse_session * se,struct fuse_loop_config_v1 * config_v1)417*9e564957SAndroid Build Coastguard Worker int fuse_session_loop_mt_32(struct fuse_session *se, struct fuse_loop_config_v1 *config_v1)
418*9e564957SAndroid Build Coastguard Worker {
419*9e564957SAndroid Build Coastguard Worker 	int err;
420*9e564957SAndroid Build Coastguard Worker 	struct fuse_loop_config *config = NULL;
421*9e564957SAndroid Build Coastguard Worker 
422*9e564957SAndroid Build Coastguard Worker 	if (config_v1 != NULL) {
423*9e564957SAndroid Build Coastguard Worker 		/* convert the given v1 config */
424*9e564957SAndroid Build Coastguard Worker 		config = fuse_loop_cfg_create();
425*9e564957SAndroid Build Coastguard Worker 		if (config == NULL)
426*9e564957SAndroid Build Coastguard Worker 			return ENOMEM;
427*9e564957SAndroid Build Coastguard Worker 
428*9e564957SAndroid Build Coastguard Worker 		fuse_loop_cfg_convert(config, config_v1);
429*9e564957SAndroid Build Coastguard Worker 	}
430*9e564957SAndroid Build Coastguard Worker 
431*9e564957SAndroid Build Coastguard Worker 	err = fuse_session_loop_mt_312(se, config);
432*9e564957SAndroid Build Coastguard Worker 
433*9e564957SAndroid Build Coastguard Worker 	fuse_loop_cfg_destroy(config);
434*9e564957SAndroid Build Coastguard Worker 
435*9e564957SAndroid Build Coastguard Worker 	return err;
436*9e564957SAndroid Build Coastguard Worker }
437*9e564957SAndroid Build Coastguard Worker 
438*9e564957SAndroid Build Coastguard Worker 
439*9e564957SAndroid Build Coastguard Worker int fuse_session_loop_mt_31(struct fuse_session *se, int clone_fd);
440*9e564957SAndroid Build Coastguard Worker FUSE_SYMVER("fuse_session_loop_mt_31", "fuse_session_loop_mt@FUSE_3.0")
fuse_session_loop_mt_31(struct fuse_session * se,int clone_fd)441*9e564957SAndroid Build Coastguard Worker int fuse_session_loop_mt_31(struct fuse_session *se, int clone_fd)
442*9e564957SAndroid Build Coastguard Worker {
443*9e564957SAndroid Build Coastguard Worker 	int err;
444*9e564957SAndroid Build Coastguard Worker 	struct fuse_loop_config *config = fuse_loop_cfg_create();
445*9e564957SAndroid Build Coastguard Worker 	if (clone_fd > 0)
446*9e564957SAndroid Build Coastguard Worker 		 fuse_loop_cfg_set_clone_fd(config, clone_fd);
447*9e564957SAndroid Build Coastguard Worker 	err = fuse_session_loop_mt_312(se, config);
448*9e564957SAndroid Build Coastguard Worker 
449*9e564957SAndroid Build Coastguard Worker 	fuse_loop_cfg_destroy(config);
450*9e564957SAndroid Build Coastguard Worker 
451*9e564957SAndroid Build Coastguard Worker 	return err;
452*9e564957SAndroid Build Coastguard Worker }
453*9e564957SAndroid Build Coastguard Worker 
fuse_loop_cfg_create(void)454*9e564957SAndroid Build Coastguard Worker struct fuse_loop_config *fuse_loop_cfg_create(void)
455*9e564957SAndroid Build Coastguard Worker {
456*9e564957SAndroid Build Coastguard Worker 	struct fuse_loop_config *config = calloc(1, sizeof(*config));
457*9e564957SAndroid Build Coastguard Worker 	if (config == NULL)
458*9e564957SAndroid Build Coastguard Worker 		return NULL;
459*9e564957SAndroid Build Coastguard Worker 
460*9e564957SAndroid Build Coastguard Worker 	config->version_id       = FUSE_LOOP_MT_V2_IDENTIFIER;
461*9e564957SAndroid Build Coastguard Worker 	config->max_idle_threads = FUSE_LOOP_MT_DEF_IDLE_THREADS;
462*9e564957SAndroid Build Coastguard Worker 	config->max_threads      = FUSE_LOOP_MT_DEF_MAX_THREADS;
463*9e564957SAndroid Build Coastguard Worker 	config->clone_fd         = FUSE_LOOP_MT_DEF_CLONE_FD;
464*9e564957SAndroid Build Coastguard Worker 
465*9e564957SAndroid Build Coastguard Worker 	return config;
466*9e564957SAndroid Build Coastguard Worker }
467*9e564957SAndroid Build Coastguard Worker 
fuse_loop_cfg_destroy(struct fuse_loop_config * config)468*9e564957SAndroid Build Coastguard Worker void fuse_loop_cfg_destroy(struct fuse_loop_config *config)
469*9e564957SAndroid Build Coastguard Worker {
470*9e564957SAndroid Build Coastguard Worker 	free(config);
471*9e564957SAndroid Build Coastguard Worker }
472*9e564957SAndroid Build Coastguard Worker 
fuse_loop_cfg_verify(struct fuse_loop_config * config)473*9e564957SAndroid Build Coastguard Worker int fuse_loop_cfg_verify(struct fuse_loop_config *config)
474*9e564957SAndroid Build Coastguard Worker {
475*9e564957SAndroid Build Coastguard Worker 	if (config->version_id != FUSE_LOOP_MT_V2_IDENTIFIER)
476*9e564957SAndroid Build Coastguard Worker 		return -EINVAL;
477*9e564957SAndroid Build Coastguard Worker 
478*9e564957SAndroid Build Coastguard Worker 	return 0;
479*9e564957SAndroid Build Coastguard Worker }
480*9e564957SAndroid Build Coastguard Worker 
fuse_loop_cfg_convert(struct fuse_loop_config * config,struct fuse_loop_config_v1 * v1_conf)481*9e564957SAndroid Build Coastguard Worker void fuse_loop_cfg_convert(struct fuse_loop_config *config,
482*9e564957SAndroid Build Coastguard Worker 			   struct fuse_loop_config_v1 *v1_conf)
483*9e564957SAndroid Build Coastguard Worker {
484*9e564957SAndroid Build Coastguard Worker 	fuse_loop_cfg_set_idle_threads(config, v1_conf->max_idle_threads);
485*9e564957SAndroid Build Coastguard Worker 
486*9e564957SAndroid Build Coastguard Worker 	fuse_loop_cfg_set_clone_fd(config, v1_conf->clone_fd);
487*9e564957SAndroid Build Coastguard Worker }
488*9e564957SAndroid Build Coastguard Worker 
fuse_loop_cfg_set_idle_threads(struct fuse_loop_config * config,unsigned int value)489*9e564957SAndroid Build Coastguard Worker void fuse_loop_cfg_set_idle_threads(struct fuse_loop_config *config,
490*9e564957SAndroid Build Coastguard Worker 				    unsigned int value)
491*9e564957SAndroid Build Coastguard Worker {
492*9e564957SAndroid Build Coastguard Worker 	if (value > FUSE_LOOP_MT_MAX_THREADS) {
493*9e564957SAndroid Build Coastguard Worker 		if (value != UINT_MAX)
494*9e564957SAndroid Build Coastguard Worker 			fuse_log(FUSE_LOG_ERR,
495*9e564957SAndroid Build Coastguard Worker 				 "Ignoring invalid max threads value "
496*9e564957SAndroid Build Coastguard Worker 				 "%u > max (%u).\n", value,
497*9e564957SAndroid Build Coastguard Worker 				 FUSE_LOOP_MT_MAX_THREADS);
498*9e564957SAndroid Build Coastguard Worker 		return;
499*9e564957SAndroid Build Coastguard Worker 	}
500*9e564957SAndroid Build Coastguard Worker 	config->max_idle_threads = value;
501*9e564957SAndroid Build Coastguard Worker }
502*9e564957SAndroid Build Coastguard Worker 
fuse_loop_cfg_set_max_threads(struct fuse_loop_config * config,unsigned int value)503*9e564957SAndroid Build Coastguard Worker void fuse_loop_cfg_set_max_threads(struct fuse_loop_config *config,
504*9e564957SAndroid Build Coastguard Worker 				   unsigned int value)
505*9e564957SAndroid Build Coastguard Worker {
506*9e564957SAndroid Build Coastguard Worker 	config->max_threads = value;
507*9e564957SAndroid Build Coastguard Worker }
508*9e564957SAndroid Build Coastguard Worker 
fuse_loop_cfg_set_clone_fd(struct fuse_loop_config * config,unsigned int value)509*9e564957SAndroid Build Coastguard Worker void fuse_loop_cfg_set_clone_fd(struct fuse_loop_config *config,
510*9e564957SAndroid Build Coastguard Worker 				unsigned int value)
511*9e564957SAndroid Build Coastguard Worker {
512*9e564957SAndroid Build Coastguard Worker 	config->clone_fd = value;
513*9e564957SAndroid Build Coastguard Worker }
514*9e564957SAndroid Build Coastguard Worker 
515