]>
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 | 109 | ASYNC_get_wait_ctx() can be used to get a pointer to the ASYNC_WAIT_CTX |
9f5a87fd PY |
110 | for the B<job>. ASYNC_WAIT_CTXs contain two different ways to notify |
111 | applications that a job is ready to be resumed. One is a "wait" file | |
112 | descriptor, and the other is a "callback" mechanism. | |
113 | ||
114 | The "wait" file descriptor associated with ASYNC_WAIT_CTX is used for | |
115 | applications to wait for the file descriptor to be ready for "read" using a | |
116 | system function call such as select or poll (being ready for "read" indicates | |
117 | that the job should be resumed). If no file descriptor is made available then | |
118 | an application will have to periodically "poll" the job by attempting to restart | |
119 | it to see if it is ready to continue. | |
120 | ||
121 | ASYNC_WAIT_CTXs also have a "callback" mechanism to notify applications. The | |
122 | callback is set by an application, and it will be automatically called when an | |
123 | engine completes a cryptography operation, so that the application can resume | |
124 | the paused work flow without polling. An engine could be written to look whether | |
125 | the callback has been set. If it has then it would use the callback mechanism | |
126 | in preference to the file descriptor notifications. If a callback is not set | |
127 | then the engine may use file descriptor based notifications. Please note that | |
128 | not all engines may support the callback mechanism, so the callback may not be | |
129 | used even if it has been set. See ASYNC_WAIT_CTX_new() for more details. | |
c00793da | 130 | |
e8dfb5bf MC |
131 | The ASYNC_block_pause() function will prevent the currently active job from |
132 | pausing. The block will remain in place until a subsequent call to | |
133 | ASYNC_unblock_pause(). These functions can be nested, e.g. if you call | |
134 | ASYNC_block_pause() twice then you must call ASYNC_unblock_pause() twice in | |
60250017 | 135 | order to re-enable pausing. If these functions are called while there is no |
e8dfb5bf MC |
136 | currently active job then they have no effect. This functionality can be useful |
137 | to avoid deadlock scenarios. For example during the execution of an ASYNC_JOB an | |
0d4fb843 | 138 | application acquires a lock. It then calls some cryptographic function which |
e8dfb5bf | 139 | invokes ASYNC_pause_job(). This returns control back to the code that created |
0d4fb843 | 140 | the ASYNC_JOB. If that code then attempts to acquire the same lock before |
e8dfb5bf | 141 | resuming the original job then a deadlock can occur. By calling |
35ed393e | 142 | ASYNC_block_pause() immediately after acquiring the lock and |
e8dfb5bf MC |
143 | ASYNC_unblock_pause() immediately before releasing it then this situation cannot |
144 | occur. | |
c00793da | 145 | |
667867cc MC |
146 | Some platforms cannot support async operations. The ASYNC_is_capable() function |
147 | can be used to detect whether the current platform is async capable or not. | |
148 | ||
c00793da MC |
149 | =head1 RETURN VALUES |
150 | ||
ff75a257 | 151 | ASYNC_init_thread returns 1 on success or 0 otherwise. |
c00793da MC |
152 | |
153 | ASYNC_start_job returns one of ASYNC_ERR, ASYNC_NO_JOBS, ASYNC_PAUSE or | |
154 | ASYNC_FINISH as described above. | |
155 | ||
0d4fb843 | 156 | ASYNC_pause_job returns 0 if an error occurred or 1 on success. If called when |
05a6347f MC |
157 | not within the context of an ASYNC_JOB then this is counted as success so 1 is |
158 | returned. | |
c00793da | 159 | |
c00793da MC |
160 | ASYNC_get_current_job returns a pointer to the currently executing ASYNC_JOB or |
161 | NULL if not within the context of a job. | |
162 | ||
ff75a257 MC |
163 | ASYNC_get_wait_ctx() returns a pointer to the ASYNC_WAIT_CTX for the job. |
164 | ||
667867cc MC |
165 | ASYNC_is_capable() returns 1 if the current platform is async capable or 0 |
166 | otherwise. | |
167 | ||
f1f5ee17 AP |
168 | =head1 NOTES |
169 | ||
170 | On Windows platforms the openssl/async.h header is dependent on some | |
171 | of the types customarily made available by including windows.h. The | |
172 | application developer is likely to require control over when the latter | |
173 | is included, commonly as one of the first included headers. Therefore | |
174 | it is defined as an application developer's responsibility to include | |
175 | windows.h prior to async.h. | |
176 | ||
c00793da MC |
177 | =head1 EXAMPLE |
178 | ||
179 | The following example demonstrates how to use most of the core async APIs: | |
180 | ||
f1f5ee17 AP |
181 | #ifdef _WIN32 |
182 | # include <windows.h> | |
183 | #endif | |
c00793da | 184 | #include <stdio.h> |
ff75a257 | 185 | #include <unistd.h> |
c00793da | 186 | #include <openssl/async.h> |
ff75a257 MC |
187 | #include <openssl/crypto.h> |
188 | ||
ff75a257 MC |
189 | int unique = 0; |
190 | ||
191 | void cleanup(ASYNC_WAIT_CTX *ctx, const void *key, OSSL_ASYNC_FD r, void *vw) | |
192 | { | |
193 | OSSL_ASYNC_FD *w = (OSSL_ASYNC_FD *)vw; | |
e9b77246 | 194 | |
ff75a257 MC |
195 | close(r); |
196 | close(*w); | |
197 | OPENSSL_free(w); | |
198 | } | |
c00793da MC |
199 | |
200 | int jobfunc(void *arg) | |
201 | { | |
202 | ASYNC_JOB *currjob; | |
203 | unsigned char *msg; | |
ff75a257 MC |
204 | int pipefds[2] = {0, 0}; |
205 | OSSL_ASYNC_FD *wptr; | |
91da5e77 | 206 | char buf = 'X'; |
c00793da MC |
207 | |
208 | currjob = ASYNC_get_current_job(); | |
209 | if (currjob != NULL) { | |
210 | printf("Executing within a job\n"); | |
211 | } else { | |
212 | printf("Not executing within a job - should not happen\n"); | |
213 | return 0; | |
214 | } | |
215 | ||
216 | msg = (unsigned char *)arg; | |
217 | printf("Passed in message is: %s\n", msg); | |
218 | ||
ff75a257 MC |
219 | if (pipe(pipefds) != 0) { |
220 | printf("Failed to create pipe\n"); | |
221 | return 0; | |
222 | } | |
223 | wptr = OPENSSL_malloc(sizeof(OSSL_ASYNC_FD)); | |
224 | if (wptr == NULL) { | |
225 | printf("Failed to malloc\n"); | |
226 | return 0; | |
227 | } | |
228 | *wptr = pipefds[1]; | |
229 | ASYNC_WAIT_CTX_set_wait_fd(ASYNC_get_wait_ctx(currjob), &unique, | |
230 | pipefds[0], wptr, cleanup); | |
231 | ||
c00793da MC |
232 | /* |
233 | * Normally some external event would cause this to happen at some | |
234 | * later point - but we do it here for demo purposes, i.e. | |
235 | * immediately signalling that the job is ready to be woken up after | |
236 | * we return to main via ASYNC_pause_job(). | |
237 | */ | |
ff75a257 | 238 | write(pipefds[1], &buf, 1); |
c00793da MC |
239 | |
240 | /* Return control back to main */ | |
241 | ASYNC_pause_job(); | |
242 | ||
243 | /* Clear the wake signal */ | |
ff75a257 | 244 | read(pipefds[0], &buf, 1); |
c00793da MC |
245 | |
246 | printf ("Resumed the job after a pause\n"); | |
247 | ||
248 | return 1; | |
249 | } | |
250 | ||
251 | int main(void) | |
252 | { | |
253 | ASYNC_JOB *job = NULL; | |
ff75a257 MC |
254 | ASYNC_WAIT_CTX *ctx = NULL; |
255 | int ret; | |
256 | OSSL_ASYNC_FD waitfd; | |
c00793da | 257 | fd_set waitfdset; |
ff75a257 | 258 | size_t numfds; |
c00793da MC |
259 | unsigned char msg[13] = "Hello world!"; |
260 | ||
c00793da MC |
261 | printf("Starting...\n"); |
262 | ||
ff75a257 MC |
263 | ctx = ASYNC_WAIT_CTX_new(); |
264 | if (ctx == NULL) { | |
265 | printf("Failed to create ASYNC_WAIT_CTX\n"); | |
266 | abort(); | |
267 | } | |
268 | ||
c00793da | 269 | for (;;) { |
2947af32 | 270 | switch (ASYNC_start_job(&job, ctx, &ret, jobfunc, msg, sizeof(msg))) { |
c00793da MC |
271 | case ASYNC_ERR: |
272 | case ASYNC_NO_JOBS: | |
2947af32 BB |
273 | printf("An error occurred\n"); |
274 | goto end; | |
c00793da | 275 | case ASYNC_PAUSE: |
2947af32 BB |
276 | printf("Job was paused\n"); |
277 | break; | |
c00793da | 278 | case ASYNC_FINISH: |
2947af32 BB |
279 | printf("Job finished with return value %d\n", ret); |
280 | goto end; | |
c00793da MC |
281 | } |
282 | ||
283 | /* Wait for the job to be woken */ | |
284 | printf("Waiting for the job to be woken up\n"); | |
1bc74519 | 285 | |
ff75a257 MC |
286 | if (!ASYNC_WAIT_CTX_get_all_fds(ctx, NULL, &numfds) |
287 | || numfds > 1) { | |
288 | printf("Unexpected number of fds\n"); | |
289 | abort(); | |
290 | } | |
291 | ASYNC_WAIT_CTX_get_all_fds(ctx, &waitfd, &numfds); | |
c00793da MC |
292 | FD_ZERO(&waitfdset); |
293 | FD_SET(waitfd, &waitfdset); | |
294 | select(waitfd + 1, &waitfdset, NULL, NULL, NULL); | |
295 | } | |
296 | ||
297 | end: | |
ff75a257 | 298 | ASYNC_WAIT_CTX_free(ctx); |
c00793da | 299 | printf("Finishing\n"); |
c00793da MC |
300 | |
301 | return 0; | |
302 | } | |
303 | ||
304 | The expected output from executing the above example program is: | |
305 | ||
306 | Starting... | |
307 | Executing within a job | |
308 | Passed in message is: Hello world! | |
309 | Job was paused | |
310 | Waiting for the job to be woken up | |
311 | Resumed the job after a pause | |
312 | Job finished with return value 1 | |
313 | Finishing | |
314 | ||
315 | =head1 SEE ALSO | |
316 | ||
b97fdb57 | 317 | L<crypto(7)>, L<ERR_print_errors(3)> |
c00793da MC |
318 | |
319 | =head1 HISTORY | |
320 | ||
667867cc MC |
321 | ASYNC_init_thread, ASYNC_cleanup_thread, |
322 | ASYNC_start_job, ASYNC_pause_job, ASYNC_get_current_job, ASYNC_get_wait_ctx(), | |
323 | ASYNC_block_pause(), ASYNC_unblock_pause() and ASYNC_is_capable() were first | |
fc5ecadd | 324 | added in OpenSSL 1.1.0. |
c00793da | 325 | |
e2f92610 RS |
326 | =head1 COPYRIGHT |
327 | ||
328 | Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved. | |
329 | ||
4746f25a | 330 | Licensed under the Apache License 2.0 (the "License"). You may not use |
e2f92610 RS |
331 | this file except in compliance with the License. You can obtain a copy |
332 | in the file LICENSE in the source distribution or at | |
333 | L<https://www.openssl.org/source/license.html>. | |
334 | ||
335 | =cut |