|
@@ -1,228 +0,0 @@
|
1
|
|
-#ifndef _GPXE_ASYNC_H
|
2
|
|
-#define _GPXE_ASYNC_H
|
3
|
|
-
|
4
|
|
-/** @file
|
5
|
|
- *
|
6
|
|
- * Asynchronous operations
|
7
|
|
- *
|
8
|
|
- */
|
9
|
|
-
|
10
|
|
-#include <gpxe/list.h>
|
11
|
|
-
|
12
|
|
-struct async;
|
13
|
|
-
|
14
|
|
-/** An asynchronous operation ID
|
15
|
|
- *
|
16
|
|
- * Only positive identifiers are valid; negative values are used to
|
17
|
|
- * indicate errors.
|
18
|
|
- */
|
19
|
|
-typedef long aid_t;
|
20
|
|
-
|
21
|
|
-/** Signals that can be delivered to asynchronous operations */
|
22
|
|
-enum signal {
|
23
|
|
- /** A child asynchronous operation has completed
|
24
|
|
- *
|
25
|
|
- * The parent should call async_wait() to reap the completed
|
26
|
|
- * child. async_wait() will return the exit status and
|
27
|
|
- * operation identifier of the child.
|
28
|
|
- *
|
29
|
|
- * The handler for this signal can be set to @c NULL; if it
|
30
|
|
- * is, then the children will accumulate as zombies until
|
31
|
|
- * async_wait() is called.
|
32
|
|
- *
|
33
|
|
- * The handler for this signal can also be set to @c SIG_IGN;
|
34
|
|
- * if it is, then the children will automatically be reaped.
|
35
|
|
- * Note that if you use @c SIG_IGN then you will not be able
|
36
|
|
- * to retrieve the return status of the children; the call to
|
37
|
|
- * async_wait() will simply return -ECHILD.
|
38
|
|
- */
|
39
|
|
- SIGCHLD = 0,
|
40
|
|
- /** Cancel asynchronous operation
|
41
|
|
- *
|
42
|
|
- * This signal should trigger the asynchronous operation to
|
43
|
|
- * cancel itself (including killing all its own children, if
|
44
|
|
- * any), and then call async_done(). The asynchronous
|
45
|
|
- * operation is allowed to not complete immediately.
|
46
|
|
- *
|
47
|
|
- * The handler for this signal can be set to @c NULL; if it
|
48
|
|
- * is, then attempts to cancel the asynchronous operation will
|
49
|
|
- * fail and the operation will complete normally. Anything
|
50
|
|
- * waiting for the operation to cancel will block.
|
51
|
|
- */
|
52
|
|
- SIGKILL,
|
53
|
|
- /** Update progress of asynchronous operation
|
54
|
|
- *
|
55
|
|
- * This signal should cause the asynchronous operation to
|
56
|
|
- * immediately update the @c completed and @c total fields.
|
57
|
|
- *
|
58
|
|
- * The handler for this signal can be set to @c NULL; if it
|
59
|
|
- * is, then the asynchronous operation is expected to keep its
|
60
|
|
- * @c completed and @c total fields up to date at all times.
|
61
|
|
- */
|
62
|
|
- SIGUPDATE,
|
63
|
|
- SIGMAX
|
64
|
|
-};
|
65
|
|
-
|
66
|
|
-/**
|
67
|
|
- * A signal handler
|
68
|
|
- *
|
69
|
|
- * @v async Asynchronous operation
|
70
|
|
- * @v signal Signal received
|
71
|
|
- */
|
72
|
|
-typedef void ( * signal_handler_t ) ( struct async *async,
|
73
|
|
- enum signal signal );
|
74
|
|
-
|
75
|
|
-/** Asynchronous operation operations */
|
76
|
|
-struct async_operations {
|
77
|
|
- /** Reap asynchronous operation
|
78
|
|
- *
|
79
|
|
- * @v async Asynchronous operation
|
80
|
|
- *
|
81
|
|
- * Release all resources associated with the asynchronous
|
82
|
|
- * operation. This will be called only after the asynchronous
|
83
|
|
- * operation itself calls async_done(), so the only remaining
|
84
|
|
- * resources will probably be the memory used by the struct
|
85
|
|
- * async itself.
|
86
|
|
- *
|
87
|
|
- * This method can be set to @c NULL; if it is, then no
|
88
|
|
- * resources will be freed. This may be suitable for
|
89
|
|
- * asynchronous operations that consume no dynamically
|
90
|
|
- * allocated memory.
|
91
|
|
- */
|
92
|
|
- void ( * reap ) ( struct async *async );
|
93
|
|
- /** Handle signals */
|
94
|
|
- signal_handler_t signal[SIGMAX];
|
95
|
|
-};
|
96
|
|
-
|
97
|
|
-/** An asynchronous operation */
|
98
|
|
-struct async {
|
99
|
|
- /** Other asynchronous operations with the same parent */
|
100
|
|
- struct list_head siblings;
|
101
|
|
- /** Child asynchronous operations */
|
102
|
|
- struct list_head children;
|
103
|
|
- /** Parent asynchronous operation
|
104
|
|
- *
|
105
|
|
- * This field is optional; if left to NULL then the owner must
|
106
|
|
- * never call async_done().
|
107
|
|
- */
|
108
|
|
- struct async *parent;
|
109
|
|
- /** Asynchronous operation ID */
|
110
|
|
- aid_t aid;
|
111
|
|
- /** Final return status code */
|
112
|
|
- int rc;
|
113
|
|
-
|
114
|
|
- /** Amount of operation completed so far
|
115
|
|
- *
|
116
|
|
- * The units for this quantity are arbitrary. @c completed
|
117
|
|
- * divded by @total should give something which approximately
|
118
|
|
- * represents the progress through the operation. For a
|
119
|
|
- * download operation, using byte counts would make sense.
|
120
|
|
- *
|
121
|
|
- * This progress indicator should also incorporate the status
|
122
|
|
- * of any child asynchronous operations.
|
123
|
|
- */
|
124
|
|
- unsigned long completed;
|
125
|
|
- /** Total operation size
|
126
|
|
- *
|
127
|
|
- * See @c completed. A zero value means "total size unknown"
|
128
|
|
- * and is explcitly permitted; users should take this into
|
129
|
|
- * account before calculating @c completed/total.
|
130
|
|
- */
|
131
|
|
- unsigned long total;
|
132
|
|
-
|
133
|
|
- struct async_operations *aop;
|
134
|
|
-};
|
135
|
|
-
|
136
|
|
-extern struct async_operations default_async_operations;
|
137
|
|
-extern struct async_operations orphan_async_operations;
|
138
|
|
-
|
139
|
|
-extern aid_t async_init ( struct async *async, struct async_operations *aop,
|
140
|
|
- struct async *parent );
|
141
|
|
-extern void async_uninit ( struct async *async );
|
142
|
|
-extern void async_ignore_signal ( struct async *async, enum signal signal );
|
143
|
|
-extern void async_signal ( struct async *async, enum signal signal );
|
144
|
|
-extern void async_signal_children ( struct async *async, enum signal signal );
|
145
|
|
-extern void async_done ( struct async *async, int rc );
|
146
|
|
-extern aid_t async_wait ( struct async *async, int *rc, int block );
|
147
|
|
-
|
148
|
|
-/** Default signal handler */
|
149
|
|
-#define SIG_DFL NULL
|
150
|
|
-
|
151
|
|
-/** Ignore signal */
|
152
|
|
-#define SIG_IGN async_ignore_signal
|
153
|
|
-
|
154
|
|
-/**
|
155
|
|
- * Initialise orphan asynchronous operation
|
156
|
|
- *
|
157
|
|
- * @v async Asynchronous operation
|
158
|
|
- * @ret aid Asynchronous operation ID
|
159
|
|
- *
|
160
|
|
- * An orphan asynchronous operation can act as a context for child
|
161
|
|
- * operations. However, you must not call async_done() on such an
|
162
|
|
- * operation, since this would attempt to send a signal to its
|
163
|
|
- * (non-existent) parent. Instead, simply free the structure (after
|
164
|
|
- * calling async_wait() to ensure that any child operations have
|
165
|
|
- * completed).
|
166
|
|
- */
|
167
|
|
-static inline aid_t async_init_orphan ( struct async *async ) {
|
168
|
|
- return async_init ( async, &orphan_async_operations, NULL );
|
169
|
|
-}
|
170
|
|
-
|
171
|
|
-/**
|
172
|
|
- * Execute and block on an asynchronous operation
|
173
|
|
- *
|
174
|
|
- * @v async_temp Temporary asynchronous operation structure to use
|
175
|
|
- * @v START Code used to start the asynchronous operation
|
176
|
|
- * @ret rc Return status code
|
177
|
|
- *
|
178
|
|
- * This is a notational shorthand for writing
|
179
|
|
- *
|
180
|
|
- * async_init_orphan ( &async_temp );
|
181
|
|
- * if ( ( rc = START ) == 0 )
|
182
|
|
- * async_wait ( &async_temp );
|
183
|
|
- * if ( rc != 0 ) {
|
184
|
|
- * ...handle failure...
|
185
|
|
- * }
|
186
|
|
- *
|
187
|
|
- * and allows you instead to write
|
188
|
|
- *
|
189
|
|
- * if ( ( rc = async_block ( &async_temp, START ) ) != 0 ) {
|
190
|
|
- * ...handle failure...
|
191
|
|
- * }
|
192
|
|
- *
|
193
|
|
- * The argument START is a code snippet; it should initiate an
|
194
|
|
- * asynchronous operation as a child of @c async_temp and return an
|
195
|
|
- * error status code if it failed to do so (e.g. due to malloc()
|
196
|
|
- * failure).
|
197
|
|
- */
|
198
|
|
-#define async_block( async_temp, START ) ( { \
|
199
|
|
- int rc; \
|
200
|
|
- \
|
201
|
|
- async_init_orphan ( async_temp ); \
|
202
|
|
- if ( ( rc = START ) == 0 ) \
|
203
|
|
- async_wait ( async_temp, &rc, 1 ); \
|
204
|
|
- rc; \
|
205
|
|
- } )
|
206
|
|
-
|
207
|
|
-/**
|
208
|
|
- * Execute and block on an asynchronous operation, with progress indicator
|
209
|
|
- *
|
210
|
|
- * @v async_temp Temporary asynchronous operation structure to use
|
211
|
|
- * @v START Code used to start the asynchronous operation
|
212
|
|
- * @ret rc Return status code
|
213
|
|
- *
|
214
|
|
- * As for async_block(), the argument START is a code snippet; it
|
215
|
|
- * should initiate an asynchronous operation as a child of @c
|
216
|
|
- * async_temp and return an error status code if it failed to do so
|
217
|
|
- * (e.g. due to malloc() failure).
|
218
|
|
- */
|
219
|
|
-#define async_block_progress( async_temp, START ) ( { \
|
220
|
|
- int rc; \
|
221
|
|
- \
|
222
|
|
- async_init_orphan ( async_temp ); \
|
223
|
|
- if ( ( rc = START ) == 0 ) \
|
224
|
|
- async_wait_progress ( async_temp, &rc );\
|
225
|
|
- rc; \
|
226
|
|
- } )
|
227
|
|
-
|
228
|
|
-#endif /* _GPXE_ASYNC_H */
|