|
| 1 | +.. highlightlang:: c |
| 2 | + |
| 3 | +.. comment: affected files: data\refcounts.dat |
| 4 | +.. comment: affected files: c-api\stackless.rst |
| 5 | +.. comment: to do: link c-api\stackless.rst in somewhere |
| 6 | +.. comment: to do: generate new docs |
| 7 | +
|
| 8 | +Tasklets |
| 9 | +-------- |
| 10 | + |
| 11 | +.. c:function:: PyTaskletObject *PyTasklet_New(PyTypeObject *type, PyObject *func) |
| 12 | +
|
| 13 | + Return a new tasklet object. *type* must be derived from :c:type:`PyTasklet_Type` |
| 14 | + or *NULL*. *func* must be a callable object (normal use-case) or *NULL*, if the |
| 15 | + tasklet is being used via capture(). |
| 16 | +
|
| 17 | +.. todo: in the case where NULL is returned and slp_ensure_linkage fails no |
| 18 | + exception is set, which is in contrast elsewhere in the function. |
| 19 | +
|
| 20 | +.. c:function:: int PyTasklet_Setup(PyTaskletObject *task, PyObject *args, PyObject *kwds) |
| 21 | + |
| 22 | + Binds a tasklet function to parameters, making it ready to run and inserts in |
| 23 | + into the runnables queue. Returns ``0`` if successful or ``-1`` in the case of failure. |
| 24 | +
|
| 25 | +.. c:function:: int PyTasklet_Run(PyTaskletObject *task) |
| 26 | +
|
| 27 | + Forces *task* to run immediately. Returns ``0`` if successful, and ``-1`` in the |
| 28 | + case of failure. |
| 29 | +
|
| 30 | +.. c:function:: int PyTasklet_Run_nr(PyTaskletObject *task) |
| 31 | +
|
| 32 | + Forces *task* to run immediately, soft switching if possible. Returns ``1`` if |
| 33 | + the call soft switched, ``0`` if the call hard switched and -1 in the case of |
| 34 | + failure. |
| 35 | +
|
| 36 | +.. c:function:: int PyTasklet_Remove(PyTaskletObject *task) |
| 37 | +
|
| 38 | + Removes *task* from the runnables queue. Be careful! If this tasklet has a C |
| 39 | + stack attached, you need to either resume running it or kill it. Just dropping |
| 40 | + it might give an inconsistent system state. Returns ``0`` if successful, and |
| 41 | + ``-1`` in the case of failure. |
| 42 | +
|
| 43 | +.. c:function:: int PyTasklet_Insert(PyTaskletObject *task) |
| 44 | +
|
| 45 | + Insert *task* into the runnables queue, if it isn't already there. If it is |
| 46 | + blocked or dead, the function returns ``-1`` and a :exc:`RuntimeError` is raised. |
| 47 | +
|
| 48 | +.. c:function:: PyObject *PyTasklet_Become(PyTaskletObject *self, PyObject *retval) |
| 49 | +
|
| 50 | + Use of this API function is undocumented and unrecommended. |
| 51 | +
|
| 52 | + .. deprecated:: 2.5 |
| 53 | + Proved problematic in production use and are pending removal. |
| 54 | +
|
| 55 | +.. c:function:: PyObject* PyTasklet_Capture(PyTaskletObject *self, PyObject *retval) |
| 56 | +
|
| 57 | + Use of this API function is undocumented and unrecommended. |
| 58 | +
|
| 59 | + .. deprecated:: 2.5 |
| 60 | + Proved problematic in production use and are pending removal. |
| 61 | +
|
| 62 | +.. c:function:: int PyTasklet_RaiseException(PyTaskletObject *self, PyObject *klass, PyObject *args) |
| 63 | +
|
| 64 | + Raises an instance of the *klass* exception on the *self* tasklet. *klass* must |
| 65 | + be a subclass of :exc:`Exception`. Returns ``1`` if the call soft switched, ``0`` |
| 66 | + if the call hard switched and ``-1`` in the case of failure. |
| 67 | +
|
| 68 | + .. note:: Raising :exc:`TaskletExit` on a tasklet can be done to silently kill |
| 69 | + it, see :c:func:`PyTasklet_Kill`. |
| 70 | +
|
| 71 | +.. c:function:: int PyTasklet_Kill(PyTaskletObject *self) |
| 72 | + |
| 73 | + Raises :exc:`TaskletExit` on tasklet *self*. This should result in *task* being |
| 74 | + silently killed. Returns ``1`` if the call soft switched, ``0`` if the call hard |
| 75 | + switched and ``-1`` in the case of failure. |
| 76 | +
|
| 77 | +.. c:function:: int PyTasklet_GetAtomic(PyTaskletObject *task) |
| 78 | +
|
| 79 | + Returns ``1`` if *task* is atomic, otherwise ``0``. |
| 80 | +
|
| 81 | +.. c:function:: int PyTasklet_SetAtomic(PyTaskletObject *task, int flag) |
| 82 | + |
| 83 | + Returns ``1`` if *task* is currently atomic, otherwise ``0``. Sets the |
| 84 | + atomic attribute to the logical value of *flag*. |
| 85 | +
|
| 86 | +.. c:function:: int PyTasklet_GetIgnoreNesting(PyTaskletObject *task) |
| 87 | +
|
| 88 | + Returns ``1`` if *task* ignores its nesting level when choosing whether to |
| 89 | + auto-schedule it, otherwise ``0``. |
| 90 | +
|
| 91 | +.. c:function:: int PyTasklet_SetIgnoreNesting(PyTaskletObject *task, int flag) |
| 92 | +
|
| 93 | + Returns the existing value of the *ignore_nesting* attribute for the tasklet |
| 94 | + *task*, setting it to the logical value of *flag*. If true, the tasklet may |
| 95 | + be auto-scheduled even if its *nesting_level* is > ``0``. |
| 96 | +
|
| 97 | +.. c:function:: int PyTasklet_GetBlockTrap(PyTaskletObject *task) |
| 98 | +
|
| 99 | + Returns ``1`` if *task* is designated as not being allowed to be blocked on a |
| 100 | + channel, otherwise ``0``. |
| 101 | +
|
| 102 | +.. c:function:: void PyTasklet_SetBlockTrap(PyTaskletObject *task, int value) |
| 103 | +
|
| 104 | + Returns ``1`` if *task* was already designated as not being allowed to be blocked |
| 105 | + on a channel, otherwise ``0``. This attribute is set to the logical value of |
| 106 | + *value*. |
| 107 | +
|
| 108 | +.. c:function:: PyObject *PyTasklet_GetFrame(PyTaskletObject *task) |
| 109 | +
|
| 110 | + Returns the current frame that *task* is executing in, or *NULL* |
| 111 | +
|
| 112 | +.. c:function:: int PyTasklet_IsMain(PyTaskletObject *task) |
| 113 | +
|
| 114 | + Returns ``1`` if *task* is the main tasklet, otherwise ``0``. |
| 115 | +
|
| 116 | +.. c:function:: int PyTasklet_IsCurrent(PyTaskletObject *task) |
| 117 | +
|
| 118 | + Returns ``1`` if *task* is the current tasklet, otherwise ``0``. |
| 119 | +
|
| 120 | +.. c:function:: int PyTasklet_GetRecursionDepth(PyTaskletObject *task) |
| 121 | +
|
| 122 | + Return the current recursion depth of *task*. |
| 123 | +
|
| 124 | +.. c:function:: int PyTasklet_GetNestingLevel(PyTaskletObject *task) |
| 125 | +
|
| 126 | + Return the current nesting level of *task*. |
| 127 | +
|
| 128 | +.. c:function:: int PyTasklet_Alive(PyTaskletObject *task) |
| 129 | +
|
| 130 | + Returns ``1`` if *task* is alive (has an associated frame), otherwise |
| 131 | + ``0`` if it is dead. |
| 132 | + |
| 133 | +.. c:function:: int PyTasklet_Paused(PyTaskletObject *task) |
| 134 | +
|
| 135 | + Returns ``1`` if *task* is paused, otherwise ``0``. A tasklet is paused if it is |
| 136 | + alive, but not scheduled or blocked on a channel. |
| 137 | +
|
| 138 | +.. c:function:: int PyTasklet_Scheduled(PyTaskletObject *task) |
| 139 | +
|
| 140 | + Returns ``1`` if *task* is scheduled, otherwise ``0``. In the context of this |
| 141 | + function a tasklet is considered to be scheduled if it is alive, and in the |
| 142 | + scheduler runnables list or blocked on a channel. |
| 143 | +
|
| 144 | +.. c:function:: int PyTasklet_Restorable(PyTaskletObject *task) |
| 145 | +
|
| 146 | + Returns ``1`` if *task* can be fully unpickled, otherwise ``0``. A tasklet can |
| 147 | + be pickled whether it is fully restorable or not for the purposes of debugging |
| 148 | + and introspection. A tasklet that has been hard-switched cannot be fully |
| 149 | + pickled, for instance. |
| 150 | +
|
| 151 | +Channels |
| 152 | +-------- |
| 153 | +
|
| 154 | + .. c:function:: PyChannelObject* PyChannel_New(PyTypeObject *type) |
| 155 | +
|
| 156 | + Return a new channel object, or *NULL* in the case of failure. *type* must be |
| 157 | + derived from :c:type:`PyChannel_Type` or be *NULL*, otherwise a :exc:`TypeError` |
| 158 | + is raised. |
| 159 | +
|
| 160 | +.. c:function:: int PyChannel_Send(PyChannelObject *self, PyObject *arg) |
| 161 | +
|
| 162 | + Send *arg* on the channel *self*. Returns ``0`` if the operation was |
| 163 | + successful, or ``-1`` in the case of failure. |
| 164 | +
|
| 165 | +.. c:function:: int PyChannel_Send_nr(PyChannelObject *self, PyObject *arg) |
| 166 | +
|
| 167 | + Send *arg* on the channel *self*, soft switching if possible. Returns ``1`` if |
| 168 | + the call soft switched, ``0`` if the call hard switched and -1 in the case of |
| 169 | + failure. |
| 170 | +
|
| 171 | +.. c:function:: PyObject *PyChannel_Receive(PyChannelObject *self) |
| 172 | +
|
| 173 | + Receive on the channel *self*. Returns a |PY| object if the operation was |
| 174 | + successful, or *NULL* in the case of failure. |
| 175 | +
|
| 176 | +.. c:function:: PyObject *PyChannel_Receive_nr(PyChannelObject *self) |
| 177 | +
|
| 178 | + Receive on the channel *self*, soft switching if possible. Returns a |PY| |
| 179 | + object if the operation was successful, :c:type:`Py_UnwindToken` if a soft switch |
| 180 | + occurred, or *NULL* in the case of failure. |
| 181 | +
|
| 182 | +.. c:function:: int PyChannel_SendException(PyChannelObject *self, PyObject *klass, PyObject *value) |
| 183 | +
|
| 184 | + Returns ``0`` if successful or ``-1`` in the case of failure. An instance of the |
| 185 | + exception type *klass* is raised on the first tasklet blocked on channel *self*. |
| 186 | +
|
| 187 | +.. c:function:: PyObject *PyChannel_GetQueue(PyChannelObject *self) |
| 188 | +
|
| 189 | + Returns the first tasklet in the channel *self*'s queue, or *NULL* in the case |
| 190 | + the queue is empty. |
| 191 | +
|
| 192 | +.. c:function:: void PyChannel_Close(PyChannelObject *self) |
| 193 | +
|
| 194 | + Marks the channel *self* as closing. No further tasklets can be blocked on the |
| 195 | + it from this point, unless it is later reopened. |
| 196 | +
|
| 197 | +.. c:function:: void PyChannel_Open(PyChannelObject *self) |
| 198 | +
|
| 199 | + Reopens the channel *self*. This allows tasklets to once again send and receive |
| 200 | + on it, if those operations would otherwise block the given tasklet. |
| 201 | +
|
| 202 | +.. c:function:: int PyChannel_GetClosing(PyChannelObject *self) |
| 203 | +
|
| 204 | + Returns ``1`` if the channel *self* is marked as closing, otherwise ``0``. |
| 205 | +
|
| 206 | +.. c:function:: int PyChannel_GetClosed(PyChannelObject *self) |
| 207 | +
|
| 208 | + Returns ``1`` if the channel *self* is marked as closing and there are no tasklets |
| 209 | + blocked on it, otherwise ``0``. |
| 210 | +
|
| 211 | +.. c:function:: int PyChannel_GetPreference(PyChannelObject *self) |
| 212 | +
|
| 213 | + Returns the current scheduling preference value of *self*. See |
| 214 | + :attr:`channel.preference`. |
| 215 | +
|
| 216 | +.. c:function:: void PyChannel_SetPreference(PyChannelObject *self, int val) |
| 217 | +
|
| 218 | + Sets the current scheduling preference value of *self*. See |
| 219 | + :attr:`channel.preference`. |
| 220 | +
|
| 221 | +.. c:function:: int PyChannel_GetScheduleAll(PyChannelObject *self) |
| 222 | +
|
| 223 | + Gets the *schedule_all* override flag for *self*. See |
| 224 | + :attr:`channel.schedule_all`. |
| 225 | +
|
| 226 | +.. c:function:: void PyChannel_SetScheduleAll(PyChannelObject *self, int val) |
| 227 | +
|
| 228 | + Sets the *schedule_all* override flag for *self*. See |
| 229 | + :attr:`channel.schedule_all`. |
| 230 | +
|
| 231 | +.. c:function:: int PyChannel_GetBalance(PyChannelObject *self) |
| 232 | +
|
| 233 | + Gets the balance for *self*. See :attr:`channel.balance`. |
| 234 | +
|
| 235 | +stackless module |
| 236 | +---------------- |
| 237 | +
|
| 238 | +.. c:function:: PyObject *PyStackless_Schedule(PyObject *retval, int remove) |
| 239 | +
|
| 240 | + Suspend the current tasklet and schedule the next one in the cyclic chain. |
| 241 | + if remove is nonzero, the current tasklet will be removed from the chain. |
| 242 | + retval = success NULL = failure |
| 243 | +
|
| 244 | +.. c:function:: PyObject *PyStackless_Schedule_nr(PyObject *retval, int remove) |
| 245 | +
|
| 246 | + retval = success NULL = failure |
| 247 | + retval == Py_UnwindToken: soft switched |
| 248 | +
|
| 249 | +.. c:function:: int PyStackless_GetRunCount() |
| 250 | +
|
| 251 | + get the number of runnable tasks of the current thread, including the current one. |
| 252 | + -1 = failure |
| 253 | +
|
| 254 | +.. c:function:: PyObject *PyStackless_GetCurrent() |
| 255 | +
|
| 256 | + Get the currently running tasklet, that is, "yourself". |
| 257 | +
|
| 258 | +.. c:function:: PyObject *PyStackless_RunWatchdog(long timeout) |
| 259 | +
|
| 260 | + Runs the scheduler until there are no tasklets remaining within it, or until |
| 261 | + one of the scheduled tasklets runs for *timeout* VM instructions without |
| 262 | + blocking. Returns *None* if the scheduler is empty, a tasklet object if that |
| 263 | + tasklet timed out, or *NULL* in the case of failure. If a timed out tasklet |
| 264 | + is returned, it should be killed or reinserted. |
| 265 | +
|
| 266 | + This function can only be called from the main tasklet. |
| 267 | + During the run, main is suspended, but will be invoked |
| 268 | + after the action. You will write your exception handler |
| 269 | + here, since every uncaught exception will be directed |
| 270 | + to main. |
| 271 | +
|
| 272 | +.. c:function:: PyObject *PyStackless_RunWatchdogEx(long timeout, int flags) |
| 273 | +
|
| 274 | + Wraps :c:func:`PyStackless_RunWatchdog`, but allows its behaviour to be |
| 275 | + customised by the value of *flags* which may contain any of the following |
| 276 | + bits: |
| 277 | + |
| 278 | + ``Py_WATCHDOG_THREADBLOCK`` |
| 279 | + Allows a thread to block if it runs out of tasklets. Ideally |
| 280 | + it will be awakened by other threads using channels which its |
| 281 | + blocked tasklets are waiting on. |
| 282 | + |
| 283 | + ``Py_WATCHDOG_SOFT`` |
| 284 | + Instead of interrupting a tasklet, we wait until the |
| 285 | + next tasklet scheduling moment to return. Always returns |
| 286 | + *Py_None*, as everything is in order. |
| 287 | + |
| 288 | + ``Py_WATCHDOG_IGNORE_NESTING`` |
| 289 | + Allows interrupts at all levels, effectively acting as |
| 290 | + though the *ignore_nesting* attribute were set on all |
| 291 | + tasklets. |
| 292 | + |
| 293 | + ``Py_WATCHDOG_TIMEOUT`` |
| 294 | + Interprets *timeout* as a fixed run time, rather than a |
| 295 | + per-tasklet run limit. The function will then attempt to |
| 296 | + interrupt execution once this many total opcodes have |
| 297 | + been executed since the call was made. |
| 298 | + |
| 299 | +debugging and monitoring functions |
| 300 | +---------------------------------- |
| 301 | +
|
| 302 | +.. c:function:: int PyStackless_SetChannelCallback(PyObject *callable) |
| 303 | +
|
| 304 | + channel debugging. The callable will be called on every send or receive. |
| 305 | + Passing NULL removes the handler. |
| 306 | + Parameters of the callable: |
| 307 | + channel, tasklet, int sendflag, int willblock |
| 308 | + -1 = failure |
| 309 | +
|
| 310 | +.. c:function:: int PyStackless_SetScheduleCallback(PyObject *callable) |
| 311 | +
|
| 312 | + scheduler monitoring. |
| 313 | + The callable will be called on every scheduling. |
| 314 | + Passing NULL removes the handler. |
| 315 | + Parameters of the callable: from, to |
| 316 | + When a tasklet dies, to is None. |
| 317 | + After death or when main starts up, from is None. |
| 318 | + -1 = failure |
| 319 | +
|
| 320 | +.. c:function:: void PyStackless_SetScheduleFastcallback(slp_schedule_hook_func func) |
| 321 | +
|
| 322 | + Scheduler monitoring with a faster interface. |
| 323 | +
|
| 324 | +Interface functions |
| 325 | +------------------- |
| 326 | +
|
| 327 | +Most of the above functions can be called both from "inside" |
| 328 | +and "outside" stackless. "inside" means there should be a running |
| 329 | +(c)frame on top which acts as the "main tasklet". The functions |
| 330 | +do a check whether the main tasklet exists, and wrap themselves |
| 331 | +if it is necessary. |
| 332 | +The following routines are used to support this, and you may use |
| 333 | +them as well if you need to make your specific functions always |
| 334 | +available. |
| 335 | +
|
| 336 | +.. c:function:: PyObject *PyStackless_Call_Main(PyObject *func, PyObject *args, PyObject *kwds) |
| 337 | +
|
| 338 | + Run any callable as the "main" |PY| function. Returns a |PY| object, or |
| 339 | + *NULL* in the case of failure. |
| 340 | +
|
| 341 | +.. c:function:: PyObject *PyStackless_CallMethod_Main(PyObject *o, char *name, char *format, ...) |
| 342 | +
|
| 343 | + Convenience: Run any method as the "main" |PY| function. Wraps PyStackless_Call_Main. |
0 commit comments