]>
Commit | Line | Data |
---|---|---|
c00793da MC |
1 | =pod |
2 | ||
3 | =head1 NAME | |
4 | ||
c952780c | 5 | ASYNC_get_wait_ctx, |
ff75a257 | 6 | ASYNC_init_thread, ASYNC_cleanup_thread, ASYNC_start_job, ASYNC_pause_job, |
667867cc MC |
7 | ASYNC_get_current_job, ASYNC_block_pause, ASYNC_unblock_pause, ASYNC_is_capable |
8 | - asynchronous job management functions | |
c00793da MC |
9 | |
10 | =head1 SYNOPSIS | |
11 | ||
12 | #include <openssl/async.h> | |
13 | ||
68487a9b MC |
14 | int ASYNC_init_thread(size_t max_size, size_t init_size); |
15 | void ASYNC_cleanup_thread(void); | |
c00793da | 16 | |
ff75a257 MC |
17 | int ASYNC_start_job(ASYNC_JOB **job, ASYNC_WAIT_CTX *ctx, int *ret, |
18 | int (*func)(void *), void *args, size_t size); | |
c00793da MC |
19 | int ASYNC_pause_job(void); |
20 | ||
c00793da | 21 | ASYNC_JOB *ASYNC_get_current_job(void); |
ff75a257 | 22 | ASYNC_WAIT_CTX *ASYNC_get_wait_ctx(ASYNC_JOB *job); |
e8dfb5bf MC |
23 | void ASYNC_block_pause(void); |
24 | void ASYNC_unblock_pause(void); | |
c00793da | 25 | |
667867cc MC |
26 | int ASYNC_is_capable(void); |
27 | ||
c00793da MC |
28 | =head1 DESCRIPTION |
29 | ||
30 | OpenSSL implements asynchronous capabilities through an ASYNC_JOB. This | |
31 | represents code that can be started and executes until some event occurs. At | |
32 | that point the code can be paused and control returns to user code until some | |
33 | subsequent event indicates that the job can be resumed. | |
34 | ||
35 | The creation of an ASYNC_JOB is a relatively expensive operation. Therefore, for | |
36 | efficiency reasons, jobs can be created up front and reused many times. They are | |
37 | held in a pool until they are needed, at which point they are removed from the | |
ff75a257 MC |
38 | pool, used, and then returned to the pool when the job completes. If the user |
39 | application is multi-threaded, then ASYNC_init_thread() may be called for each | |
40 | thread that will initiate asynchronous jobs. Before | |
41 | user code exits per-thread resources need to be cleaned up. This will normally | |
42 | occur automatically (see L<OPENSSL_init_crypto(3)>) but may be explicitly | |
43 | initiated by using ASYNC_cleanup_thread(). No asynchronous jobs must be | |
44 | outstanding for the thread when ASYNC_cleanup_thread() is called. Failing to | |
45 | ensure this will result in memory leaks. | |
82272550 MC |
46 | |
47 | The B<max_size> argument limits the number of ASYNC_JOBs that will be held in | |
48 | the pool. If B<max_size> is set to 0 then no upper limit is set. When an | |
49 | ASYNC_JOB is needed but there are none available in the pool already then one | |
50 | will be automatically created, as long as the total of ASYNC_JOBs managed by the | |
51 | pool does not exceed B<max_size>. When the pool is first initialised | |
68487a9b MC |
52 | B<init_size> ASYNC_JOBs will be created immediately. If ASYNC_init_thread() is |
53 | not called before the pool is first used then it will be called automatically | |
54 | with a B<max_size> of 0 (no upper limit) and an B<init_size> of 0 (no ASYNC_JOBs | |
ff75a257 | 55 | created up front). |
c00793da MC |
56 | |
57 | An asynchronous job is started by calling the ASYNC_start_job() function. | |
ff75a257 MC |
58 | Initially B<*job> should be NULL. B<ctx> should point to an ASYNC_WAIT_CTX |
59 | object created through the L<ASYNC_WAIT_CTX_new(3)> function. B<ret> should | |
60 | point to a location where the return value of the asynchronous function should | |
61 | be stored on completion of the job. B<func> represents the function that should | |
62 | be started asynchronously. The data pointed to by B<args> and of size B<size> | |
63 | will be copied and then passed as an argument to B<func> when the job starts. | |
64 | ASYNC_start_job will return one of the following values: | |
c00793da MC |
65 | |
66 | =over 4 | |
67 | ||
68 | =item B<ASYNC_ERR> | |
69 | ||
70 | An error occurred trying to start the job. Check the OpenSSL error queue (e.g. | |
71 | see L<ERR_print_errors(3)>) for more details. | |
72 | ||
73 | =item B<ASYNC_NO_JOBS> | |
74 | ||
75 | There are no jobs currently available in the pool. This call can be retried | |
76 | again at a later time. | |
77 | ||
78 | =item B<ASYNC_PAUSE> | |
79 | ||
80 | The job was successfully started but was "paused" before it completed (see | |
81 | ASYNC_pause_job() below). A handle to the job is placed in B<*job>. Other work | |
82 | can be performed (if desired) and the job restarted at a later time. To restart | |
83 | a job call ASYNC_start_job() again passing the job handle in B<*job>. The | |
84 | B<func>, B<args> and B<size> parameters will be ignored when restarting a job. | |
05a6347f MC |
85 | When restarting a job ASYNC_start_job() B<must> be called from the same thread |
86 | that the job was originally started from. | |
c00793da MC |
87 | |
88 | =item B<ASYNC_FINISH> | |
89 | ||
90 | The job completed. B<*job> will be NULL and the return value from B<func> will | |
91 | be placed in B<*ret>. | |
92 | ||
93 | =back | |
94 | ||
05a6347f MC |
95 | At any one time there can be a maximum of one job actively running per thread |
96 | (you can have many that are paused). ASYNC_get_current_job() can be used to get | |
97 | a pointer to the currently executing ASYNC_JOB. If no job is currently executing | |
98 | then this will return NULL. | |
c00793da MC |
99 | |
100 | If executing within the context of a job (i.e. having been called directly or | |
101 | indirectly by the function "func" passed as an argument to ASYNC_start_job()) | |
102 | then ASYNC_pause_job() will immediately return control to the calling | |
103 | application with ASYNC_PAUSE returned from the ASYNC_start_job() call. A | |
104 | subsequent call to ASYNC_start_job passing in the relevant ASYNC_JOB in the | |
105 | B<*job> parameter will resume execution from the ASYNC_pause_job() call. If | |
106 | ASYNC_pause_job() is called whilst not within the context of a job then no | |
107 | action is taken and ASYNC_pause_job() returns immediately. | |
108 | ||
ff75a257 MC |
109 | ASYNC_get_wait_ctx() can be used to get a pointer to the ASYNC_WAIT_CTX |
110 | for the B<job>. ASYNC_WAIT_CTXs can have a "wait" file descriptor associated | |
111 | with them. Applications can wait for the file descriptor to be ready for "read" | |
112 | using a system function call such as select or poll (being ready for "read" | |
113 | indicates that the job should be resumed). If no file descriptor is made | |
24c2cd39 | 114 | available then an application will have to periodically "poll" the job by |
ff75a257 | 115 | attempting to restart it to see if it is ready to continue. |
c00793da MC |
116 | |
117 | An example of typical usage might be an async capable engine. User code would | |
118 | initiate cryptographic operations. The engine would initiate those operations | |
ff75a257 MC |
119 | asynchronously and then call L<ASYNC_WAIT_CTX_set_wait_fd(3)> followed by |
120 | ASYNC_pause_job() to return control to the user code. The user code can then | |
121 | perform other tasks or wait for the job to be ready by calling "select" or other | |
122 | similar function on the wait file descriptor. The engine can signal to the user | |
123 | code that the job should be resumed by making the wait file descriptor | |
124 | "readable". Once resumed the engine should clear the wake signal on the wait | |
125 | file descriptor. | |
c00793da | 126 | |
e8dfb5bf MC |
127 | The ASYNC_block_pause() function will prevent the currently active job from |
128 | pausing. The block will remain in place until a subsequent call to | |
129 | ASYNC_unblock_pause(). These functions can be nested, e.g. if you call | |
130 | ASYNC_block_pause() twice then you must call ASYNC_unblock_pause() twice in | |
60250017 | 131 | order to re-enable pausing. If these functions are called while there is no |
e8dfb5bf MC |
132 | currently active job then they have no effect. This functionality can be useful |
133 | to avoid deadlock scenarios. For example during the execution of an ASYNC_JOB an | |
0d4fb843 | 134 | application acquires a lock. It then calls some cryptographic function which |
e8dfb5bf | 135 | invokes ASYNC_pause_job(). This returns control back to the code that created |
0d4fb843 | 136 | the ASYNC_JOB. If that code then attempts to acquire the same lock before |
e8dfb5bf | 137 | resuming the original job then a deadlock can occur. By calling |
35ed393e | 138 | ASYNC_block_pause() immediately after acquiring the lock and |
e8dfb5bf MC |
139 | ASYNC_unblock_pause() immediately before releasing it then this situation cannot |
140 | occur. | |
c00793da | 141 | |
667867cc MC |
142 | Some platforms cannot support async operations. The ASYNC_is_capable() function |
143 | can be used to detect whether the current platform is async capable or not. | |
144 | ||
c00793da MC |
145 | =head1 RETURN VALUES |
146 | ||
ff75a257 | 147 | ASYNC_init_thread returns 1 on success or 0 otherwise. |
c00793da MC |
148 | |
149 | ASYNC_start_job returns one of ASYNC_ERR, ASYNC_NO_JOBS, ASYNC_PAUSE or | |
150 | ASYNC_FINISH as described above. | |
151 | ||
0d4fb843 | 152 | ASYNC_pause_job returns 0 if an error occurred or 1 on success. If called when |
05a6347f MC |
153 | not within the context of an ASYNC_JOB then this is counted as success so 1 is |
154 | returned. | |
c00793da | 155 | |
c00793da MC |
156 | ASYNC_get_current_job returns a pointer to the currently executing ASYNC_JOB or |
157 | NULL if not within the context of a job. | |
158 | ||
ff75a257 MC |
159 | ASYNC_get_wait_ctx() returns a pointer to the ASYNC_WAIT_CTX for the job. |
160 | ||
667867cc MC |
161 | ASYNC_is_capable() returns 1 if the current platform is async capable or 0 |
162 | otherwise. | |
163 | ||
f1f5ee17 AP |
164 | =head1 NOTES |
165 | ||
166 | On Windows platforms the openssl/async.h header is dependent on some | |
167 | of the types customarily made available by including windows.h. The | |
168 | application developer is likely to require control over when the latter | |
169 | is included, commonly as one of the first included headers. Therefore | |
170 | it is defined as an application developer's responsibility to include | |
171 | windows.h prior to async.h. | |
172 | ||
c00793da MC |
173 | =head1 EXAMPLE |
174 | ||
175 | The following example demonstrates how to use most of the core async APIs: | |
176 | ||
f1f5ee17 AP |
177 | #ifdef _WIN32 |
178 | # include <windows.h> | |
179 | #endif | |
c00793da | 180 | #include <stdio.h> |
ff75a257 | 181 | #include <unistd.h> |
c00793da | 182 | #include <openssl/async.h> |
ff75a257 MC |
183 | #include <openssl/crypto.h> |
184 | ||
ff75a257 MC |
185 | int unique = 0; |
186 | ||
187 | void cleanup(ASYNC_WAIT_CTX *ctx, const void *key, OSSL_ASYNC_FD r, void *vw) | |
188 | { | |
189 | OSSL_ASYNC_FD *w = (OSSL_ASYNC_FD *)vw; | |
190 | close(r); | |
191 | close(*w); | |
192 | OPENSSL_free(w); | |
193 | } | |
c00793da MC |
194 | |
195 | int jobfunc(void *arg) | |
196 | { | |
197 | ASYNC_JOB *currjob; | |
198 | unsigned char *msg; | |
ff75a257 MC |
199 | int pipefds[2] = {0, 0}; |
200 | OSSL_ASYNC_FD *wptr; | |
91da5e77 | 201 | char buf = 'X'; |
c00793da MC |
202 | |
203 | currjob = ASYNC_get_current_job(); | |
204 | if (currjob != NULL) { | |
205 | printf("Executing within a job\n"); | |
206 | } else { | |
207 | printf("Not executing within a job - should not happen\n"); | |
208 | return 0; | |
209 | } | |
210 | ||
211 | msg = (unsigned char *)arg; | |
212 | printf("Passed in message is: %s\n", msg); | |
213 | ||
ff75a257 MC |
214 | if (pipe(pipefds) != 0) { |
215 | printf("Failed to create pipe\n"); | |
216 | return 0; | |
217 | } | |
218 | wptr = OPENSSL_malloc(sizeof(OSSL_ASYNC_FD)); | |
219 | if (wptr == NULL) { | |
220 | printf("Failed to malloc\n"); | |
221 | return 0; | |
222 | } | |
223 | *wptr = pipefds[1]; | |
224 | ASYNC_WAIT_CTX_set_wait_fd(ASYNC_get_wait_ctx(currjob), &unique, | |
225 | pipefds[0], wptr, cleanup); | |
226 | ||
c00793da MC |
227 | /* |
228 | * Normally some external event would cause this to happen at some | |
229 | * later point - but we do it here for demo purposes, i.e. | |
230 | * immediately signalling that the job is ready to be woken up after | |
231 | * we return to main via ASYNC_pause_job(). | |
232 | */ | |
ff75a257 | 233 | write(pipefds[1], &buf, 1); |
c00793da MC |
234 | |
235 | /* Return control back to main */ | |
236 | ASYNC_pause_job(); | |
237 | ||
238 | /* Clear the wake signal */ | |
ff75a257 | 239 | read(pipefds[0], &buf, 1); |
c00793da MC |
240 | |
241 | printf ("Resumed the job after a pause\n"); | |
242 | ||
243 | return 1; | |
244 | } | |
245 | ||
246 | int main(void) | |
247 | { | |
248 | ASYNC_JOB *job = NULL; | |
ff75a257 MC |
249 | ASYNC_WAIT_CTX *ctx = NULL; |
250 | int ret; | |
251 | OSSL_ASYNC_FD waitfd; | |
c00793da | 252 | fd_set waitfdset; |
ff75a257 | 253 | size_t numfds; |
c00793da MC |
254 | unsigned char msg[13] = "Hello world!"; |
255 | ||
c00793da MC |
256 | printf("Starting...\n"); |
257 | ||
ff75a257 MC |
258 | ctx = ASYNC_WAIT_CTX_new(); |
259 | if (ctx == NULL) { | |
260 | printf("Failed to create ASYNC_WAIT_CTX\n"); | |
261 | abort(); | |
262 | } | |
263 | ||
c00793da | 264 | for (;;) { |
ff75a257 | 265 | switch(ASYNC_start_job(&job, ctx, &ret, jobfunc, msg, sizeof(msg))) { |
c00793da MC |
266 | case ASYNC_ERR: |
267 | case ASYNC_NO_JOBS: | |
268 | printf("An error occurred\n"); | |
269 | goto end; | |
270 | case ASYNC_PAUSE: | |
271 | printf("Job was paused\n"); | |
272 | break; | |
273 | case ASYNC_FINISH: | |
274 | printf("Job finished with return value %d\n", ret); | |
275 | goto end; | |
276 | } | |
277 | ||
278 | /* Wait for the job to be woken */ | |
279 | printf("Waiting for the job to be woken up\n"); | |
1bc74519 | 280 | |
ff75a257 MC |
281 | if (!ASYNC_WAIT_CTX_get_all_fds(ctx, NULL, &numfds) |
282 | || numfds > 1) { | |
283 | printf("Unexpected number of fds\n"); | |
284 | abort(); | |
285 | } | |
286 | ASYNC_WAIT_CTX_get_all_fds(ctx, &waitfd, &numfds); | |
c00793da MC |
287 | FD_ZERO(&waitfdset); |
288 | FD_SET(waitfd, &waitfdset); | |
289 | select(waitfd + 1, &waitfdset, NULL, NULL, NULL); | |
290 | } | |
291 | ||
292 | end: | |
ff75a257 | 293 | ASYNC_WAIT_CTX_free(ctx); |
c00793da | 294 | printf("Finishing\n"); |
c00793da MC |
295 | |
296 | return 0; | |
297 | } | |
298 | ||
299 | The expected output from executing the above example program is: | |
300 | ||
301 | Starting... | |
302 | Executing within a job | |
303 | Passed in message is: Hello world! | |
304 | Job was paused | |
305 | Waiting for the job to be woken up | |
306 | Resumed the job after a pause | |
307 | Job finished with return value 1 | |
308 | Finishing | |
309 | ||
310 | =head1 SEE ALSO | |
311 | ||
312 | L<crypto(3)>, L<ERR_print_errors(3)> | |
313 | ||
314 | =head1 HISTORY | |
315 | ||
667867cc MC |
316 | ASYNC_init_thread, ASYNC_cleanup_thread, |
317 | ASYNC_start_job, ASYNC_pause_job, ASYNC_get_current_job, ASYNC_get_wait_ctx(), | |
318 | ASYNC_block_pause(), ASYNC_unblock_pause() and ASYNC_is_capable() were first | |
319 | added to OpenSSL 1.1.0. | |
c00793da | 320 | |
e2f92610 RS |
321 | =head1 COPYRIGHT |
322 | ||
323 | Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved. | |
324 | ||
325 | Licensed under the OpenSSL license (the "License"). You may not use | |
326 | this file except in compliance with the License. You can obtain a copy | |
327 | in the file LICENSE in the source distribution or at | |
328 | L<https://www.openssl.org/source/license.html>. | |
329 | ||
330 | =cut |