static void fuse_join_worker(struct fuse_mt *mt, struct fuse_worker *w) { pthread_join(w->thread_id, NULL); pthread_mutex_lock(&mt->lock); list_del_worker(w); pthread_mutex_unlock(&mt->lock); free(w->buf); free(w); }
void mt_do_work(void *data) { struct cmd_request *w = (struct cmd_request *) data; struct buse_session *mt = w->session; u_int64_t from; u_int32_t len; //request.magic == htonl(NBD_REQUEST_MAGIC); struct nbd_reply reply; reply.magic = htonl(NBD_REPLY_MAGIC); reply.error = htonl(0); memcpy(reply.handle, w->handle, sizeof(w->handle)); switch (ntohl(w->type)) { /* I may at some point need to deal with the the fact that the * official nbd server has a maximum buffer size, and divides up * oversized requests into multiple pieces. This applies to reads * and writes. */ case NBD_CMD_READ: len = ntohl(w->len); from = ntohll(w->from); //fprintf(stderr, "Request for read of size %d\n", len); //assert(aop->read); w->buf = malloc(len); reply.error = mt->aop->read(w->buf, len, from, mt->userdata); pthread_mutex_lock(&(mt->wlock)); write_all(mt->sk, (char*) &reply, sizeof(struct nbd_reply)); if (w->reply.error == 0) write_all(mt->sk, (char*) w->buf, len); pthread_mutex_unlock(&(mt->wlock)); break; case NBD_CMD_WRITE: //fprintf(stderr, "Request for write of size %d\n", len); len = ntohl(w->len); from = ntohll(w->from); reply.error = mt->aop->write(w->buf, len, from, mt->userdata); //fprintf(stderr, "Request err write %d\n", reply.error); pthread_mutex_lock(&(mt->wlock)); write_all(mt->sk, (char*) &reply, sizeof(struct nbd_reply)); pthread_mutex_unlock(&(mt->wlock)); break; case NBD_CMD_DISC: /* Handle a disconnect request. */ // assert(aop->disc); //fprintf(stderr, "Received Disconnect!\n"); mt->aop->disc(mt->userdata); mt->go_on = false; break; #ifdef NBD_FLAG_SEND_FLUSH case NBD_CMD_FLUSH: //assert(aop->flush); reply.error = mt->aop->flush(mt->userdata); //fprintf(stderr, "Request err flush %d\n", reply.error); pthread_mutex_lock(&(mt->wlock)); write_all(mt->sk, (char*) &reply, sizeof(struct nbd_reply)); pthread_mutex_unlock(&(mt->wlock)); break; #endif #ifdef NBD_FLAG_SEND_TRIM case NBD_CMD_TRIM: len = ntohl(w->len); from = ntohll(w->from); //fprintf(stderr, "Request err trim %d\n", reply.error); //fprintf(stderr, "Request for trim of size %d\n", len); //assert(aop->trim); reply.error = mt->aop->trim(from, len, mt->userdata); pthread_mutex_lock(&(mt->wlock)); write_all(mt->sk, (char*) &reply, sizeof(struct nbd_reply)); pthread_mutex_unlock(&(mt->wlock)); break; #endif } list_del_worker(w); if (w->buf) free(w->buf); free(w); }
static void *fuse_do_work(void *data) { struct fuse_worker *w = (struct fuse_worker *) data; struct fuse_mt *mt = w->mt; while (!fuse_session_exited(mt->se)) { int isforget = 0; struct fuse_chan *ch = mt->prevch; struct fuse_buf fbuf = { .mem = w->buf, .size = w->bufsize, }; int res; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); res = fuse_session_receive_buf(mt->se, &fbuf, &ch); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); if (res == -EINTR) continue; if (res <= 0) { if (res < 0) { fuse_session_exit(mt->se); mt->error = -1; } break; } pthread_mutex_lock(&mt->lock); if (mt->exit) { pthread_mutex_unlock(&mt->lock); return NULL; } /* * This disgusting hack is needed so that zillions of threads * are not created on a burst of FORGET messages */ if (!(fbuf.flags & FUSE_BUF_IS_FD)) { struct fuse_in_header *in = fbuf.mem; if (in->opcode == FUSE_FORGET || in->opcode == FUSE_BATCH_FORGET) isforget = 1; } if (!isforget) mt->numavail--; if (mt->numavail == 0) fuse_loop_start_thread(mt); pthread_mutex_unlock(&mt->lock); fuse_session_process_buf(mt->se, &fbuf, ch); pthread_mutex_lock(&mt->lock); if (!isforget) mt->numavail++; if (mt->numavail > 10) { if (mt->exit) { pthread_mutex_unlock(&mt->lock); return NULL; } list_del_worker(w); mt->numavail--; mt->numworker--; pthread_mutex_unlock(&mt->lock); pthread_detach(w->thread_id); free(w->buf); free(w); return NULL; } pthread_mutex_unlock(&mt->lock); } sem_post(&mt->finish); return NULL; } int fuse_start_thread(pthread_t *thread_id, void *(*func)(void *), void *arg) { sigset_t oldset; sigset_t newset; int res; pthread_attr_t attr; char *stack_size; /* Override default stack size */ pthread_attr_init(&attr); stack_size = getenv(ENVNAME_THREAD_STACK); if (stack_size && pthread_attr_setstacksize(&attr, atoi(stack_size))) fprintf(stderr, "fuse: invalid stack size: %s\n", stack_size); /* Disallow signal reception in worker threads */ sigemptyset(&newset); sigaddset(&newset, SIGTERM); sigaddset(&newset, SIGINT); sigaddset(&newset, SIGHUP); sigaddset(&newset, SIGQUIT); pthread_sigmask(SIG_BLOCK, &newset, &oldset); res = pthread_create(thread_id, &attr, func, arg); pthread_sigmask(SIG_SETMASK, &oldset, NULL); pthread_attr_destroy(&attr); if (res != 0) { fprintf(stderr, "fuse: error creating thread: %s\n", strerror(res)); return -1; } return 0; }
static void *fuse_do_work(void *data) { struct fuse_worker *w = (struct fuse_worker *) data; struct fuse_mt *mt = w->mt; while (!fuse_session_exited(mt->se)) { int isforget = 0; struct fuse_chan *ch = mt->prevch; int res; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); res = fuse_chan_recv(&ch, w->buf, w->bufsize); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); if (res == -EINTR) continue; if (res <= 0) { if (res < 0) { fuse_session_exit(mt->se); mt->error = -1; } break; } pthread_mutex_lock(&mt->lock); if (mt->exit) { pthread_mutex_unlock(&mt->lock); return NULL; } /* * This disgusting hack is needed so that zillions of threads * are not created on a burst of FORGET messages */ if (((struct fuse_in_header *) w->buf)->opcode == FUSE_FORGET) isforget = 1; if (!isforget) mt->numavail--; if (mt->numavail == 0) fuse_start_thread(mt); pthread_mutex_unlock(&mt->lock); fuse_session_process(mt->se, w->buf, res, ch); pthread_mutex_lock(&mt->lock); if (!isforget) mt->numavail++; if (mt->numavail > 10) { if (mt->exit) { pthread_mutex_unlock(&mt->lock); return NULL; } list_del_worker(w); mt->numavail--; mt->numworker--; pthread_mutex_unlock(&mt->lock); pthread_detach(w->thread_id); free(w->buf); free(w); return NULL; } pthread_mutex_unlock(&mt->lock); } sem_post(&mt->finish); #ifdef __APPLE__ { sigset_t set; (void) sigprocmask(0, NULL, &set); (void) sigsuspend(&set); /* want cancelable */ } #else /* !__APPLE__ */ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pause(); #endif /* __APPLE__ */ return NULL; }