Imported from 6.824 labs
[invirt/third/libt4.git] / rpc / method_thread.h
1 #ifndef method_thread_h
2 #define method_thread_h
3
4 // method_thread(): start a thread that runs an object method.
5 // returns a pthread_t on success, and zero on error.
6
7 #include <pthread.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <stdlib.h>
11 #include "lang/verify.h"
12
13 static pthread_t
14 method_thread_parent(void *(*fn)(void *), void *arg, bool detach)
15 {
16         pthread_t th;
17         pthread_attr_t attr;
18         pthread_attr_init(&attr);
19         // set stack size to 100K, so we don't run out of memory
20         pthread_attr_setstacksize(&attr, 100*1024);
21         int err = pthread_create(&th, &attr, fn, arg);
22         pthread_attr_destroy(&attr);
23         if (err != 0) {
24                 fprintf(stderr, "pthread_create ret %d %s\n", err, strerror(err));
25                 exit(1);
26         }
27
28         if (detach) {
29                 // don't keep thread state around after exit, to avoid
30                 // running out of threads. set detach==false if you plan
31                 // to pthread_join.
32                 VERIFY(pthread_detach(th) == 0);
33         }
34
35         return th;
36 }
37
38 static void
39 method_thread_child()
40 {
41         // defer pthread_cancel() by default. check explicitly by
42         // enabling then pthread_testcancel().
43         int oldstate, oldtype;
44         VERIFY(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate) == 0);
45         VERIFY(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype) == 0);
46 }
47
48 template <class C> pthread_t 
49 method_thread(C *o, bool detach, void (C::*m)())
50 {
51         class XXX {
52                 public:
53                         C *o;
54                         void (C::*m)();
55                         static void *yyy(void *vvv) {
56                                 XXX *x = (XXX*)vvv;
57                                 C *o = x->o;
58                                 void (C::*m)() = x->m;
59                                 delete x;
60                                 method_thread_child();
61                                 (o->*m)();
62                                 return 0;
63                         }
64         };
65         XXX *x = new XXX;
66         x->o = o;
67         x->m = m;
68         return method_thread_parent(&XXX::yyy, (void *) x, detach);
69 }
70
71 template <class C, class A> pthread_t
72 method_thread(C *o, bool detach, void (C::*m)(A), A a)
73 {
74         class XXX {
75                 public:
76                         C *o;
77                         void (C::*m)(A a);
78                         A a;
79                         static void *yyy(void *vvv) {
80                                 XXX *x = (XXX*)vvv;
81                                 C *o = x->o;
82                                 void (C::*m)(A ) = x->m;
83                                 A a = x->a;
84                                 delete x;
85                                 method_thread_child();
86                                 (o->*m)(a);
87                                 return 0;
88                         }
89         };
90         XXX *x = new XXX;
91         x->o = o;
92         x->m = m;
93         x->a = a;
94         return method_thread_parent(&XXX::yyy, (void *) x, detach);
95 }
96
97 namespace {
98         // ~xavid: this causes a bizzare compile error on OS X.5 when
99         //         it's declared in the function, so I moved it out here.
100         template <class C, class A1, class A2>
101                 class XXX {
102                         public:
103                                 C *o;
104                                 void (C::*m)(A1 a1, A2 a2);
105                                 A1 a1;
106                                 A2  a2;
107                                 static void *yyy(void *vvv) {
108                                         XXX *x = (XXX*)vvv;
109                                         C *o = x->o;
110                                         void (C::*m)(A1 , A2 ) = x->m;
111                                         A1 a1 = x->a1;
112                                         A2 a2 = x->a2;
113                                         delete x;
114                                         method_thread_child();
115                                         (o->*m)(a1, a2);
116                                         return 0;
117                                 }
118                 };
119 }
120
121 template <class C, class A1, class A2> pthread_t
122 method_thread(C *o, bool detach, void (C::*m)(A1 , A2 ), A1 a1, A2 a2)
123 {
124         XXX<C,A1,A2> *x = new XXX<C,A1,A2>;
125         x->o = o;
126         x->m = m;
127         x->a1 = a1;
128         x->a2 = a2;
129         return method_thread_parent(&XXX<C,A1,A2>::yyy, (void *) x, detach);
130 }
131
132 template <class C, class A1, class A2, class A3> pthread_t
133 method_thread(C *o, bool detach, void (C::*m)(A1 , A2, A3 ), A1 a1, A2 a2, A3 a3)
134 {
135         class XXX {
136                 public:
137                         C *o;
138                         void (C::*m)(A1 a1, A2 a2, A3 a3);
139                         A1 a1;
140                         A2  a2;
141                         A3 a3;
142                         static void *yyy(void *vvv) {
143                                 XXX *x = (XXX*)vvv;
144                                 C *o = x->o;
145                                 void (C::*m)(A1 , A2 , A3 ) = x->m;
146                                 A1 a1 = x->a1;
147                                 A2 a2 = x->a2;
148                                 A3 a3 = x->a3;
149                                 delete x;
150                                 method_thread_child();
151                                 (o->*m)(a1, a2, a3);
152                                 return 0;
153                         }
154         };
155         XXX *x = new XXX;
156         x->o = o;
157         x->m = m;
158         x->a1 = a1;
159         x->a2 = a2;
160         x->a3 = a3;
161         return method_thread_parent(&XXX::yyy, (void *) x, detach);
162 }
163
164 #endif