Stackless-Python C-API

Stackless-Python provides the following C functions.

Tasklets

PyTaskletObject *PyTasklet_New(PyTypeObject *type,PyObject *func)

Return a new tasklet object.type must be derived fromPyTasklet_TypeorNULL.func must be a callable object orNULL orPy_None. IffuncisNULL orPy_None you must set it later withPyTasklet_BindEx().

intPyTasklet_Setup(PyTaskletObject *task,PyObject *args,PyObject *kwds)

Binds a tasklet function to parameters, making it ready to run and inserts ininto the runnables queue. Returns0 if successful or-1 in the case of failure.

intPyTasklet_BindEx(PyTaskletObject *task,PyObject *func,PyObject *args,PyObject *kwargs)

Binds a tasklet to a function and/or to parameters, making it ready to run. This is the C equivalent tomethodtasklet.bind(). The argumentsfunc,args andkwargs are optional andmay beNULL orPy_None. Returns0 if successful or-1 in the case of failure.

intPyTasklet_BindThread(PyTaskletObject *task, long thread_id)

Binds a tasklet function to a thread. This is the C equivalent tomethodtasklet.bind_thread(). Returns0 if successful or-1 in the case of failure.

intPyTasklet_Run(PyTaskletObject *task)

Forcestask to run immediately. Returns0 if successful, and-1 in thecase of failure.

intPyTasklet_Run_nr(PyTaskletObject *task)

Forcestask to run immediately, soft switching if possible. Returns1 ifthe call soft switched,0 if the call hard switched and -1 in the case offailure.

intPyTasklet_Switch(PyTaskletObject *task)

Forcestask to run immediately. The previous tasklet is paused.Returns0 if successful, and-1 in thecase of failure.

intPyTasklet_Switch_nr(PyTaskletObject *task)

Forcestask to run immediately, soft switching if possible.The previous tasklet is paused. Returns1 ifthe call soft switched,0 if the call hard switched and -1 in the case offailure.

intPyTasklet_Remove(PyTaskletObject *task)

Removestask from the runnables queue. Be careful! If this tasklet has a Cstack attached, you need to either resume running it or kill it. Just droppingit might give an inconsistent system state. Returns0 if successful, and-1 in the case of failure.

intPyTasklet_Insert(PyTaskletObject *task)

Inserttask into the runnables queue, if it isn’t already there. If it isblocked or dead, the function returns-1 and aRuntimeError is raised.

intPyTasklet_RaiseException(PyTaskletObject *self,PyObject *klass,PyObject *args)

Raises an instance of theklass exception on theself tasklet.klass mustbe a subclass ofException. Returns1 if the call soft switched,0if the call hard switched and-1 in the case of failure.

Note

RaisingTaskletExit on a tasklet can be done to silently killit, seePyTasklet_Kill().

intPyTasklet_Throw(PyTaskletObject *self, int pending,PyObject *exc,PyObject *val,PyObject *tb)

Raises (exc,val,tb) on theself tasklet. This is the C equivalent tomethodtasklet.throw(). Returns1 if the call soft switched,0if the call hard switched and-1 in the case of failure.

intPyTasklet_Kill(PyTaskletObject *self)

RaisesTaskletExit on taskletself. This should result intask beingsilently killed. (This exception is ignored by tasklet_end anddoes not invoke main as exception handler.)Returns1 if the call soft switched,0 if the call hardswitched and-1 in the case of failure.

intPyTasklet_KillEx(PyTaskletObject *self, int pending)

RaisesTaskletExit on taskletself. This is the C equivalent tomethodtasklet.kill().Returns1 if the call soft switched,0 if the call hardswitched and-1 in the case of failure.

intPyTasklet_GetAtomic(PyTaskletObject *task)

Returns1 iftask is atomic, otherwise0.

intPyTasklet_SetAtomic(PyTaskletObject *task, int flag)

Returns1 iftask is currently atomic, otherwise0. Sets theatomic attribute to the logical value offlag.

intPyTasklet_GetIgnoreNesting(PyTaskletObject *task)

Returns1 iftask ignores its nesting level when choosing whether toauto-schedule it, otherwise0.

intPyTasklet_SetIgnoreNesting(PyTaskletObject *task, int flag)

