#ifndef _IPXE_PROCESS_H #define _IPXE_PROCESS_H /** @file * * Processes * */ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include /** A process */ struct process { /** List of processes */ struct list_head list; /** Process descriptor */ struct process_descriptor *desc; /** Reference counter * * If this process is not part of a reference-counted object, * this field may be NULL. */ struct refcnt *refcnt; }; /** A process descriptor */ struct process_descriptor { /** Process name */ const char *name; /** Offset of process within containing object */ size_t offset; /** * Single-step the process * * This method should execute a single step of the process. * Returning from this method is isomorphic to yielding the * CPU to another process. */ void ( * step ) ( void *object ); /** Automatically reschedule the process */ int reschedule; }; /** * Define a process step() method * * @v object_type Implementing method's expected object type * @v step Implementing method * @ret step Process step method */ #define PROC_STEP( object_type, step ) \ ( ( ( ( typeof ( step ) * ) NULL ) == \ ( ( void ( * ) ( object_type *object ) ) NULL ) ) ? \ ( void ( * ) ( void *object ) ) step : \ ( void ( * ) ( void *object ) ) step ) /** * Calculate offset of process within containing object * * @v object_type Containing object data type * @v name Process name (i.e. field within object data type) * @ret offset Offset of process within containing object */ #define process_offset( object_type, name ) \ ( ( ( ( typeof ( ( ( object_type * ) NULL )->name ) * ) NULL ) \ == ( ( struct process * ) NULL ) ) \ ? offsetof ( object_type, name ) \ : offsetof ( object_type, name ) ) /** * Define a process descriptor * * @v object_type Containing object data type * @v process Process name (i.e. field within object data type) * @v step Process' step() method * @ret desc Object interface descriptor */ #define PROC_DESC( object_type, process, _step ) { \ .name = #_step, \ .offset = process_offset ( object_type, process ), \ .step = PROC_STEP ( object_type, _step ), \ .reschedule = 1, \ } /** * Define a process descriptor for a process that runs only once * * @v object_type Containing object data type * @v process Process name (i.e. field within object data type) * @v step Process' step() method * @ret desc Object interface descriptor */ #define PROC_DESC_ONCE( object_type, process, _step ) { \ .name = #_step, \ .offset = process_offset ( object_type, process ), \ .step = PROC_STEP ( object_type, _step ), \ .reschedule = 0, \ } /** * Define a process descriptor for a pure process * * A pure process is a process that does not have a containing object. * * @v step Process' step() method * @ret desc Object interface descriptor */ #define PROC_DESC_PURE( _step ) { \ .name = #_step, \ .offset = 0, \ .step = PROC_STEP ( struct process, _step ), \ .reschedule = 1, \ } extern void * __attribute__ (( pure )) process_object ( struct process *process ); extern void process_add ( struct process *process ); extern void process_del ( struct process *process ); extern void step ( void ); /** * Initialise a static process * * @v process Process * @v desc Process descriptor */ #define PROC_INIT( _process, _desc ) { \ .list = LIST_HEAD_INIT ( (_process).list ), \ .desc = (_desc), \ .refcnt = NULL, \ } /** * Initialise process without adding to process list * * @v process Process * @v desc Process descriptor * @v refcnt Containing object reference count, or NULL */ static inline __attribute__ (( always_inline )) void process_init_stopped ( struct process *process, struct process_descriptor *desc, struct refcnt *refcnt ) { INIT_LIST_HEAD ( &process->list ); process->desc = desc; process->refcnt = refcnt; } /** * Initialise process and add to process list * * @v process Process * @v desc Process descriptor * @v refcnt Containing object reference count, or NULL */ static inline __attribute__ (( always_inline )) void process_init ( struct process *process, struct process_descriptor *desc, struct refcnt *refcnt ) { process_init_stopped ( process, desc, refcnt ); process_add ( process ); } /** * Check if process is running * * @v process Process * @ret running Process is running */ static inline __attribute__ (( always_inline )) int process_running ( struct process *process ) { return ( ! list_empty ( &process->list ) ); } /** Permanent process table */ #define PERMANENT_PROCESSES __table ( struct process, "processes" ) /** * Declare a permanent process * * Permanent processes will be automatically added to the process list * at initialisation time. */ #define __permanent_process __table_entry ( PERMANENT_PROCESSES, 01 ) /** Define a permanent process * */ #define PERMANENT_PROCESS( name, step ) \ static struct process_descriptor name ## _desc = PROC_DESC_PURE ( step ); \ struct process name __permanent_process = PROC_INIT ( name, & name ## _desc ); /** * Find debugging colourisation for a process * * @v process Process * @ret col Debugging colourisation * * Use as the first argument to DBGC() or equivalent macro. */ #define PROC_COL( process ) process_object ( process ) /** printf() format string for PROC_DBG() */ #define PROC_FMT "%p %s()" /** * printf() arguments for representing a process * * @v process Process * @ret args printf() argument list corresponding to PROC_FMT */ #define PROC_DBG( process ) process_object ( process ), (process)->desc->name #endif /* _IPXE_PROCESS_H */