[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/stackless-dev/stackman/dev/src/stackman_switch.h [Back]  [Original]

#pragma once
#ifndef STACKMAN_SWITCH_H
#define STACKMAN_SWITCH_H

/* Must include the platform here to know if the switch function
 * is implemented in assembler or nt
 */
#include "platforms/platform.h"

/* we can request that C functions be implemented with static linkage
 * when including in other libraries
 */
#if defined(STACKMAN_LINKAGE_STATIC)
#if !defined(STACKMAN_ASSEMBLY_SRC) && !STACKMAN_SWITCH_C
#define STACKMAN_LINKAGE_SWITCH static
#endif
#endif

#if !defined(STACKMAN_LINKAGE_SWITCH)
/* then it is extern */
#if defined(__cplusplus)
#define STACKMAN_LINKAGE_SWITCH extern "C"
#else
#define STACKMAN_LINKAGE_SWITCH extern
#endif
#endif

/* do we need to have indirection for stackman_switch?
 * we do, if the implementation is inline and we are not
 * building a library, because an optimizing compiler may
 * decide to inline functions that contain in-line assembler
 */
#if (!defined(STACKMAN_ASSEMBLY_SRC) && !defined(STACKMAN_BUILD_LIB))
#define STACKMAN_SWITCH_NEED_INDIRECT 1
#else
#define STACKMAN_SWITCH_NEED_INDIRECT 0
#endif

#if STACKMAN_SWITCH_NEED_INDIRECT
#define STACKMAN_SWITCH_INASM_NAME _stackman_switch_inasm
#define STACKMAN_LINKAGE_SWITCH_INASM static
#else
#define STACKMAN_SWITCH_INASM_NAME stackman_switch
#define STACKMAN_LINKAGE_SWITCH_INASM STACKMAN_LINKAGE_SWITCH
#endif


/* raw stack switching function. The caller supplies a callback
 * and context to perform determine the new stack pointer and
 * perform cleanup of old stack and initialization of the new
 * stack.
 * The platform specific implementation of the function is responsible
 * for saving and restoring any machine registers that are assumed
 * to be unchanged across function calls and to change the actual
 * stack pointer.
 *
 * The implementation must simply:
 * 1) store all platform and cpu state on the stack (callee-stored
 *    registers, exception state, etc)
 * 2) call the callback with the context, opcode STACKMAN_OP_SAVE and
 *    the current stack pointer. This allows the application to do additional
 *    cleanup and determine the new stack pointer.
 * 3) replace the stack pointer with the returned value from the callback.
 * 4) call the callback again with opcode STACKMAN_OP_RESTORE and the new
 *    stack pointer. This allows the application to initialize its state
      after the switch.
 * 5) Pop the platform state back from stack.
 * 6) return the result from the second call of the callback.
 *
 * Note that the callback and context are _not_ guaranteed
 * to be stack local.  That is, even if the stack pointer is modified
 * according to the first call to the callback, the same callback and
 * context may be used during the second callback, in the new stack.
 * Therefore, the same callback and context pointers should always be used
 * when switching between stacks.  This
 * restriction could be lifted by pushing both values onto the stack
 * before switching but the added complexity of platform implementations
 * doesn't seem to warrant that for such an exotic use case.
 *
 * an appropriate implementation is included by
 * platforms/platform.h
 * A template implementation is available in
 * platforms/switch_template.h
 */

/* Opcodes for the callback function */
typedef enum stackman_op_t {
	/* The callback receives the current stack pointer and should
	 * save any state that it wishes, for example the contents of the
	 * stack, before returning a new stack pointer.
	 */
	STACKMAN_OP_SAVE = 0,

	/* The callback receives the new stack pointer and should restore
	 * any state for it, e.g. fillint the stack with the correct data.
	 * what it returns will be the return value from stackman_switch().
	 */
	STACKMAN_OP_RESTORE = 1,

	/* The callback is being invoked from a stackman_call() invokation.
	 * Stack_pointer is the pointer that was provided to stackman_call()
	 */
	STACKMAN_OP_CALL = 2,
	
} stackman_op_t;


/* The switch callback.  It receives the context passed to
 * stackman_switch(), an opcode (above) and a stack pointer.
 * The opcode is passed as an int, to avoid portability problems
 * with the ambiguous size of an enum.
 */
typedef void *(*stackman_cb_t)(
	void *context, int opcode, void *stack_pointer);
/* The actual stack switching function.
 * It saves state, switches stack pointer, and restores state
 */
STACKMAN_LINKAGE_SWITCH
void *stackman_switch(stackman_cb_t callback, void *context);


/* A function to call a function with a different stack location.
 * Instead of a normal function call, where the return address and arguments
 * are pushed on the current stack, first the stack pointer is changed to
 * a new location. This is useful for example to move the stack into heap memory.
 * 'callback' will be invoked with the
 * stack already set to the new position as specified by 'stack'. The third
 * argument to the callback is the *previous* stack pointer.
 * The callback can then proceed to 'save' the new stack for future switching.
 * Returning from the callback will work normally.
 */
STACKMAN_LINKAGE_SWITCH
void *stackman_call(stackman_cb_t callback, void *context, void *stack);


#endif /* STACKMAN_SWITCH_H */

Web Proxy Viewer  |  New URL  |  Original Page