summaryrefslogtreecommitdiffstats
path: root/qemu/roms/ipxe/src/include/ipxe/process.h
blob: d600508e7ee31d07b453c740d98ea31645af8230 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#ifndef _IPXE_PROCESS_H
#define _IPXE_PROCESS_H

/** @file
 *
 * Processes
 *
 */

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );

#include <ipxe/list.h>
#include <ipxe/refcnt.h>
#include <ipxe/tables.h>

/** 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 {
	/** 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 ) {			      \
		.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 ) {			      \
		.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 ) {					      \
		.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 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 = {				      \
	.list = LIST_HEAD_INIT ( name.list ),				      \
	.desc = & name ## _desc,					      \
	.refcnt = NULL,							      \
};

/**
 * 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+%zx"

/**
 * 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->offset

#endif /* _IPXE_PROCESS_H */