| 12
 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
 
 | #ifndef CORO_API_H
#define CORO_API_H
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#ifndef pTHX_
# define pTHX_
# define aTHX_
# define pTHX
# define aTHX
#endif
/* C-level coroutine struct, opaque, not used much */
struct coro;
/* used for schedule-like-function prepares */
struct coro_transfer_args
{
  struct coro *prev, *next;
};
/* this is the per-perl-coro slf frame info
 * it is treated like other "global" interpreter data
 * and unfortunately is copied around, so keep it small
 *
 * Workflow:
 *
 * 1. init function is called to parse arguments and fill out the CoroSLF frame
 * 2. loop starts by calling frame->prepare, providing transfer arguments
 * 3. transfer is called, transsferring control to another coro
 * 4. if at this point, the coro is destroyed: frame->destroy is called, then no further processing
 * 5. otherwise: eventually control is transferred back to coro
 * 6. frame->check is called
 * 7. check returns 0 => wait not finished, loop to 2
 * 8. otherwise, check puts results on stack, returns 1 => finish
 */
struct CoroSLF
{
  void (*prepare) (pTHX_ struct coro_transfer_args *ta); /* 0 means not yet initialised */
  int (*check) (pTHX_ struct CoroSLF *frame);
  void *data; /* for use by prepare/check/destroy */
  void (*destroy) (pTHX_ struct CoroSLF *frame);
};
/* needs to fill in the *frame */
typedef void (*coro_slf_cb) (pTHX_ struct CoroSLF *frame, CV *cv, SV **arg, int items);
/* called on enter/leave */
typedef void (*coro_enterleave_hook) (pTHX_ void *arg);
/* private structure, always use the provided macros below */
struct CoroAPI
{
  /* private */
  I32 ver;
  I32 rev;
#define CORO_API_VERSION 7 /* reorder CoroSLF on change */
#define CORO_API_REVISION 2
  /* Coro */
  int nready;
  SV *current;
  SV *except;
  void (*readyhook) (void);
  void (*schedule) (pTHX);
  void (*schedule_to) (pTHX_ SV *coro_sv);
  int (*cede) (pTHX);
  int (*cede_notself) (pTHX);
  int (*ready) (pTHX_ SV *coro_sv);
  int (*is_ready) (pTHX_ SV *coro_sv);
  /* Coro::State */
  void (*transfer) (pTHX_ SV *prev_sv, SV *next_sv); /* Coro::State */
  /* SLF */
  struct coro *(*sv_state) (pTHX_ SV *coro_sv);
  void (*execute_slf) (pTHX_ CV *cv, coro_slf_cb init_cb, I32 ax);
  /* public */
  /* for use as CoroSLF.prepare */
  void (*prepare_nop)          (pTHX_ struct coro_transfer_args *ta);
  void (*prepare_schedule)     (pTHX_ struct coro_transfer_args *ta);
  void (*prepare_cede)         (pTHX_ struct coro_transfer_args *ta);
  void (*prepare_cede_notself) (pTHX_ struct coro_transfer_args *ta);
  /* private */
  void (*enterleave_hook)(pTHX_ SV *coro_sv, coro_enterleave_hook enter, void *enter_arg, coro_enterleave_hook leave, void *leave_arg);
  void (*enterleave_unhook)(pTHX_ SV *coro_sv, coro_enterleave_hook enter, coro_enterleave_hook leave);
  void (*enterleave_scope_hook)(pTHX_ coro_enterleave_hook enter, void *enter_arg, coro_enterleave_hook leave, void *leave_arg); /* XS caller must LEAVE/ENTER */
};
static struct CoroAPI *GCoroAPI;
/* public API macros */
#define CORO_TRANSFER(prev,next) GCoroAPI->transfer (aTHX_ (prev), (next))
#define CORO_SV_STATE(coro)      GCoroAPI->sv_state (aTHX_ (coro))
#define CORO_EXECUTE_SLF(cv,init,ax) GCoroAPI->execute_slf (aTHX_ (cv), (init), (ax))
#define CORO_EXECUTE_SLF_XS(init) CORO_EXECUTE_SLF (cv, (init), ax)
#define CORO_SCHEDULE            GCoroAPI->schedule (aTHX)
#define CORO_CEDE                GCoroAPI->cede (aTHX)
#define CORO_CEDE_NOTSELF        GCoroAPI->cede_notself (aTHX)
#define CORO_READY(coro)         GCoroAPI->ready (aTHX_ coro)
#define CORO_IS_READY(coro)      GCoroAPI->is_ready (coro)
#define CORO_NREADY              (GCoroAPI->nready)
#define CORO_THROW               (GCoroAPI->except)
#define CORO_CURRENT             SvRV (GCoroAPI->current)
#define CORO_READYHOOK           (GCoroAPI->readyhook)
#define CORO_ENTERLEAVE_HOOK(coro,enter,enter_arg,leave,leave_arg)   GCoroAPI->enterleave_hook (aTHX_ coro, enter, enter_arg, leave, leave_arg)
#define CORO_ENTERLEAVE_UNHOOK(coro,enter,leave)                     GCoroAPI->enterleave_hook (aTHX_ coro, enter           , leave           )
#define CORO_ENTERLEAVE_SCOPE_HOOK(enter,enter_arg,leave,leave_arg)  GCoroAPI->enterleave_scope_hook (aTHX_ enter, enter_arg, leave, leave_arg)
#define I_CORO_API(YourName)                                                                       \
STMT_START {                                                                                       \
  SV *sv = perl_get_sv ("Coro::API", 0);                                                           \
  if (!sv) croak ("Coro::API not found");                                                          \
  GCoroAPI = (struct CoroAPI*) SvIV (sv);                                                          \
  if (GCoroAPI->ver != CORO_API_VERSION                                                            \
      || GCoroAPI->rev < CORO_API_REVISION)                                                        \
    croak ("Coro::API version mismatch (%d.%d vs. %d.%d) -- please recompile %s",                  \
           (int)GCoroAPI->ver, (int)GCoroAPI->rev, CORO_API_VERSION, CORO_API_REVISION, YourName); \
} STMT_END
#endif
 |