Returns the existing value of theignore_nesting attribute for the tasklettask, setting it to the logical value offlag. If true, the tasklet maybe auto-scheduled even if itsnesting_level is >0.

intPyTasklet_GetBlockTrap(PyTaskletObject *task)

Returns1 iftask is designated as not being allowed to be blocked on achannel, otherwise0.

voidPyTasklet_SetBlockTrap(PyTaskletObject *task, int value)

Returns1 iftask was already designated as not being allowed to be blockedon a channel, otherwise0. This attribute is set to the logical value ofvalue.

PyObject *PyTasklet_GetFrame(PyTaskletObject *task)

Returns the current frame thattask is executing in, orNULL

intPyTasklet_IsMain(PyTaskletObject *task)

Returns1 iftask is the main tasklet, otherwise0.

intPyTasklet_IsCurrent(PyTaskletObject *task)

Returns1 iftask is the current tasklet, otherwise0.

intPyTasklet_GetRecursionDepth(PyTaskletObject *task)

Return the current recursion depth oftask.

intPyTasklet_GetNestingLevel(PyTaskletObject *task)

Return the current nesting level oftask.

intPyTasklet_Alive(PyTaskletObject *task)

Returns1 iftask is alive (has an associated frame), otherwise0 if it is dead.

intPyTasklet_Paused(PyTaskletObject *task)

Returns1 iftask is paused, otherwise0. A tasklet is paused if it isalive, but not scheduled or blocked on a channel.

intPyTasklet_Scheduled(PyTaskletObject *task)

Returns1 iftask is scheduled, otherwise0. In the context of thisfunction a tasklet is considered to be scheduled if it is alive, and in thescheduler runnables list or blocked on a channel.

intPyTasklet_Restorable(PyTaskletObject *task)

Returns1 iftask can be fully unpickled, otherwise0. A tasklet canbe pickled whether it is fully restorable or not for the purposes of debuggingand introspection. A tasklet that has been hard-switched cannot be fullypickled, for instance.

Channels

PyChannelObject*PyChannel_New(PyTypeObject *type)

Return a new channel object, orNULL in the case of failure.type must bederived fromPyChannel_Type or beNULL, otherwise aTypeErroris raised.

intPyChannel_Send(PyChannelObject *self,PyObject *arg)

Sendarg on the channelself. Returns0 if the operation wassuccessful, or-1 in the case of failure.

intPyChannel_Send_nr(PyChannelObject *self,PyObject *arg)

Sendarg on the channelself, soft switching if possible. Returns1 ifthe call soft switched,0 if the call hard switched and -1 in the case offailure.

PyObject *PyChannel_Receive(PyChannelObject *self)

Receive on the channelself. Returns aPython® object if the operation wassuccessful, orNULL in the case of failure.

PyObject *PyChannel_Receive_nr(PyChannelObject *self)

Receive on the channelself, soft switching if possible. Returns aPython®object if the operation was successful,Py_UnwindToken if a soft switchoccurred, orNULL in the case of failure.

intPyChannel_SendException(PyChannelObject *self,PyObject *klass,PyObject *value)

Returns0 if successful or-1 in the case of failure. An instance of theexception typeklass is raised on the first tasklet blocked on channelself.

intPyChannel_SendThrow(PyChannelObject *self,PyObject *exc,PyObject *val,PyObject *tb)

Returns0 if successful or-1 in the case of failure.(exc,val,tb) is raised on the first tasklet blocked on channelself.

PyObject *PyChannel_GetQueue(PyChannelObject *self)

Returns the first tasklet in the channelself’s queue, orNULL in the casethe queue is empty.

voidPyChannel_Close(PyChannelObject *self)

Marks the channelself as closing. No further tasklets can be blocked on theit from this point, unless it is later reopened.

voidPyChannel_Open(PyChannelObject *self)

Reopens the channelself. This allows tasklets to once again send and receiveon it, if those operations would otherwise block the given tasklet.

intPyChannel_GetClosing(PyChannelObject *self)

Returns1 if the channelself is marked as closing, otherwise0.

intPyChannel_GetClosed(PyChannelObject *self)

Returns1 if the channelself is marked as closing and there are no taskletsblocked on it, otherwise0.

intPyChannel_GetPreference(PyChannelObject *self)

Returns the current scheduling preference value ofself. Seechannel.preference.

voidPyChannel_SetPreference(PyChannelObject *self, int val)

