2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
5 This program can be distributed under the terms of the GNU LGPLv2.
6 See the file COPYING.LIB.
9 #include "fuse_lowlevel.h"
10 #include "fuse_misc.h"
11 #include "fuse_kernel.h"
19 #include <semaphore.h>
23 /* Environment var controlling the thread stack size */
24 #define ENVNAME_THREAD_STACK "FUSE_THREAD_STACK"
27 struct fuse_worker
*prev
;
28 struct fuse_worker
*next
;
39 struct fuse_session
*se
;
40 struct fuse_chan
*prevch
;
41 struct fuse_worker main
;
47 static void list_add_worker(struct fuse_worker
*w
, struct fuse_worker
*next
)
49 struct fuse_worker
*prev
= next
->prev
;
56 static void list_del_worker(struct fuse_worker
*w
)
58 struct fuse_worker
*prev
= w
->prev
;
59 struct fuse_worker
*next
= w
->next
;
64 static int fuse_loop_start_thread(struct fuse_mt
*mt
);
66 static void *fuse_do_work(void *data
)
68 struct fuse_worker
*w
= (struct fuse_worker
*) data
;
69 struct fuse_mt
*mt
= w
->mt
;
71 while (!fuse_session_exited(mt
->se
)) {
73 struct fuse_chan
*ch
= mt
->prevch
;
74 struct fuse_buf fbuf
= {
80 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, NULL
);
81 res
= fuse_session_receive_buf(mt
->se
, &fbuf
, &ch
);
82 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
, NULL
);
87 fuse_session_exit(mt
->se
);
93 pthread_mutex_lock(&mt
->lock
);
95 pthread_mutex_unlock(&mt
->lock
);
100 * This disgusting hack is needed so that zillions of threads
101 * are not created on a burst of FORGET messages
103 if (!(fbuf
.flags
& FUSE_BUF_IS_FD
)) {
104 struct fuse_in_header
*in
= fbuf
.mem
;
106 if (in
->opcode
== FUSE_FORGET
||
107 in
->opcode
== FUSE_BATCH_FORGET
)
113 if (mt
->numavail
== 0)
114 fuse_loop_start_thread(mt
);
115 pthread_mutex_unlock(&mt
->lock
);
117 fuse_session_process_buf(mt
->se
, &fbuf
, ch
);
119 pthread_mutex_lock(&mt
->lock
);
122 if (mt
->numavail
> 10) {
124 pthread_mutex_unlock(&mt
->lock
);
130 pthread_mutex_unlock(&mt
->lock
);
132 pthread_detach(w
->thread_id
);
137 pthread_mutex_unlock(&mt
->lock
);
140 sem_post(&mt
->finish
);
145 int fuse_start_thread(pthread_t
*thread_id
, void *(*func
)(void *), void *arg
)
153 /* Override default stack size */
154 pthread_attr_init(&attr
);
155 stack_size
= getenv(ENVNAME_THREAD_STACK
);
156 if (stack_size
&& pthread_attr_setstacksize(&attr
, atoi(stack_size
)))
157 fprintf(stderr
, "fuse: invalid stack size: %s\n", stack_size
);
159 /* Disallow signal reception in worker threads */
160 sigemptyset(&newset
);
161 sigaddset(&newset
, SIGTERM
);
162 sigaddset(&newset
, SIGINT
);
163 sigaddset(&newset
, SIGHUP
);
164 sigaddset(&newset
, SIGQUIT
);
165 pthread_sigmask(SIG_BLOCK
, &newset
, &oldset
);
166 res
= pthread_create(thread_id
, &attr
, func
, arg
);
167 pthread_sigmask(SIG_SETMASK
, &oldset
, NULL
);
168 pthread_attr_destroy(&attr
);
170 fprintf(stderr
, "fuse: error creating thread: %s\n",
178 static int fuse_loop_start_thread(struct fuse_mt
*mt
)
181 struct fuse_worker
*w
= malloc(sizeof(struct fuse_worker
));
183 fprintf(stderr
, "fuse: failed to allocate worker structure\n");
186 memset(w
, 0, sizeof(struct fuse_worker
));
187 w
->bufsize
= fuse_chan_bufsize(mt
->prevch
);
188 w
->buf
= malloc(w
->bufsize
);
191 fprintf(stderr
, "fuse: failed to allocate read buffer\n");
196 res
= fuse_start_thread(&w
->thread_id
, fuse_do_work
, w
);
202 list_add_worker(w
, &mt
->main
);
209 static void fuse_join_worker(struct fuse_mt
*mt
, struct fuse_worker
*w
)
211 pthread_join(w
->thread_id
, NULL
);
212 pthread_mutex_lock(&mt
->lock
);
214 pthread_mutex_unlock(&mt
->lock
);
219 int fuse_session_loop_mt(struct fuse_session
*se
)
223 struct fuse_worker
*w
;
225 memset(&mt
, 0, sizeof(struct fuse_mt
));
227 mt
.prevch
= fuse_session_next_chan(se
, NULL
);
231 mt
.main
.thread_id
= pthread_self();
232 mt
.main
.prev
= mt
.main
.next
= &mt
.main
;
233 sem_init(&mt
.finish
, 0, 0);
234 fuse_mutex_init(&mt
.lock
);
236 pthread_mutex_lock(&mt
.lock
);
237 err
= fuse_loop_start_thread(&mt
);
238 pthread_mutex_unlock(&mt
.lock
);
240 /* sem_wait() is interruptible */
241 while (!fuse_session_exited(se
))
242 sem_wait(&mt
.finish
);
244 pthread_mutex_lock(&mt
.lock
);
245 for (w
= mt
.main
.next
; w
!= &mt
.main
; w
= w
->next
)
246 pthread_cancel(w
->thread_id
);
248 pthread_mutex_unlock(&mt
.lock
);
250 while (mt
.main
.next
!= &mt
.main
)
251 fuse_join_worker(&mt
, mt
.main
.next
);
256 pthread_mutex_destroy(&mt
.lock
);
257 sem_destroy(&mt
.finish
);
258 fuse_session_reset(se
);