1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
|
/* Copyright 2016 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
#ifndef NSYNC_TESTING_CLOSURE_H_
#define NSYNC_TESTING_CLOSURE_H_
/* A run-once, self-freeing closure. */
typedef struct closure_s {
void (*f0) (void *);
} closure;
/* Run the closure *cl, and free it. */
void closure_run (closure *cl);
/* Fork a new thread running the closure *cl, which will be freed when the
thread exits. */
void closure_fork (closure *cl);
/* To create a closure, declare a closure constructor with the right function arguments.
For functions taking no arguments, use
CLOSURE_DECL_BODY0 (foo)
to generate the static routine:
static closure *closure_foo (void (*f) (void));
that will return a closure for any function *f that takes no argument.
For an 1-argument function, use
CLOSURE_DECL_BODY1 (foo, type)
to generate the static routine:
static closure *closure_foo (void (*f) (type), type x);
that will return a closure for any function taking a single argument of the
specified type.
For an 2-argument function, use
CLOSURE_DECL_BODY2 (foo, type0, type1)
to generate the static routine:
static closure *closure_foo (void (*f) (type0, type1), type0 x0, type1 x1);
that will return a closure for any function taking a "type0" argument, and
a "type1" argument.
And so on, up to 9 arguments.
For example, to make closures out of qsort():
// First, just once (per module) define:
// static closure *closure_qsort_args (
// void (*f) (void *, size_t, size_t, int (*)(const void *, const void *))
// void *x0, size_t x1, size_t x2, int (*x3)(const void *, const void *));
// by writing:
CLOSURE_DECL_BODY4 (qsort_args, void *, size_t, size_t, int (*)(const void *, const void *))
// Second, for each closure to be created, write something like this:
closure *cl = closure_qsort_args (array, n_elements, sizeof (array[0]), &elem_cmp);
// Then to run (and free) each closure:
closure_run (cl);
// This is like calling
// qsort (array, n_elements, sizeof (array[0]), &elem_cmp);
// free (cl);
*/
/* ------------------------------------------------------------------ */
/* Internal macro details follow. */
#define CLOSURE_S0(x,e) e
#define CLOSURE_S1(x,e) x##0
#define CLOSURE_S2(x,e) x##0, x##1
#define CLOSURE_S3(x,e) x##0, x##1, x##2
#define CLOSURE_S4(x,e) x##0, x##1, x##2, x##3
#define CLOSURE_S5(x,e) x##0, x##1, x##2, x##3, x##4
#define CLOSURE_S6(x,e) x##0, x##1, x##2, x##3, x##4, x##5
#define CLOSURE_S7(x,e) x##0, x##1, x##2, x##3, x##4, x##5, x##6
#define CLOSURE_S8(x,e) x##0, x##1, x##2, x##3, x##4, x##5, x##6, x##7
#define CLOSURE_S9(x,e) x##0, x##1, x##2, x##3, x##4, x##5, x##6, x##7, x##8
#define CLOSURE_P0(x,y,p,s,t)
#define CLOSURE_P1(x,y,p,s,t) p x##0 y##0 t
#define CLOSURE_P2(x,y,p,s,t) p x##0 y##0 s x##1 y##1 t
#define CLOSURE_P3(x,y,p,s,t) p x##0 y##0 s x##1 y##1 s x##2 y##2 t
#define CLOSURE_P4(x,y,p,s,t) p x##0 y##0 s x##1 y##1 s x##2 y##2 s x##3 y##3 t
#define CLOSURE_P5(x,y,p,s,t) p x##0 y##0 s x##1 y##1 s x##2 y##2 s x##3 y##3 s x##4 y##4 t
#define CLOSURE_P6(x,y,p,s,t) p x##0 y##0 s x##1 y##1 s x##2 y##2 s x##3 y##3 s x##4 y##4 s \
x##5 y##5 t
#define CLOSURE_P7(x,y,p,s,t) p x##0 y##0 s x##1 y##1 s x##2 y##2 s x##3 y##3 s x##4 y##4 s \
x##5 y##5 s x##6 y##6 t
#define CLOSURE_P8(x,y,p,s,t) p x##0 y##0 s x##1 y##1 s x##2 y##2 s x##3 y##3 s x##4 y##4 s \
x##5 y##5 s x##6 y##6 s x##7 y##7 t
#define CLOSURE_P9(x,y,p,s,t) p x##0 y##0 s x##1 y##1 s x##2 y##2 s x##3 y##3 s x##4 y##4 s \
x##5 y##5 s x##6 y##6 s x##7 y##7 s x##8 y##8 t
#define CLOSURE_COMMA_ ,
#define CLOSURE_SEMI_ ;
#define CLOSURE_BLANK_
#define CLOSURE_DECL_BODY_N_(name, n) \
struct closure_s_##name { \
void (*f0) (void *); /* must be first; matches closure. */ \
void (*f) (CLOSURE_S##n (closure_t_##name##_,void)); \
CLOSURE_P##n (closure_t_##name##_, a, CLOSURE_BLANK_, \
CLOSURE_SEMI_, CLOSURE_SEMI_) \
}; \
static void closure_f0_##name (void *v) { \
struct closure_s_##name *a = (struct closure_s_##name *) v; \
(*a->f) (CLOSURE_S##n (a->a,CLOSURE_BLANK_)); \
free (a); \
} \
static closure *closure_##name (void (*f) (CLOSURE_S##n (closure_t_##name##_,void)) \
CLOSURE_P##n (closure_t_##name##_, a, CLOSURE_COMMA_, \
CLOSURE_COMMA_, CLOSURE_BLANK_)) { \
struct closure_s_##name *cl = (struct closure_s_##name *) malloc (sizeof (*cl)); \
cl->f0 = &closure_f0_##name; \
cl->f = f; \
CLOSURE_P##n (cl->a, = a, CLOSURE_BLANK_, CLOSURE_SEMI_, CLOSURE_SEMI_) \
return ((closure *) cl); \
}
#define CLOSURE_DECL_BODY0(name) \
CLOSURE_DECL_BODY_N_ (name, 0)
#define CLOSURE_DECL_BODY1(name, t0) \
typedef t0 closure_t_##name##_0; \
CLOSURE_DECL_BODY_N_ (name, 1)
#define CLOSURE_DECL_BODY2(name, t0, t1) \
typedef t0 closure_t_##name##_0; \
typedef t1 closure_t_##name##_1; \
CLOSURE_DECL_BODY_N_ (name, 2)
#define CLOSURE_DECL_BODY3(name, t0, t1, t2) \
typedef t0 closure_t_##name##_0; \
typedef t1 closure_t_##name##_1; \
typedef t2 closure_t_##name##_2; \
CLOSURE_DECL_BODY_N_ (name, 3)
#define CLOSURE_DECL_BODY4(name, t0, t1, t2, t3) \
typedef t0 closure_t_##name##_0; \
typedef t1 closure_t_##name##_1; \
typedef t2 closure_t_##name##_2; \
typedef t3 closure_t_##name##_3; \
CLOSURE_DECL_BODY_N_ (name, 4)
#define CLOSURE_DECL_BODY5(name, t0, t1, t2, t3, t4) \
typedef t0 closure_t_##name##_0; \
typedef t1 closure_t_##name##_1; \
typedef t2 closure_t_##name##_2; \
typedef t3 closure_t_##name##_3; \
typedef t4 closure_t_##name##_4; \
CLOSURE_DECL_BODY_N_ (name, 5)
#define CLOSURE_DECL_BODY6(name, t0, t1, t2, t3, t4, t5) \
typedef t0 closure_t_##name##_0; \
typedef t1 closure_t_##name##_1; \
typedef t2 closure_t_##name##_2; \
typedef t3 closure_t_##name##_3; \
typedef t4 closure_t_##name##_4; \
typedef t5 closure_t_##name##_5; \
CLOSURE_DECL_BODY_N_ (name, 6)
#define CLOSURE_DECL_BODY7(name, t0, t1, t2, t3, t4, t5, t6) \
typedef t0 closure_t_##name##_0; \
typedef t1 closure_t_##name##_1; \
typedef t2 closure_t_##name##_2; \
typedef t3 closure_t_##name##_3; \
typedef t4 closure_t_##name##_4; \
typedef t5 closure_t_##name##_5; \
typedef t6 closure_t_##name##_6; \
CLOSURE_DECL_BODY_N_ (name, 7)
#define CLOSURE_DECL_BODY8(name, t0, t1, t2, t3, t4, t5, t6, t7) \
typedef t0 closure_t_##name##_0; \
typedef t1 closure_t_##name##_1; \
typedef t2 closure_t_##name##_2; \
typedef t3 closure_t_##name##_3; \
typedef t4 closure_t_##name##_4; \
typedef t5 closure_t_##name##_5; \
typedef t6 closure_t_##name##_6; \
typedef t7 closure_t_##name##_7; \
CLOSURE_DECL_BODY_N_ (name, 8)
#define CLOSURE_DECL_BODY9(name, t0, t1, t2, t3, t4, t5, t6, t7, t8) \
typedef t0 closure_t_##name##_0; \
typedef t1 closure_t_##name##_1; \
typedef t2 closure_t_##name##_2; \
typedef t3 closure_t_##name##_3; \
typedef t4 closure_t_##name##_4; \
typedef t5 closure_t_##name##_5; \
typedef t6 closure_t_##name##_6; \
typedef t7 closure_t_##name##_7; \
typedef t8 closure_t_##name##_8; \
CLOSURE_DECL_BODY_N_ (name, 9)
#endif /*NSYNC_TESTING_CLOSURE_H_*/
|