Sets the current scheduling preference value ofself. Seechannel.preference.

intPyChannel_GetScheduleAll(PyChannelObject *self)

Gets theschedule_all override flag forself. Seechannel.schedule_all.

voidPyChannel_SetScheduleAll(PyChannelObject *self, int val)

Sets theschedule_all override flag forself. Seechannel.schedule_all.

intPyChannel_GetBalance(PyChannelObject *self)

Gets the balance forself. Seechannel.balance.

stackless module

PyObject *PyStackless_Schedule(PyObject *retval, int remove)

Suspend the current tasklet and schedule the next one in the cyclic chain.if remove is nonzero, the current tasklet will be removed from the chain.retval = success NULL = failure

PyObject *PyStackless_Schedule_nr(PyObject *retval, int remove)

retval = success NULL = failureretval == Py_UnwindToken: soft switched

intPyStackless_GetRunCount()

get the number of runnable tasks of the current thread, including the current one.-1 = failure

PyObject *PyStackless_GetCurrent()

Get the currently running tasklet, that is, “yourself”.

longPyStackless_GetCurrentId()

Get a unique integer ID for the current tasklet

Threadsafe.

This is useful for benchmarking code thatneeds to get some sort of a stack identifier and mustnot worry about the GIL being present and so on.

Note

  1. the “main” tasklet on each thread will have the same id,even if a proper tasklet has not been initialized.
  2. IDs may get recycled for new tasklets.
PyObject *PyStackless_RunWatchdog(long timeout)

Runs the scheduler until there are no tasklets remaining within it, or untilone of the scheduled tasklets runs fortimeout VM instructions withoutblocking. ReturnsNone if the scheduler is empty, a tasklet object if thattasklet timed out, orNULL in the case of failure. If a timed out taskletis returned, it should be killed or reinserted.

This function can only be called from the main tasklet.During the run, main is suspended, but will be invokedafter the action. You will write your exception handlerhere, since every uncaught exception will be directedto main.

PyObject *PyStackless_RunWatchdogEx(long timeout, int flags)

WrapsPyStackless_RunWatchdog(), but allows its behaviour to becustomised by the value offlags which may contain any of the followingbits:

Py_WATCHDOG_THREADBLOCK
Allows a thread to block if it runs out of tasklets. Ideallyit will be awakened by other threads using channels which itsblocked tasklets are waiting on.
Py_WATCHDOG_SOFT
Instead of interrupting a tasklet, we wait until thenext tasklet scheduling moment to return. Always returnsPy_None, as everything is in order.
Py_WATCHDOG_IGNORE_NESTING
Allows interrupts at all levels, effectively acting asthough theignore_nesting attribute were set on alltasklets.
Py_WATCHDOG_TIMEOUT
Interpretstimeout as a fixed run time, rather than aper-tasklet run limit. The function will then attempt tointerrupt execution once this many total opcodes havebeen executed since the call was made.

debugging and monitoring functions

intPyStackless_SetChannelCallback(PyObject *callable)

channel debugging. The callable will be called on every send or receive.Passing NULL removes the handler.Parameters of the callable:channel, tasklet, int sendflag, int willblock-1 = failure

intPyStackless_SetScheduleCallback(PyObject *callable)

scheduler monitoring.The callable will be called on every scheduling.Passing NULL removes the handler.Parameters of the callable: from, toWhen a tasklet dies, to is None.After death or when main starts up, from is None.-1 = failure

voidPyStackless_SetScheduleFastcallback(slp_schedule_hook_func func)

Scheduler monitoring with a faster interface.

Interface functions

Most of the above functions can be called both from “inside”and “outside” stackless. “inside” means there should be a running(c)frame on top which acts as the “main tasklet”. The functionsdo a check whether the main tasklet exists, and wrap themselvesif it is necessary.The following routines are used to support this, and you may usethem as well if you need to make your specific functions alwaysavailable.

PyObject *PyStackless_Call_Main(PyObject *func,PyObject *args,PyObject *kwds)

Run any callable as the “main”Python® function. Returns aPython® object, orNULL in the case of failure.

PyObject *PyStackless_CallMethod_Main(PyObject *o, char *name, char *format, ...)

Convenience: Run any method as the “main”Python® function. Wraps PyStackless_Call_Main.