33|SLP | C-API
44===========
55
6+ .. note ::
7+
8+ Some switching functions have a variant with the
9+ same name, but ending on "_nr". These are non-recursive
10+ versions with the same functionality, but they might
11+ avoid a hard stack switch.
12+ Their return value is ternary, and they require the
13+ caller to return to its frame, properly.
14+ All three different cases must be treated.
15+
16+ Ternary return from an integer function:
17+
18+ ===== ============= ===============================
19+ value meaning action
20+ ===== ============= ===============================
21+ -1 failure return NULL
22+ 1 soft switched return :c:data: `Py_UnwindToken `
23+ 0 hard switched return :c:data: `Py_None `
24+ ===== ============= ===============================
25+
26+ Ternary return from a PyObject * function:
27+
28+ ============== ============= ===============================
29+ value meaning action
30+ ============== ============= ===============================
31+ NULL failure return NULL
32+ Py_UnwindToken soft switched return :c:data: `Py_UnwindToken `
33+ other hard switched return value
34+ ============== ============= ===============================
35+
36+
637|SLP | provides the following C functions.
738
839Tasklets
@@ -262,8 +293,8 @@ Channels
262293
263294 Gets the balance for *self *. See :attr: `channel.balance `.
264295
265- stackless module
266- ----------------
296+ Module :py:mod: ` stackless `
297+ --------------------------
267298
268299.. c :function :: PyObject *PyStackless_Schedule (PyObject *retval, int remove)
269300
@@ -354,7 +385,8 @@ Soft-switchable extension functions
354385
355386A soft switchable extension function or method is a function or method defined
356387by an extension module written in C. In contrast to an normal C-function you
357- can soft-switch tasklets while this function executes. At the C-language level
388+ can soft-switch tasklets while this function executes. Soft-switchable functions
389+ obey the stackless-protocol. At the C-language level
358390such a function or method is made from 3 C-definitions:
359391
3603921. A declaration object of type :c:type:`PyStacklessFunctionDeclaration_Type`.
@@ -378,10 +410,10 @@ Typedef ``slp_softswitchablefunc``::
378410
379411.. c :type :: PyStacklessFunctionDeclarationObject
380412
381- This subtype of :c:type: `PyObject ` represents a Stackless soft switchable
382- extension function declaration object.
413+ This subtype of :c:type: `PyObject ` represents a Stackless soft switchable
414+ extension function declaration object.
383415
384- Here is the structure definition::
416+ Here is the structure definition::
385417
386418 typedef struct {
387419 PyObject_HEAD
@@ -390,42 +422,145 @@ Typedef ``slp_softswitchablefunc``::
390422 const char * module_name;
391423 } PyStacklessFunctionDeclarationObject;
392424
393- .. c :member :: slp_softswitchablefunc PyStacklessFunctionDeclarationObject.sfunc
425+ .. c :member :: slp_softswitchablefunc PyStacklessFunctionDeclarationObject.sfunc
394426
395- Pointer to implementation function.
427+ Pointer to implementation function.
396428
397- .. c :member :: const char * PyStacklessFunctionDeclarationObject.name
429+ .. c :member :: const char * PyStacklessFunctionDeclarationObject.name
398430
399- Name of the function.
431+ Name of the function.
400432
401- .. c :member :: const char * PyStacklessFunctionDeclarationObject.module_name
433+ .. c :member :: const char * PyStacklessFunctionDeclarationObject.module_name
402434
403- Name of the containing module.
435+ Name of the containing module.
404436
405437.. c :var :: PyTypeObject PyStacklessFunctionDeclaration_Type
406438
407- This instance of :c:type: `PyTypeObject ` represents the Stackless
408- soft switchable extension function declaration type.
439+ This instance of :c:type: `PyTypeObject ` represents the Stackless
440+ soft switchable extension function declaration type.
409441
410442.. c :function :: int PyStacklessFunctionDeclarationType_CheckExact (PyObject *p)
411443
412- Return true if *p * is a PyStacklessFunctionDeclarationObject object, but
413- not an instance of a subtype of this type.
444+ Return true if *p * is a PyStacklessFunctionDeclarationObject object, but
445+ not an instance of a subtype of this type.
414446
415447.. c :function :: PyObject* PyStackless_CallFunction (PyStacklessFunctionDeclarationObject *sfd, PyObject *arg, PyObject *ob1, PyObject *ob2, PyObject *ob3, long n, void *any)
416448
417- Invoke the soft switchable extension, which is represented by *sfd *.
418- Pass *arg * as initial value for argument *retval * and *ob1 *, *ob2 *, *ob3 *,
419- *n * and *any * as general purpose in-out-arguments.
449+ Invoke the soft switchable extension, which is represented by *sfd *.
450+ Pass *arg * as initial value for argument *retval * and *ob1 *, *ob2 *, *ob3 *,
451+ *n * and *any * as general purpose in-out-arguments.
420452
421- Return the result of the function call or :c:data: `Py_UnwindToken `.
453+ Return the result of the function call or :c:data: `Py_UnwindToken `.
422454
423455.. c :function :: int PyStackless_InitFunctionDeclaration (PyStacklessFunctionDeclarationObject *sfd, PyObject *module, PyModuleDef *module_def)
424456
425- Initialize the fields :c:member: `PyStacklessFunctionDeclarationObject.name ` and
426- :c:member: `PyStacklessFunctionDeclarationObject.module_name ` of *sfd *.
457+ Initialize the fields :c:member: `PyStacklessFunctionDeclarationObject.name ` and
458+ :c:member: `PyStacklessFunctionDeclarationObject.module_name ` of *sfd *.
459+
460+ Within the body of a soft switchable extension function (or any other C-function, that obyes the stackless-protocol)
461+ you need the following macros.
462+
463+ Macros for the "stackless-protocol"
464+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
465+
466+ How to does Stackless Python decide, if a function may return an unwind-token?
467+ There is one global variable "_PyStackless_TRY_STACKLESS"[#]_ which is used
468+ like an implicit parameter. Since we don't have a real parameter,
469+ the flag is copied into the local variable "stackless" and cleared.
470+ This is done by the STACKLESS_GETARG() macro, which should be added to
471+ the top of the function's declarations.
472+
473+ The idea is to keep the chances to introduce error to the minimum.
474+ A function can safely do some tests and return before calling
475+ anything, since the flag is in a local variable.
476+ Depending on context, this flag is propagated to other called
477+ functions. They *must * obey the protocol. To make this sure,
478+ the STACKLESS_ASSERT() macro has to be called after every such call.
479+
480+ Many internal functions have been patched to support this protocol.
481+ Their first action is a direct or indirect call of the macro
482+ :c:func: `STACKLESS_GETARG `.
483+
484+ .. c :function :: STACKLESS_GETARG()
485+
486+ Define the local variable ``int stackless `` and move the global
487+ "_PyStackless_TRY_STACKLESS" flag into the local variable "stackless".
488+ After a call to :c:func: `STACKLESS_GETARG ` the value of
489+ "_PyStackless_TRY_STACKLESS" is 0.
490+
491+ .. c :function :: STACKLESS_PROMOTE_ALL()
492+
493+ All STACKLESS_PROMOTE_xxx macros are used to propagate the stackless-flag
494+ from the local variable "stackless" to the global variable
495+ "_PyStackless_TRY_STACKLESS". The macro :c:func: `STACKLESS_PROMOTE_ALL ` does
496+ this unconditionally. It is used for cases where we know that the called
497+ function will take care of our object, and we need no test. For example,
498+ :c:func: `PyObject_Call ` and all other Py{Object,Function,CFunction}_*Call*
499+ functions use STACKLESS_PROMOTE_xxx itself, so we don't need to check further.
500+
501+ .. c :function :: STACKLESS_PROMOTE_FLAG(flag)
502+
503+ This macro is the most general conditional variant.
504+ If the local variable "stackless" was set, it sets the global
505+ variable "_PyStackless_TRY_STACKLESS" to *flag * and returns *flag *.
506+ Otherwise the macro returns 0. It is used for special cases,
507+ like PyCFunction objects. PyCFunction_Type
508+ says that it supports a stackless call, but the final action depends
509+ on the METH_STACKLESS flag in the object to be called. Therefore,
510+ PyCFunction_Call uses ``STACKLESS_PROMOTE_FLAG(flags & METH_STACKLESS) `` to
511+ take care of PyCFunctions which don't care about it.
427512
428- debugging and monitoring functions
513+ Another example is the "next" method of iterators. To support this,
514+ the wrapperobject's type has the Py_TPFLAGS_HAVE_STACKLESS_CALL
515+ flag set, but wrapper_call then examines the wrapper descriptors
516+ flags if PyWrapperFlag_STACKLESS is set. "next" has it set.
517+ It also checks whether Py_TPFLAGS_HAVE_STACKLESS_CALL is set
518+ for the iterator's type.
519+
520+ .. c :function :: STACKLESS_PROMOTE_METHOD(obj, slot_name)
521+
522+ If the local variable "stackless" was set and if the type method for the
523+ slot *slot_name * of the type of object *obj * obeys the stackless-protocol,
524+ then _PyStackless_TRY_STACKLESS is set to 1, and we
525+ expect that the function handles it correctly.
526+
527+ .. c :function :: STACKLESS_PROMOTE(obj)
528+
529+ A special optimized variant of ``STACKLESS_PROMOTE_METHOD( `` *obj * ``, tp_call) ``.
530+
531+ .. c :function :: STACKLESS_ASSERT()
532+
533+ In debug builds this macro asserts that _PyStackless_TRY_STACKLESS was cleared.
534+ This debug feature tries to ensure that no unexpected nonrecursive call can happen.
535+ In release builds this macro does nothing.
536+
537+ .. c :function :: STACKLESS_RETRACT()
538+
539+ Set the global variable "_PyStackless_TRY_STACKLESS" unconditionally to 0.
540+ Rarely used.
541+
542+ Examples
543+ ~~~~~~~~
544+
545+ The Stackless test-module :py:mod: `_teststackless ` contains the following
546+ example for a soft switchable function.
547+ To call it use
548+ ``PyStackless_CallFunction(&demo_soft_switchable_declaration, result, NULL, NULL, NULL, action, NULL) ``.
549+
550+ .. include :: ../../Stackless/module/_teststackless.c
551+ :code: c
552+ :encoding: utf-8
553+ :start-after: /*DO-NOT-REMOVE-OR-MODIFY-THIS-MARKER:ssf-example-start */
554+ :end-before: /*DO-NOT-REMOVE-OR-MODIFY-THIS-MARKER:ssf-example-end */
555+
556+ Another, more realistic example is :py:const: `_asyncio._task_step_impl_stackless `, defined in
557+ "Modules/_asynciomodules.c".
558+
559+
560+ .. [# ] Actually "_PyStackless_TRY_STACKLESS" is a macro that expands to a C L-value. As long as
561+ |CPY | uses the GIL, this L-value is a global variable.
562+
563+ Debugging and monitoring Functions
429564----------------------------------
430565
431566.. c :function :: int PyStackless_SetChannelCallback (PyObject *callable)
@@ -460,6 +595,12 @@ Stack unwinding
460595
461596 A singleton that indicates C-stack unwinding
462597
598+ .. note::
599+
600+ :c:data:`Py_UnwindToken` is *never* inc/decref'ed. Use the
601+ macro :c:func:`STACKLESS_UNWINDING` to test for
602+ Py_UnwindToken.
603+
463604.. c:function:: int STACKLESS_UNWINDING(obj)
464605
465606 Return 1, if *obj* is :c:data:`Py_UnwindToken` and 0 otherwise.
0 commit comments