Imported Upstream version 2.9.0
[platform/upstream/fuse.git] / lib / fuse_mt.c
1 /*
2   FUSE: Filesystem in Userspace
3   Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
4
5   This program can be distributed under the terms of the GNU LGPLv2.
6   See the file COPYING.LIB.
7 */
8
9 #include "fuse_i.h"
10 #include "fuse_misc.h"
11 #include "fuse_lowlevel.h"
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <pthread.h>
17 #include <assert.h>
18
19 struct procdata {
20         struct fuse *f;
21         struct fuse_chan *prevch;
22         struct fuse_session *prevse;
23         fuse_processor_t proc;
24         void *data;
25 };
26
27 static void mt_session_proc(void *data, const char *buf, size_t len,
28                             struct fuse_chan *ch)
29 {
30         struct procdata *pd = (struct procdata *) data;
31         struct fuse_cmd *cmd = *(struct fuse_cmd **) buf;
32
33         (void) len;
34         (void) ch;
35         pd->proc(pd->f, cmd, pd->data);
36 }
37
38 static void mt_session_exit(void *data, int val)
39 {
40         struct procdata *pd = (struct procdata *) data;
41         if (val)
42                 fuse_session_exit(pd->prevse);
43         else
44                 fuse_session_reset(pd->prevse);
45 }
46
47 static int mt_session_exited(void *data)
48 {
49         struct procdata *pd = (struct procdata *) data;
50         return fuse_session_exited(pd->prevse);
51 }
52
53 static int mt_chan_receive(struct fuse_chan **chp, char *buf, size_t size)
54 {
55         struct fuse_cmd *cmd;
56         struct procdata *pd = (struct procdata *) fuse_chan_data(*chp);
57
58         assert(size >= sizeof(cmd));
59
60         cmd = fuse_read_cmd(pd->f);
61         if (cmd == NULL)
62                 return 0;
63
64         *(struct fuse_cmd **) buf = cmd;
65
66         return sizeof(cmd);
67 }
68
69 int fuse_loop_mt_proc(struct fuse *f, fuse_processor_t proc, void *data)
70 {
71         int res;
72         struct procdata pd;
73         struct fuse_session *prevse = fuse_get_session(f);
74         struct fuse_session *se;
75         struct fuse_chan *prevch = fuse_session_next_chan(prevse, NULL);
76         struct fuse_chan *ch;
77         struct fuse_session_ops sop = {
78                 .exit = mt_session_exit,
79                 .exited = mt_session_exited,
80                 .process = mt_session_proc,
81         };
82         struct fuse_chan_ops cop = {
83                 .receive = mt_chan_receive,
84         };
85
86         pd.f = f;
87         pd.prevch = prevch;
88         pd.prevse = prevse;
89         pd.proc = proc;
90         pd.data = data;
91
92         se = fuse_session_new(&sop, &pd);
93         if (se == NULL)
94                 return -1;
95
96         ch = fuse_chan_new(&cop, fuse_chan_fd(prevch),
97                            sizeof(struct fuse_cmd *), &pd);
98         if (ch == NULL) {
99                 fuse_session_destroy(se);
100                 return -1;
101         }
102         fuse_session_add_chan(se, ch);
103         res = fuse_session_loop_mt(se);
104         fuse_session_destroy(se);
105         return res;
106 }
107
108 int fuse_loop_mt(struct fuse *f)
109 {
110         if (f == NULL)
111                 return -1;
112
113         int res = fuse_start_cleanup_thread(f);
114         if (res)
115                 return -1;
116
117         res = fuse_session_loop_mt(fuse_get_session(f));
118         fuse_stop_cleanup_thread(f);
119         return res;
120 }
121
122 FUSE_SYMVER(".symver fuse_loop_mt_proc,__fuse_loop_mt@");