1=pod 2 3=head1 NAME 4 5ASYNC_get_wait_ctx, 6ASYNC_init_thread, ASYNC_cleanup_thread, ASYNC_start_job, ASYNC_pause_job, 7ASYNC_get_current_job, ASYNC_block_pause, ASYNC_unblock_pause, ASYNC_is_capable 8- asynchronous job management functions 9 10=head1 SYNOPSIS 11 12 #include <openssl/async.h> 13 14 int ASYNC_init_thread(size_t max_size, size_t init_size); 15 void ASYNC_cleanup_thread(void); 16 17 int ASYNC_start_job(ASYNC_JOB **job, ASYNC_WAIT_CTX *ctx, int *ret, 18 int (*func)(void *), void *args, size_t size); 19 int ASYNC_pause_job(void); 20 21 ASYNC_JOB *ASYNC_get_current_job(void); 22 ASYNC_WAIT_CTX *ASYNC_get_wait_ctx(ASYNC_JOB *job); 23 void ASYNC_block_pause(void); 24 void ASYNC_unblock_pause(void); 25 26 int ASYNC_is_capable(void); 27 28=head1 DESCRIPTION 29 30OpenSSL implements asynchronous capabilities through an B<ASYNC_JOB>. This 31represents code that can be started and executes until some event occurs. At 32that point the code can be paused and control returns to user code until some 33subsequent event indicates that the job can be resumed. 34 35The creation of an B<ASYNC_JOB> is a relatively expensive operation. Therefore, 36for efficiency reasons, jobs can be created up front and reused many times. They 37are held in a pool until they are needed, at which point they are removed from 38the pool, used, and then returned to the pool when the job completes. If the 39user application is multi-threaded, then ASYNC_init_thread() may be called for 40each thread that will initiate asynchronous jobs. Before 41user code exits per-thread resources need to be cleaned up. This will normally 42occur automatically (see L<OPENSSL_init_crypto(3)>) but may be explicitly 43initiated by using ASYNC_cleanup_thread(). No asynchronous jobs must be 44outstanding for the thread when ASYNC_cleanup_thread() is called. Failing to 45ensure this will result in memory leaks. 46 47The I<max_size> argument limits the number of B<ASYNC_JOB>s that will be held in 48the pool. If I<max_size> is set to 0 then no upper limit is set. When an 49B<ASYNC_JOB> is needed but there are none available in the pool already then one 50will be automatically created, as long as the total of B<ASYNC_JOB>s managed by 51the pool does not exceed I<max_size>. When the pool is first initialised 52I<init_size> B<ASYNC_JOB>s will be created immediately. If ASYNC_init_thread() 53is not called before the pool is first used then it will be called automatically 54with a I<max_size> of 0 (no upper limit) and an I<init_size> of 0 (no 55B<ASYNC_JOB>s created up front). 56 57An asynchronous job is started by calling the ASYNC_start_job() function. 58Initially I<*job> should be NULL. I<ctx> should point to an B<ASYNC_WAIT_CTX> 59object created through the L<ASYNC_WAIT_CTX_new(3)> function. I<ret> should 60point to a location where the return value of the asynchronous function should 61be stored on completion of the job. I<func> represents the function that should 62be started asynchronously. The data pointed to by I<args> and of size I<size> 63will be copied and then passed as an argument to I<func> when the job starts. 64ASYNC_start_job will return one of the following values: 65 66=over 4 67 68=item B<ASYNC_ERR> 69 70An error occurred trying to start the job. Check the OpenSSL error queue (e.g. 71see L<ERR_print_errors(3)>) for more details. 72 73=item B<ASYNC_NO_JOBS> 74 75There are no jobs currently available in the pool. This call can be retried 76again at a later time. 77 78=item B<ASYNC_PAUSE> 79 80The job was successfully started but was "paused" before it completed (see 81ASYNC_pause_job() below). A handle to the job is placed in I<*job>. Other work 82can be performed (if desired) and the job restarted at a later time. To restart 83a job call ASYNC_start_job() again passing the job handle in I<*job>. The 84I<func>, I<args> and I<size> parameters will be ignored when restarting a job. 85When restarting a job ASYNC_start_job() B<must> be called from the same thread 86that the job was originally started from. 87 88=item B<ASYNC_FINISH> 89 90The job completed. I<*job> will be NULL and the return value from I<func> will 91be placed in I<*ret>. 92 93=back 94 95At 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 97a pointer to the currently executing B<ASYNC_JOB>. If no job is currently 98executing then this will return NULL. 99 100If executing within the context of a job (i.e. having been called directly or 101indirectly by the function "func" passed as an argument to ASYNC_start_job()) 102then ASYNC_pause_job() will immediately return control to the calling 103application with B<ASYNC_PAUSE> returned from the ASYNC_start_job() call. A 104subsequent call to ASYNC_start_job passing in the relevant B<ASYNC_JOB> in the 105I<*job> parameter will resume execution from the ASYNC_pause_job() call. If 106ASYNC_pause_job() is called whilst not within the context of a job then no 107action is taken and ASYNC_pause_job() returns immediately. 108 109ASYNC_get_wait_ctx() can be used to get a pointer to the B<ASYNC_WAIT_CTX> 110for the I<job>. B<ASYNC_WAIT_CTX>s contain two different ways to notify 111applications that a job is ready to be resumed. One is a "wait" file 112descriptor, and the other is a "callback" mechanism. 113 114The "wait" file descriptor associated with B<ASYNC_WAIT_CTX> is used for 115applications to wait for the file descriptor to be ready for "read" using a 116system function call such as select or poll (being ready for "read" indicates 117that the job should be resumed). If no file descriptor is made available then 118an application will have to periodically "poll" the job by attempting to restart 119it to see if it is ready to continue. 120 121B<ASYNC_WAIT_CTX>s also have a "callback" mechanism to notify applications. The 122callback is set by an application, and it will be automatically called when an 123engine completes a cryptography operation, so that the application can resume 124the paused work flow without polling. An engine could be written to look whether 125the callback has been set. If it has then it would use the callback mechanism 126in preference to the file descriptor notifications. If a callback is not set 127then the engine may use file descriptor based notifications. Please note that 128not all engines may support the callback mechanism, so the callback may not be 129used even if it has been set. See ASYNC_WAIT_CTX_new() for more details. 130 131The ASYNC_block_pause() function will prevent the currently active job from 132pausing. The block will remain in place until a subsequent call to 133ASYNC_unblock_pause(). These functions can be nested, e.g. if you call 134ASYNC_block_pause() twice then you must call ASYNC_unblock_pause() twice in 135order to re-enable pausing. If these functions are called while there is no 136currently active job then they have no effect. This functionality can be useful 137to avoid deadlock scenarios. For example during the execution of an B<ASYNC_JOB> 138an application acquires a lock. It then calls some cryptographic function which 139invokes ASYNC_pause_job(). This returns control back to the code that created 140the B<ASYNC_JOB>. If that code then attempts to acquire the same lock before 141resuming the original job then a deadlock can occur. By calling 142ASYNC_block_pause() immediately after acquiring the lock and 143ASYNC_unblock_pause() immediately before releasing it then this situation cannot 144occur. 145 146Some platforms cannot support async operations. The ASYNC_is_capable() function 147can be used to detect whether the current platform is async capable or not. 148 149=head1 RETURN VALUES 150 151ASYNC_init_thread returns 1 on success or 0 otherwise. 152 153ASYNC_start_job returns one of B<ASYNC_ERR>, B<ASYNC_NO_JOBS>, B<ASYNC_PAUSE> or 154B<ASYNC_FINISH> as described above. 155 156ASYNC_pause_job returns 0 if an error occurred or 1 on success. If called when 157not within the context of an B<ASYNC_JOB> then this is counted as success so 1 158is returned. 159 160ASYNC_get_current_job returns a pointer to the currently executing B<ASYNC_JOB> 161or NULL if not within the context of a job. 162 163ASYNC_get_wait_ctx() returns a pointer to the B<ASYNC_WAIT_CTX> for the job. 164 165ASYNC_is_capable() returns 1 if the current platform is async capable or 0 166otherwise. 167 168=head1 NOTES 169 170On Windows platforms the F<< <openssl/async.h> >> header is dependent on some 171of the types customarily made available by including F<< <windows.h> >>. The 172application developer is likely to require control over when the latter 173is included, commonly as one of the first included headers. Therefore, 174it is defined as an application developer's responsibility to include 175F<< <windows.h> >> prior to F<< <openssl/async.h> >>. 176 177=head1 EXAMPLES 178 179The following example demonstrates how to use most of the core async APIs: 180 181 #ifdef _WIN32 182 # include <windows.h> 183 #endif 184 #include <stdio.h> 185 #include <unistd.h> 186 #include <openssl/async.h> 187 #include <openssl/crypto.h> 188 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; 194 195 close(r); 196 close(*w); 197 OPENSSL_free(w); 198 } 199 200 int jobfunc(void *arg) 201 { 202 ASYNC_JOB *currjob; 203 unsigned char *msg; 204 int pipefds[2] = {0, 0}; 205 OSSL_ASYNC_FD *wptr; 206 char buf = 'X'; 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 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 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 */ 238 write(pipefds[1], &buf, 1); 239 240 /* Return control back to main */ 241 ASYNC_pause_job(); 242 243 /* Clear the wake signal */ 244 read(pipefds[0], &buf, 1); 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; 254 ASYNC_WAIT_CTX *ctx = NULL; 255 int ret; 256 OSSL_ASYNC_FD waitfd; 257 fd_set waitfdset; 258 size_t numfds; 259 unsigned char msg[13] = "Hello world!"; 260 261 printf("Starting...\n"); 262 263 ctx = ASYNC_WAIT_CTX_new(); 264 if (ctx == NULL) { 265 printf("Failed to create ASYNC_WAIT_CTX\n"); 266 abort(); 267 } 268 269 for (;;) { 270 switch (ASYNC_start_job(&job, ctx, &ret, jobfunc, msg, sizeof(msg))) { 271 case ASYNC_ERR: 272 case ASYNC_NO_JOBS: 273 printf("An error occurred\n"); 274 goto end; 275 case ASYNC_PAUSE: 276 printf("Job was paused\n"); 277 break; 278 case ASYNC_FINISH: 279 printf("Job finished with return value %d\n", ret); 280 goto end; 281 } 282 283 /* Wait for the job to be woken */ 284 printf("Waiting for the job to be woken up\n"); 285 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); 292 FD_ZERO(&waitfdset); 293 FD_SET(waitfd, &waitfdset); 294 select(waitfd + 1, &waitfdset, NULL, NULL, NULL); 295 } 296 297 end: 298 ASYNC_WAIT_CTX_free(ctx); 299 printf("Finishing\n"); 300 301 return 0; 302 } 303 304The 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 317L<crypto(7)>, L<ERR_print_errors(3)> 318 319=head1 HISTORY 320 321ASYNC_init_thread, ASYNC_cleanup_thread, 322ASYNC_start_job, ASYNC_pause_job, ASYNC_get_current_job, ASYNC_get_wait_ctx(), 323ASYNC_block_pause(), ASYNC_unblock_pause() and ASYNC_is_capable() were first 324added in OpenSSL 1.1.0. 325 326=head1 COPYRIGHT 327 328Copyright 2015-2021 The OpenSSL Project Authors. All Rights Reserved. 329 330Licensed under the Apache License 2.0 (the "License"). You may not use 331this file except in compliance with the License. You can obtain a copy 332in the file LICENSE in the source distribution or at 333L<https://www.openssl.org/source/license.html>. 334 335=cut 336