1 #ifndef _IPXE_PROCESS_H
2 #define _IPXE_PROCESS_H
3 
4 /** @file
5  *
6  * Processes
7  *
8  */
9 
10 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
11 
12 #include <ipxe/list.h>
13 #include <ipxe/refcnt.h>
14 #include <ipxe/tables.h>
15 
16 /** A process */
17 struct process {
18 	/** List of processes */
19 	struct list_head list;
20 	/** Process descriptor */
21 	struct process_descriptor *desc;
22 	/** Reference counter
23 	 *
24 	 * If this process is not part of a reference-counted object,
25 	 * this field may be NULL.
26 	 */
27 	struct refcnt *refcnt;
28 };
29 
30 /** A process descriptor */
31 struct process_descriptor {
32 	/** Process name */
33 	const char *name;
34 	/** Offset of process within containing object */
35 	size_t offset;
36 	/**
37 	 * Single-step the process
38 	 *
39 	 * This method should execute a single step of the process.
40 	 * Returning from this method is isomorphic to yielding the
41 	 * CPU to another process.
42 	 */
43 	void ( * step ) ( void *object );
44 	/** Automatically reschedule the process */
45 	int reschedule;
46 };
47 
48 /**
49  * Define a process step() method
50  *
51  * @v object_type	Implementing method's expected object type
52  * @v step		Implementing method
53  * @ret step		Process step method
54  */
55 #define PROC_STEP( object_type, step )					      \
56 	( ( ( ( typeof ( step ) * ) NULL ) ==				      \
57 	    ( ( void ( * ) ( object_type *object ) ) NULL ) ) ?		      \
58 	  ( void ( * ) ( void *object ) ) step :			      \
59 	  ( void ( * ) ( void *object ) ) step )
60 
61 /**
62  * Calculate offset of process within containing object
63  *
64  * @v object_type	Containing object data type
65  * @v name		Process name (i.e. field within object data type)
66  * @ret offset		Offset of process within containing object
67  */
68 #define process_offset( object_type, name )				      \
69 	( ( ( ( typeof ( ( ( object_type * ) NULL )->name ) * ) NULL )	      \
70 	    == ( ( struct process * ) NULL ) )			      	      \
71 	  ? offsetof ( object_type, name )				      \
72 	  : offsetof ( object_type, name ) )
73 
74 /**
75  * Define a process descriptor
76  *
77  * @v object_type	Containing object data type
78  * @v process		Process name (i.e. field within object data type)
79  * @v step		Process' step() method
80  * @ret desc		Object interface descriptor
81  */
82 #define PROC_DESC( object_type, process, _step ) {			      \
83 		.name = #_step,						      \
84 		.offset = process_offset ( object_type, process ),	      \
85 		.step = PROC_STEP ( object_type, _step ),		      \
86 		.reschedule = 1,					      \
87 	}
88 
89 /**
90  * Define a process descriptor for a process that runs only once
91  *
92  * @v object_type	Containing object data type
93  * @v process		Process name (i.e. field within object data type)
94  * @v step		Process' step() method
95  * @ret desc		Object interface descriptor
96  */
97 #define PROC_DESC_ONCE( object_type, process, _step ) {			      \
98 		.name = #_step,						      \
99 		.offset = process_offset ( object_type, process ),	      \
100 		.step = PROC_STEP ( object_type, _step ),		      \
101 		.reschedule = 0,					      \
102 	}
103 
104 /**
105  * Define a process descriptor for a pure process
106  *
107  * A pure process is a process that does not have a containing object.
108  *
109  * @v step		Process' step() method
110  * @ret desc		Object interface descriptor
111  */
112 #define PROC_DESC_PURE( _step ) {					      \
113 		.name = #_step,						      \
114 		.offset = 0,						      \
115 		.step = PROC_STEP ( struct process, _step ),		      \
116 		.reschedule = 1,					      \
117 	}
118 
119 extern void * __attribute__ (( pure ))
120 process_object ( struct process *process );
121 extern void process_add ( struct process *process );
122 extern void process_del ( struct process *process );
123 extern void step ( void );
124 
125 /**
126  * Initialise a static process
127  *
128  * @v process		Process
129  * @v desc		Process descriptor
130  */
131 #define PROC_INIT( _process, _desc ) {					      \
132 		.list = LIST_HEAD_INIT ( (_process).list ),		      \
133 		.desc = (_desc),					      \
134 		.refcnt = NULL,						      \
135 	}
136 
137 /**
138  * Initialise process without adding to process list
139  *
140  * @v process		Process
141  * @v desc		Process descriptor
142  * @v refcnt		Containing object reference count, or NULL
143  */
144 static inline __attribute__ (( always_inline )) void
process_init_stopped(struct process * process,struct process_descriptor * desc,struct refcnt * refcnt)145 process_init_stopped ( struct process *process,
146 		       struct process_descriptor *desc,
147 		       struct refcnt *refcnt ) {
148 	INIT_LIST_HEAD ( &process->list );
149 	process->desc = desc;
150 	process->refcnt = refcnt;
151 }
152 
153 /**
154  * Initialise process and add to process list
155  *
156  * @v process		Process
157  * @v desc		Process descriptor
158  * @v refcnt		Containing object reference count, or NULL
159  */
160 static inline __attribute__ (( always_inline )) void
process_init(struct process * process,struct process_descriptor * desc,struct refcnt * refcnt)161 process_init ( struct process *process,
162 	       struct process_descriptor *desc,
163 	       struct refcnt *refcnt ) {
164 	process_init_stopped ( process, desc, refcnt );
165 	process_add ( process );
166 }
167 
168 /**
169  * Check if process is running
170  *
171  * @v process		Process
172  * @ret running		Process is running
173  */
174 static inline __attribute__ (( always_inline )) int
process_running(struct process * process)175 process_running ( struct process *process ) {
176 	return ( ! list_empty ( &process->list ) );
177 }
178 
179 /** Permanent process table */
180 #define PERMANENT_PROCESSES __table ( struct process, "processes" )
181 
182 /**
183  * Declare a permanent process
184  *
185  * Permanent processes will be automatically added to the process list
186  * at initialisation time.
187  */
188 #define __permanent_process __table_entry ( PERMANENT_PROCESSES, 01 )
189 
190 /** Define a permanent process
191  *
192  */
193 #define PERMANENT_PROCESS( name, step )					      \
194 static struct process_descriptor name ## _desc = PROC_DESC_PURE ( step );     \
195 struct process name __permanent_process = PROC_INIT ( name, & name ## _desc );
196 
197 /**
198  * Find debugging colourisation for a process
199  *
200  * @v process		Process
201  * @ret col		Debugging colourisation
202  *
203  * Use as the first argument to DBGC() or equivalent macro.
204  */
205 #define PROC_COL( process ) process_object ( process )
206 
207 /** printf() format string for PROC_DBG() */
208 #define PROC_FMT "%p %s()"
209 
210 /**
211  * printf() arguments for representing a process
212  *
213  * @v process		Process
214  * @ret args		printf() argument list corresponding to PROC_FMT
215  */
216 #define PROC_DBG( process ) process_object ( process ), (process)->desc->name
217 
218 #endif /* _IPXE_PROCESS_H */
219