mbed I/F binding for mruby
Dependents: mruby_mbed_web mirb_mbed
mbed-mruby
How to use
Class
mrbgems/mruby-fiber/fiber.c@1:8ccd1d494a4b, 2015-04-13 (annotated)
- Committer:
- mzta
- Date:
- Mon Apr 13 05:20:15 2015 +0000
- Revision:
- 1:8ccd1d494a4b
- Parent:
- 0:158c61bb030f
- code refactoring.; - add SPI, SPISlave, I2C class to mruby-mbed (Incomplete).
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
mzta | 0:158c61bb030f | 1 | #include "mruby.h" |
mzta | 0:158c61bb030f | 2 | #include "mruby/array.h" |
mzta | 0:158c61bb030f | 3 | #include "mruby/class.h" |
mzta | 0:158c61bb030f | 4 | #include "mruby/proc.h" |
mzta | 0:158c61bb030f | 5 | |
mzta | 0:158c61bb030f | 6 | #define fiber_ptr(o) ((struct RFiber*)mrb_ptr(o)) |
mzta | 0:158c61bb030f | 7 | |
mzta | 0:158c61bb030f | 8 | #define FIBER_STACK_INIT_SIZE 64 |
mzta | 0:158c61bb030f | 9 | #define FIBER_CI_INIT_SIZE 8 |
mzta | 0:158c61bb030f | 10 | |
mzta | 0:158c61bb030f | 11 | /* |
mzta | 0:158c61bb030f | 12 | * call-seq: |
mzta | 0:158c61bb030f | 13 | * Fiber.new{...} -> obj |
mzta | 0:158c61bb030f | 14 | * |
mzta | 0:158c61bb030f | 15 | * Creates a fiber, whose execution is suspend until it is explicitly |
mzta | 0:158c61bb030f | 16 | * resumed using <code>Fiber#resume</code> method. |
mzta | 0:158c61bb030f | 17 | * The code running inside the fiber can give up control by calling |
mzta | 0:158c61bb030f | 18 | * <code>Fiber.yield</code> in which case it yields control back to caller |
mzta | 0:158c61bb030f | 19 | * (the caller of the <code>Fiber#resume</code>). |
mzta | 0:158c61bb030f | 20 | * |
mzta | 0:158c61bb030f | 21 | * Upon yielding or termination the Fiber returns the value of the last |
mzta | 0:158c61bb030f | 22 | * executed expression |
mzta | 0:158c61bb030f | 23 | * |
mzta | 0:158c61bb030f | 24 | * For instance: |
mzta | 0:158c61bb030f | 25 | * |
mzta | 0:158c61bb030f | 26 | * fiber = Fiber.new do |
mzta | 0:158c61bb030f | 27 | * Fiber.yield 1 |
mzta | 0:158c61bb030f | 28 | * 2 |
mzta | 0:158c61bb030f | 29 | * end |
mzta | 0:158c61bb030f | 30 | * |
mzta | 0:158c61bb030f | 31 | * puts fiber.resume |
mzta | 0:158c61bb030f | 32 | * puts fiber.resume |
mzta | 0:158c61bb030f | 33 | * puts fiber.resume |
mzta | 0:158c61bb030f | 34 | * |
mzta | 0:158c61bb030f | 35 | * <em>produces</em> |
mzta | 0:158c61bb030f | 36 | * |
mzta | 0:158c61bb030f | 37 | * 1 |
mzta | 0:158c61bb030f | 38 | * 2 |
mzta | 0:158c61bb030f | 39 | * resuming dead fiber (FiberError) |
mzta | 0:158c61bb030f | 40 | * |
mzta | 0:158c61bb030f | 41 | * The <code>Fiber#resume</code> method accepts an arbitrary number of |
mzta | 0:158c61bb030f | 42 | * parameters, if it is the first call to <code>resume</code> then they |
mzta | 0:158c61bb030f | 43 | * will be passed as block arguments. Otherwise they will be the return |
mzta | 0:158c61bb030f | 44 | * value of the call to <code>Fiber.yield</code> |
mzta | 0:158c61bb030f | 45 | * |
mzta | 0:158c61bb030f | 46 | * Example: |
mzta | 0:158c61bb030f | 47 | * |
mzta | 0:158c61bb030f | 48 | * fiber = Fiber.new do |first| |
mzta | 0:158c61bb030f | 49 | * second = Fiber.yield first + 2 |
mzta | 0:158c61bb030f | 50 | * end |
mzta | 0:158c61bb030f | 51 | * |
mzta | 0:158c61bb030f | 52 | * puts fiber.resume 10 |
mzta | 0:158c61bb030f | 53 | * puts fiber.resume 14 |
mzta | 0:158c61bb030f | 54 | * puts fiber.resume 18 |
mzta | 0:158c61bb030f | 55 | * |
mzta | 0:158c61bb030f | 56 | * <em>produces</em> |
mzta | 0:158c61bb030f | 57 | * |
mzta | 0:158c61bb030f | 58 | * 12 |
mzta | 0:158c61bb030f | 59 | * 14 |
mzta | 0:158c61bb030f | 60 | * resuming dead fiber (FiberError) |
mzta | 0:158c61bb030f | 61 | * |
mzta | 0:158c61bb030f | 62 | */ |
mzta | 0:158c61bb030f | 63 | static mrb_value |
mzta | 0:158c61bb030f | 64 | fiber_init(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 65 | { |
mzta | 0:158c61bb030f | 66 | static const struct mrb_context mrb_context_zero = { 0 }; |
mzta | 0:158c61bb030f | 67 | struct RFiber *f = fiber_ptr(self); |
mzta | 0:158c61bb030f | 68 | struct mrb_context *c; |
mzta | 0:158c61bb030f | 69 | struct RProc *p; |
mzta | 0:158c61bb030f | 70 | mrb_callinfo *ci; |
mzta | 0:158c61bb030f | 71 | mrb_value blk; |
mzta | 0:158c61bb030f | 72 | size_t slen; |
mzta | 0:158c61bb030f | 73 | |
mzta | 0:158c61bb030f | 74 | mrb_get_args(mrb, "&", &blk); |
mzta | 0:158c61bb030f | 75 | |
mzta | 0:158c61bb030f | 76 | if (mrb_nil_p(blk)) { |
mzta | 0:158c61bb030f | 77 | mrb_raise(mrb, E_ARGUMENT_ERROR, "tried to create Fiber object without a block"); |
mzta | 0:158c61bb030f | 78 | } |
mzta | 0:158c61bb030f | 79 | p = mrb_proc_ptr(blk); |
mzta | 0:158c61bb030f | 80 | if (MRB_PROC_CFUNC_P(p)) { |
mzta | 0:158c61bb030f | 81 | mrb_raise(mrb, E_FIBER_ERROR, "tried to create Fiber from C defined method"); |
mzta | 0:158c61bb030f | 82 | } |
mzta | 0:158c61bb030f | 83 | |
mzta | 0:158c61bb030f | 84 | f->cxt = (struct mrb_context*)mrb_malloc(mrb, sizeof(struct mrb_context)); |
mzta | 0:158c61bb030f | 85 | *f->cxt = mrb_context_zero; |
mzta | 0:158c61bb030f | 86 | c = f->cxt; |
mzta | 0:158c61bb030f | 87 | |
mzta | 0:158c61bb030f | 88 | /* initialize VM stack */ |
mzta | 0:158c61bb030f | 89 | slen = FIBER_STACK_INIT_SIZE; |
mzta | 0:158c61bb030f | 90 | if (p->body.irep->nregs > slen) { |
mzta | 0:158c61bb030f | 91 | slen += p->body.irep->nregs; |
mzta | 0:158c61bb030f | 92 | } |
mzta | 0:158c61bb030f | 93 | c->stbase = (mrb_value *)mrb_malloc(mrb, slen*sizeof(mrb_value)); |
mzta | 0:158c61bb030f | 94 | c->stend = c->stbase + slen; |
mzta | 0:158c61bb030f | 95 | c->stack = c->stbase; |
mzta | 0:158c61bb030f | 96 | |
mzta | 0:158c61bb030f | 97 | #ifdef MRB_NAN_BOXING |
mzta | 0:158c61bb030f | 98 | { |
mzta | 0:158c61bb030f | 99 | mrb_value *p = c->stbase; |
mzta | 0:158c61bb030f | 100 | mrb_value *pend = c->stend; |
mzta | 0:158c61bb030f | 101 | |
mzta | 0:158c61bb030f | 102 | while (p < pend) { |
mzta | 0:158c61bb030f | 103 | SET_NIL_VALUE(*p); |
mzta | 0:158c61bb030f | 104 | p++; |
mzta | 0:158c61bb030f | 105 | } |
mzta | 0:158c61bb030f | 106 | } |
mzta | 0:158c61bb030f | 107 | #else |
mzta | 0:158c61bb030f | 108 | memset(c->stbase, 0, slen * sizeof(mrb_value)); |
mzta | 0:158c61bb030f | 109 | #endif |
mzta | 0:158c61bb030f | 110 | |
mzta | 0:158c61bb030f | 111 | /* copy receiver from a block */ |
mzta | 0:158c61bb030f | 112 | c->stack[0] = mrb->c->stack[0]; |
mzta | 0:158c61bb030f | 113 | |
mzta | 0:158c61bb030f | 114 | /* initialize callinfo stack */ |
mzta | 0:158c61bb030f | 115 | c->cibase = (mrb_callinfo *)mrb_calloc(mrb, FIBER_CI_INIT_SIZE, sizeof(mrb_callinfo)); |
mzta | 0:158c61bb030f | 116 | c->ciend = c->cibase + FIBER_CI_INIT_SIZE; |
mzta | 0:158c61bb030f | 117 | c->ci = c->cibase; |
mzta | 0:158c61bb030f | 118 | c->ci->stackent = c->stack; |
mzta | 0:158c61bb030f | 119 | |
mzta | 0:158c61bb030f | 120 | /* adjust return callinfo */ |
mzta | 0:158c61bb030f | 121 | ci = c->ci; |
mzta | 0:158c61bb030f | 122 | ci->target_class = p->target_class; |
mzta | 0:158c61bb030f | 123 | ci->proc = p; |
mzta | 0:158c61bb030f | 124 | ci->pc = p->body.irep->iseq; |
mzta | 0:158c61bb030f | 125 | ci->nregs = p->body.irep->nregs; |
mzta | 0:158c61bb030f | 126 | ci[1] = ci[0]; |
mzta | 0:158c61bb030f | 127 | c->ci++; /* push dummy callinfo */ |
mzta | 0:158c61bb030f | 128 | |
mzta | 0:158c61bb030f | 129 | c->fib = f; |
mzta | 0:158c61bb030f | 130 | c->status = MRB_FIBER_CREATED; |
mzta | 0:158c61bb030f | 131 | |
mzta | 0:158c61bb030f | 132 | return self; |
mzta | 0:158c61bb030f | 133 | } |
mzta | 0:158c61bb030f | 134 | |
mzta | 0:158c61bb030f | 135 | static struct mrb_context* |
mzta | 0:158c61bb030f | 136 | fiber_check(mrb_state *mrb, mrb_value fib) |
mzta | 0:158c61bb030f | 137 | { |
mzta | 0:158c61bb030f | 138 | struct RFiber *f = fiber_ptr(fib); |
mzta | 0:158c61bb030f | 139 | |
mzta | 0:158c61bb030f | 140 | mrb_assert(f->tt == MRB_TT_FIBER); |
mzta | 0:158c61bb030f | 141 | if (!f->cxt) { |
mzta | 0:158c61bb030f | 142 | mrb_raise(mrb, E_FIBER_ERROR, "uninitialized Fiber"); |
mzta | 0:158c61bb030f | 143 | } |
mzta | 0:158c61bb030f | 144 | return f->cxt; |
mzta | 0:158c61bb030f | 145 | } |
mzta | 0:158c61bb030f | 146 | |
mzta | 0:158c61bb030f | 147 | static mrb_value |
mzta | 0:158c61bb030f | 148 | fiber_result(mrb_state *mrb, const mrb_value *a, mrb_int len) |
mzta | 0:158c61bb030f | 149 | { |
mzta | 0:158c61bb030f | 150 | if (len == 0) return mrb_nil_value(); |
mzta | 0:158c61bb030f | 151 | if (len == 1) return a[0]; |
mzta | 0:158c61bb030f | 152 | return mrb_ary_new_from_values(mrb, len, a); |
mzta | 0:158c61bb030f | 153 | } |
mzta | 0:158c61bb030f | 154 | |
mzta | 0:158c61bb030f | 155 | /* mark return from context modifying method */ |
mzta | 0:158c61bb030f | 156 | #define MARK_CONTEXT_MODIFY(c) (c)->ci->target_class = NULL |
mzta | 0:158c61bb030f | 157 | |
mzta | 0:158c61bb030f | 158 | static mrb_value |
mzta | 0:158c61bb030f | 159 | fiber_switch(mrb_state *mrb, mrb_value self, mrb_int len, const mrb_value *a, mrb_bool resume) |
mzta | 0:158c61bb030f | 160 | { |
mzta | 0:158c61bb030f | 161 | struct mrb_context *c = fiber_check(mrb, self); |
mzta | 0:158c61bb030f | 162 | mrb_callinfo *ci; |
mzta | 0:158c61bb030f | 163 | |
mzta | 0:158c61bb030f | 164 | for (ci = c->ci; ci >= c->cibase; ci--) { |
mzta | 0:158c61bb030f | 165 | if (ci->acc < 0) { |
mzta | 0:158c61bb030f | 166 | mrb_raise(mrb, E_FIBER_ERROR, "can't cross C function boundary"); |
mzta | 0:158c61bb030f | 167 | } |
mzta | 0:158c61bb030f | 168 | } |
mzta | 0:158c61bb030f | 169 | if (resume && c->status == MRB_FIBER_TRANSFERRED) { |
mzta | 0:158c61bb030f | 170 | mrb_raise(mrb, E_FIBER_ERROR, "resuming transfered fiber"); |
mzta | 0:158c61bb030f | 171 | } |
mzta | 0:158c61bb030f | 172 | if (c->status == MRB_FIBER_RUNNING || c->status == MRB_FIBER_RESUMING) { |
mzta | 0:158c61bb030f | 173 | mrb_raise(mrb, E_FIBER_ERROR, "double resume"); |
mzta | 0:158c61bb030f | 174 | } |
mzta | 0:158c61bb030f | 175 | if (c->status == MRB_FIBER_TERMINATED) { |
mzta | 0:158c61bb030f | 176 | mrb_raise(mrb, E_FIBER_ERROR, "resuming dead fiber"); |
mzta | 0:158c61bb030f | 177 | } |
mzta | 0:158c61bb030f | 178 | mrb->c->status = resume ? MRB_FIBER_RESUMING : MRB_FIBER_TRANSFERRED; |
mzta | 0:158c61bb030f | 179 | c->prev = resume ? mrb->c : (c->prev ? c->prev : mrb->root_c); |
mzta | 0:158c61bb030f | 180 | if (c->status == MRB_FIBER_CREATED) { |
mzta | 0:158c61bb030f | 181 | mrb_value *b = c->stack+1; |
mzta | 0:158c61bb030f | 182 | mrb_value *e = b + len; |
mzta | 0:158c61bb030f | 183 | |
mzta | 0:158c61bb030f | 184 | while (b<e) { |
mzta | 0:158c61bb030f | 185 | *b++ = *a++; |
mzta | 0:158c61bb030f | 186 | } |
mzta | 0:158c61bb030f | 187 | c->cibase->argc = len; |
mzta | 0:158c61bb030f | 188 | if (c->prev->fib) |
mzta | 0:158c61bb030f | 189 | mrb_field_write_barrier(mrb, (struct RBasic*)c->fib, (struct RBasic*)c->prev->fib); |
mzta | 0:158c61bb030f | 190 | mrb_write_barrier(mrb, (struct RBasic*)c->fib); |
mzta | 0:158c61bb030f | 191 | c->status = MRB_FIBER_RUNNING; |
mzta | 0:158c61bb030f | 192 | mrb->c = c; |
mzta | 0:158c61bb030f | 193 | |
mzta | 0:158c61bb030f | 194 | MARK_CONTEXT_MODIFY(c); |
mzta | 0:158c61bb030f | 195 | return c->ci->proc->env->stack[0]; |
mzta | 0:158c61bb030f | 196 | } |
mzta | 0:158c61bb030f | 197 | MARK_CONTEXT_MODIFY(c); |
mzta | 0:158c61bb030f | 198 | if (c->prev->fib) |
mzta | 0:158c61bb030f | 199 | mrb_field_write_barrier(mrb, (struct RBasic*)c->fib, (struct RBasic*)c->prev->fib); |
mzta | 0:158c61bb030f | 200 | mrb_write_barrier(mrb, (struct RBasic*)c->fib); |
mzta | 0:158c61bb030f | 201 | c->status = MRB_FIBER_RUNNING; |
mzta | 0:158c61bb030f | 202 | mrb->c = c; |
mzta | 0:158c61bb030f | 203 | return fiber_result(mrb, a, len); |
mzta | 0:158c61bb030f | 204 | } |
mzta | 0:158c61bb030f | 205 | |
mzta | 0:158c61bb030f | 206 | /* |
mzta | 0:158c61bb030f | 207 | * call-seq: |
mzta | 0:158c61bb030f | 208 | * fiber.resume(args, ...) -> obj |
mzta | 0:158c61bb030f | 209 | * |
mzta | 0:158c61bb030f | 210 | * Resumes the fiber from the point at which the last <code>Fiber.yield</code> |
mzta | 0:158c61bb030f | 211 | * was called, or starts running it if it is the first call to |
mzta | 0:158c61bb030f | 212 | * <code>resume</code>. Arguments passed to resume will be the value of |
mzta | 0:158c61bb030f | 213 | * the <code>Fiber.yield</code> expression or will be passed as block |
mzta | 0:158c61bb030f | 214 | * parameters to the fiber's block if this is the first <code>resume</code>. |
mzta | 0:158c61bb030f | 215 | * |
mzta | 0:158c61bb030f | 216 | * Alternatively, when resume is called it evaluates to the arguments passed |
mzta | 0:158c61bb030f | 217 | * to the next <code>Fiber.yield</code> statement inside the fiber's block |
mzta | 0:158c61bb030f | 218 | * or to the block value if it runs to completion without any |
mzta | 0:158c61bb030f | 219 | * <code>Fiber.yield</code> |
mzta | 0:158c61bb030f | 220 | */ |
mzta | 0:158c61bb030f | 221 | static mrb_value |
mzta | 0:158c61bb030f | 222 | fiber_resume(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 223 | { |
mzta | 0:158c61bb030f | 224 | mrb_value *a; |
mzta | 0:158c61bb030f | 225 | mrb_int len; |
mzta | 0:158c61bb030f | 226 | |
mzta | 0:158c61bb030f | 227 | mrb_get_args(mrb, "*", &a, &len); |
mzta | 0:158c61bb030f | 228 | return fiber_switch(mrb, self, len, a, TRUE); |
mzta | 0:158c61bb030f | 229 | } |
mzta | 0:158c61bb030f | 230 | |
mzta | 0:158c61bb030f | 231 | /* |
mzta | 0:158c61bb030f | 232 | * call-seq: |
mzta | 0:158c61bb030f | 233 | * fiber.alive? -> true or false |
mzta | 0:158c61bb030f | 234 | * |
mzta | 0:158c61bb030f | 235 | * Returns true if the fiber can still be resumed. After finishing |
mzta | 0:158c61bb030f | 236 | * execution of the fiber block this method will always return false. |
mzta | 0:158c61bb030f | 237 | */ |
mzta | 0:158c61bb030f | 238 | static mrb_value |
mzta | 0:158c61bb030f | 239 | fiber_alive_p(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 240 | { |
mzta | 0:158c61bb030f | 241 | struct mrb_context *c = fiber_check(mrb, self); |
mzta | 0:158c61bb030f | 242 | return mrb_bool_value(c->status != MRB_FIBER_TERMINATED); |
mzta | 0:158c61bb030f | 243 | } |
mzta | 0:158c61bb030f | 244 | |
mzta | 0:158c61bb030f | 245 | static mrb_value |
mzta | 0:158c61bb030f | 246 | fiber_eq(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 247 | { |
mzta | 0:158c61bb030f | 248 | mrb_value other; |
mzta | 0:158c61bb030f | 249 | mrb_get_args(mrb, "o", &other); |
mzta | 0:158c61bb030f | 250 | |
mzta | 0:158c61bb030f | 251 | if (mrb_type(other) != MRB_TT_FIBER) { |
mzta | 0:158c61bb030f | 252 | return mrb_false_value(); |
mzta | 0:158c61bb030f | 253 | } |
mzta | 0:158c61bb030f | 254 | return mrb_bool_value(fiber_ptr(self) == fiber_ptr(other)); |
mzta | 0:158c61bb030f | 255 | } |
mzta | 0:158c61bb030f | 256 | |
mzta | 0:158c61bb030f | 257 | /* |
mzta | 0:158c61bb030f | 258 | * call-seq: |
mzta | 0:158c61bb030f | 259 | * fiber.transfer(args, ...) -> obj |
mzta | 0:158c61bb030f | 260 | * |
mzta | 0:158c61bb030f | 261 | * Transfers control to reciever fiber of the method call. |
mzta | 0:158c61bb030f | 262 | * Unlike <code>resume</code> the reciever wouldn't be pushed to call |
mzta | 0:158c61bb030f | 263 | * stack of fibers. Instead it will switch to the call stack of |
mzta | 0:158c61bb030f | 264 | * transferring fiber. |
mzta | 0:158c61bb030f | 265 | * When resuming a fiber that was transferred to another fiber it would |
mzta | 0:158c61bb030f | 266 | * cause double resume error. Though when the fiber is re-transferred |
mzta | 0:158c61bb030f | 267 | * and <code>Fiber.yield</code> is called, the fiber would be resumable. |
mzta | 0:158c61bb030f | 268 | */ |
mzta | 0:158c61bb030f | 269 | static mrb_value |
mzta | 0:158c61bb030f | 270 | fiber_transfer(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 271 | { |
mzta | 0:158c61bb030f | 272 | struct mrb_context *c = fiber_check(mrb, self); |
mzta | 0:158c61bb030f | 273 | mrb_value* a; |
mzta | 0:158c61bb030f | 274 | mrb_int len; |
mzta | 0:158c61bb030f | 275 | |
mzta | 0:158c61bb030f | 276 | mrb_get_args(mrb, "*", &a, &len); |
mzta | 0:158c61bb030f | 277 | |
mzta | 0:158c61bb030f | 278 | if (c == mrb->root_c) { |
mzta | 0:158c61bb030f | 279 | mrb->c->status = MRB_FIBER_TRANSFERRED; |
mzta | 0:158c61bb030f | 280 | mrb->c = c; |
mzta | 0:158c61bb030f | 281 | c->status = MRB_FIBER_RUNNING; |
mzta | 0:158c61bb030f | 282 | MARK_CONTEXT_MODIFY(c); |
mzta | 0:158c61bb030f | 283 | mrb_write_barrier(mrb, (struct RBasic*)c->fib); |
mzta | 0:158c61bb030f | 284 | return fiber_result(mrb, a, len); |
mzta | 0:158c61bb030f | 285 | } |
mzta | 0:158c61bb030f | 286 | |
mzta | 0:158c61bb030f | 287 | if (c == mrb->c) { |
mzta | 0:158c61bb030f | 288 | return fiber_result(mrb, a, len); |
mzta | 0:158c61bb030f | 289 | } |
mzta | 0:158c61bb030f | 290 | |
mzta | 0:158c61bb030f | 291 | return fiber_switch(mrb, self, len, a, FALSE); |
mzta | 0:158c61bb030f | 292 | } |
mzta | 0:158c61bb030f | 293 | |
mzta | 0:158c61bb030f | 294 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 295 | mrb_fiber_yield(mrb_state *mrb, mrb_int len, const mrb_value *a) |
mzta | 0:158c61bb030f | 296 | { |
mzta | 0:158c61bb030f | 297 | struct mrb_context *c = mrb->c; |
mzta | 0:158c61bb030f | 298 | mrb_callinfo *ci; |
mzta | 0:158c61bb030f | 299 | |
mzta | 0:158c61bb030f | 300 | for (ci = c->ci; ci >= c->cibase; ci--) { |
mzta | 0:158c61bb030f | 301 | if (ci->acc < 0) { |
mzta | 0:158c61bb030f | 302 | mrb_raise(mrb, E_FIBER_ERROR, "can't cross C function boundary"); |
mzta | 0:158c61bb030f | 303 | } |
mzta | 0:158c61bb030f | 304 | } |
mzta | 0:158c61bb030f | 305 | if (!c->prev) { |
mzta | 0:158c61bb030f | 306 | mrb_raise(mrb, E_FIBER_ERROR, "can't yield from root fiber"); |
mzta | 0:158c61bb030f | 307 | } |
mzta | 0:158c61bb030f | 308 | |
mzta | 0:158c61bb030f | 309 | c->prev->status = MRB_FIBER_RUNNING; |
mzta | 0:158c61bb030f | 310 | c->status = MRB_FIBER_SUSPENDED; |
mzta | 0:158c61bb030f | 311 | mrb->c = c->prev; |
mzta | 0:158c61bb030f | 312 | c->prev = NULL; |
mzta | 0:158c61bb030f | 313 | MARK_CONTEXT_MODIFY(mrb->c); |
mzta | 0:158c61bb030f | 314 | mrb_write_barrier(mrb, (struct RBasic*)c->fib); |
mzta | 0:158c61bb030f | 315 | return fiber_result(mrb, a, len); |
mzta | 0:158c61bb030f | 316 | } |
mzta | 0:158c61bb030f | 317 | |
mzta | 0:158c61bb030f | 318 | /* |
mzta | 0:158c61bb030f | 319 | * call-seq: |
mzta | 0:158c61bb030f | 320 | * Fiber.yield(args, ...) -> obj |
mzta | 0:158c61bb030f | 321 | * |
mzta | 0:158c61bb030f | 322 | * Yields control back to the context that resumed the fiber, passing |
mzta | 0:158c61bb030f | 323 | * along any arguments that were passed to it. The fiber will resume |
mzta | 0:158c61bb030f | 324 | * processing at this point when <code>resume</code> is called next. |
mzta | 0:158c61bb030f | 325 | * Any arguments passed to the next <code>resume</code> will be the |
mzta | 0:158c61bb030f | 326 | * value that this <code>Fiber.yield</code> expression evaluates to. |
mzta | 0:158c61bb030f | 327 | */ |
mzta | 0:158c61bb030f | 328 | static mrb_value |
mzta | 0:158c61bb030f | 329 | fiber_yield(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 330 | { |
mzta | 0:158c61bb030f | 331 | mrb_value *a; |
mzta | 0:158c61bb030f | 332 | mrb_int len; |
mzta | 0:158c61bb030f | 333 | |
mzta | 0:158c61bb030f | 334 | mrb_get_args(mrb, "*", &a, &len); |
mzta | 0:158c61bb030f | 335 | return mrb_fiber_yield(mrb, len, a); |
mzta | 0:158c61bb030f | 336 | } |
mzta | 0:158c61bb030f | 337 | |
mzta | 0:158c61bb030f | 338 | /* |
mzta | 0:158c61bb030f | 339 | * call-seq: |
mzta | 0:158c61bb030f | 340 | * Fiber.current() -> fiber |
mzta | 0:158c61bb030f | 341 | * |
mzta | 0:158c61bb030f | 342 | * Returns the current fiber. If you are not running in the context of |
mzta | 0:158c61bb030f | 343 | * a fiber this method will return the root fiber. |
mzta | 0:158c61bb030f | 344 | */ |
mzta | 0:158c61bb030f | 345 | static mrb_value |
mzta | 0:158c61bb030f | 346 | fiber_current(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 347 | { |
mzta | 0:158c61bb030f | 348 | if (!mrb->c->fib) { |
mzta | 0:158c61bb030f | 349 | struct RFiber *f = (struct RFiber*)mrb_obj_alloc(mrb, MRB_TT_FIBER, mrb_class_ptr(self)); |
mzta | 0:158c61bb030f | 350 | |
mzta | 0:158c61bb030f | 351 | f->cxt = mrb->c; |
mzta | 0:158c61bb030f | 352 | mrb->c->fib = f; |
mzta | 0:158c61bb030f | 353 | } |
mzta | 0:158c61bb030f | 354 | return mrb_obj_value(mrb->c->fib); |
mzta | 0:158c61bb030f | 355 | } |
mzta | 0:158c61bb030f | 356 | |
mzta | 0:158c61bb030f | 357 | void |
mzta | 0:158c61bb030f | 358 | mrb_mruby_fiber_gem_init(mrb_state* mrb) |
mzta | 0:158c61bb030f | 359 | { |
mzta | 0:158c61bb030f | 360 | struct RClass *c; |
mzta | 0:158c61bb030f | 361 | |
mzta | 0:158c61bb030f | 362 | c = mrb_define_class(mrb, "Fiber", mrb->object_class); |
mzta | 0:158c61bb030f | 363 | MRB_SET_INSTANCE_TT(c, MRB_TT_FIBER); |
mzta | 0:158c61bb030f | 364 | |
mzta | 0:158c61bb030f | 365 | mrb_define_method(mrb, c, "initialize", fiber_init, MRB_ARGS_NONE()); |
mzta | 0:158c61bb030f | 366 | mrb_define_method(mrb, c, "resume", fiber_resume, MRB_ARGS_ANY()); |
mzta | 0:158c61bb030f | 367 | mrb_define_method(mrb, c, "transfer", fiber_transfer, MRB_ARGS_ANY()); |
mzta | 0:158c61bb030f | 368 | mrb_define_method(mrb, c, "alive?", fiber_alive_p, MRB_ARGS_NONE()); |
mzta | 0:158c61bb030f | 369 | mrb_define_method(mrb, c, "==", fiber_eq, MRB_ARGS_REQ(1)); |
mzta | 0:158c61bb030f | 370 | |
mzta | 0:158c61bb030f | 371 | mrb_define_class_method(mrb, c, "yield", fiber_yield, MRB_ARGS_ANY()); |
mzta | 0:158c61bb030f | 372 | mrb_define_class_method(mrb, c, "current", fiber_current, MRB_ARGS_NONE()); |
mzta | 0:158c61bb030f | 373 | |
mzta | 0:158c61bb030f | 374 | mrb_define_class(mrb, "FiberError", mrb->eStandardError_class); |
mzta | 0:158c61bb030f | 375 | } |
mzta | 0:158c61bb030f | 376 | |
mzta | 0:158c61bb030f | 377 | void |
mzta | 0:158c61bb030f | 378 | mrb_mruby_fiber_gem_final(mrb_state* mrb) |
mzta | 0:158c61bb030f | 379 | { |
mzta | 0:158c61bb030f | 380 | } |
mzta | 0:158c61bb030f | 381 |