File: CoroAPI.h

package info (click to toggle)
libcoro-perl 6.570-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,144 kB
  • sloc: ansic: 2,560; perl: 2,122; makefile: 14
file content (130 lines) | stat: -rw-r--r-- 5,222 bytes parent folder | download | duplicates (3)
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
#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