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 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 ASYNC_JOB is a relatively expensive operation. Therefore, for 36efficiency reasons, jobs can be created up front and reused many times. They are 37held in a pool until they are needed, at which point they are removed from the 38pool, used, and then returned to the pool when the job completes. If the user 39application is multi-threaded, then ASYNC_init_thread() may be called for each 40thread 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 B<max_size> argument limits the number of ASYNC_JOBs that will be held in 48the pool. If B<max_size> is set to 0 then no upper limit is set. When an 49ASYNC_JOB is needed but there are none available in the pool already then one 50will be automatically created, as long as the total of ASYNC_JOBs managed by the 51pool does not exceed B<max_size>. When the pool is first initialised 52B<init_size> ASYNC_JOBs will be created immediately. If ASYNC_init_thread() is 53not called before the pool is first used then it will be called automatically 54with a B<max_size> of 0 (no upper limit) and an B<init_size> of 0 (no ASYNC_JOBs 55created up front). 56 57An asynchronous job is started by calling the ASYNC_start_job() function. 58Initially B<*job> should be NULL. B<ctx> should point to an ASYNC_WAIT_CTX 59object created through the L<ASYNC_WAIT_CTX_new(3)> function. B<ret> should 60point to a location where the return value of the asynchronous function should 61be stored on completion of the job. B<func> represents the function that should 62be started asynchronously. The data pointed to by B<args> and of size B<size> 63will be copied and then passed as an argument to B<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 B<*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 B<*job>. The 84B<func>, B<args> and B<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. B<*job> will be NULL and the return value from B<func> will 91be placed in B<*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 ASYNC_JOB. If no job is currently executing 98then 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 ASYNC_PAUSE returned from the ASYNC_start_job() call. A 104subsequent call to ASYNC_start_job passing in the relevant ASYNC_JOB in the 105B<*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 ASYNC_WAIT_CTX 110for the B<job>. ASYNC_WAIT_CTXs can have a "wait" file descriptor associated 111with them. Applications can wait for the file descriptor to be ready for "read" 112using a system function call such as select or poll (being ready for "read" 113indicates that the job should be resumed). If no file descriptor is made 114available then an application will have to periodically "poll" the job by 115attempting to restart it to see if it is ready to continue. 116 117An example of typical usage might be an async capable engine. User code would 118initiate cryptographic operations. The engine would initiate those operations 119asynchronously and then call L<ASYNC_WAIT_CTX_set_wait_fd(3)> followed by 120ASYNC_pause_job() to return control to the user code. The user code can then 121perform other tasks or wait for the job to be ready by calling "select" or other 122similar function on the wait file descriptor. The engine can signal to the user 123code 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 125file descriptor. 126 127The ASYNC_block_pause() function will prevent the currently active job from 128pausing. The block will remain in place until a subsequent call to 129ASYNC_unblock_pause(). These functions can be nested, e.g. if you call 130ASYNC_block_pause() twice then you must call ASYNC_unblock_pause() twice in 131order to re-enable pausing. If these functions are called while there is no 132currently active job then they have no effect. This functionality can be useful 133to avoid deadlock scenarios. For example during the execution of an ASYNC_JOB an 134application acquires a lock. It then calls some cryptographic function which 135invokes ASYNC_pause_job(). This returns control back to the code that created 136the ASYNC_JOB. If that code then attempts to acquire the same lock before 137resuming the original job then a deadlock can occur. By calling 138ASYNC_block_pause() immediately after acquiring the lock and 139ASYNC_unblock_pause() immediately before releasing it then this situation cannot 140occur. 141 142Some platforms cannot support async operations. The ASYNC_is_capable() function 143can be used to detect whether the current platform is async capable or not. 144 145=head1 RETURN VALUES 146 147ASYNC_init_thread returns 1 on success or 0 otherwise. 148 149ASYNC_start_job returns one of ASYNC_ERR, ASYNC_NO_JOBS, ASYNC_PAUSE or 150ASYNC_FINISH as described above. 151 152ASYNC_pause_job returns 0 if an error occurred or 1 on success. If called when 153not within the context of an ASYNC_JOB then this is counted as success so 1 is 154returned. 155 156ASYNC_get_current_job returns a pointer to the currently executing ASYNC_JOB or 157NULL if not within the context of a job. 158 159ASYNC_get_wait_ctx() returns a pointer to the ASYNC_WAIT_CTX for the job. 160 161ASYNC_is_capable() returns 1 if the current platform is async capable or 0 162otherwise. 163 164=head1 NOTES 165 166On Windows platforms the openssl/async.h header is dependent on some 167of the types customarily made available by including windows.h. The 168application developer is likely to require control over when the latter 169is included, commonly as one of the first included headers. Therefore, 170it is defined as an application developer's responsibility to include 171windows.h prior to async.h. 172 173=head1 EXAMPLES 174 175The following example demonstrates how to use most of the core async APIs: 176 177 #ifdef _WIN32 178 # include <windows.h> 179 #endif 180 #include <stdio.h> 181 #include <unistd.h> 182 #include <openssl/async.h> 183 #include <openssl/crypto.h> 184 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 191 close(r); 192 close(*w); 193 OPENSSL_free(w); 194 } 195 196 int jobfunc(void *arg) 197 { 198 ASYNC_JOB *currjob; 199 unsigned char *msg; 200 int pipefds[2] = {0, 0}; 201 OSSL_ASYNC_FD *wptr; 202 char buf = 'X'; 203 204 currjob = ASYNC_get_current_job(); 205 if (currjob != NULL) { 206 printf("Executing within a job\n"); 207 } else { 208 printf("Not executing within a job - should not happen\n"); 209 return 0; 210 } 211 212 msg = (unsigned char *)arg; 213 printf("Passed in message is: %s\n", msg); 214 215 if (pipe(pipefds) != 0) { 216 printf("Failed to create pipe\n"); 217 return 0; 218 } 219 wptr = OPENSSL_malloc(sizeof(OSSL_ASYNC_FD)); 220 if (wptr == NULL) { 221 printf("Failed to malloc\n"); 222 return 0; 223 } 224 *wptr = pipefds[1]; 225 ASYNC_WAIT_CTX_set_wait_fd(ASYNC_get_wait_ctx(currjob), &unique, 226 pipefds[0], wptr, cleanup); 227 228 /* 229 * Normally some external event would cause this to happen at some 230 * later point - but we do it here for demo purposes, i.e. 231 * immediately signalling that the job is ready to be woken up after 232 * we return to main via ASYNC_pause_job(). 233 */ 234 write(pipefds[1], &buf, 1); 235 236 /* Return control back to main */ 237 ASYNC_pause_job(); 238 239 /* Clear the wake signal */ 240 read(pipefds[0], &buf, 1); 241 242 printf ("Resumed the job after a pause\n"); 243 244 return 1; 245 } 246 247 int main(void) 248 { 249 ASYNC_JOB *job = NULL; 250 ASYNC_WAIT_CTX *ctx = NULL; 251 int ret; 252 OSSL_ASYNC_FD waitfd; 253 fd_set waitfdset; 254 size_t numfds; 255 unsigned char msg[13] = "Hello world!"; 256 257 printf("Starting...\n"); 258 259 ctx = ASYNC_WAIT_CTX_new(); 260 if (ctx == NULL) { 261 printf("Failed to create ASYNC_WAIT_CTX\n"); 262 abort(); 263 } 264 265 for (;;) { 266 switch (ASYNC_start_job(&job, ctx, &ret, jobfunc, msg, sizeof(msg))) { 267 case ASYNC_ERR: 268 case ASYNC_NO_JOBS: 269 printf("An error occurred\n"); 270 goto end; 271 case ASYNC_PAUSE: 272 printf("Job was paused\n"); 273 break; 274 case ASYNC_FINISH: 275 printf("Job finished with return value %d\n", ret); 276 goto end; 277 } 278 279 /* Wait for the job to be woken */ 280 printf("Waiting for the job to be woken up\n"); 281 282 if (!ASYNC_WAIT_CTX_get_all_fds(ctx, NULL, &numfds) 283 || numfds > 1) { 284 printf("Unexpected number of fds\n"); 285 abort(); 286 } 287 ASYNC_WAIT_CTX_get_all_fds(ctx, &waitfd, &numfds); 288 FD_ZERO(&waitfdset); 289 FD_SET(waitfd, &waitfdset); 290 select(waitfd + 1, &waitfdset, NULL, NULL, NULL); 291 } 292 293 end: 294 ASYNC_WAIT_CTX_free(ctx); 295 printf("Finishing\n"); 296 297 return 0; 298 } 299 300The expected output from executing the above example program is: 301 302 Starting... 303 Executing within a job 304 Passed in message is: Hello world! 305 Job was paused 306 Waiting for the job to be woken up 307 Resumed the job after a pause 308 Job finished with return value 1 309 Finishing 310 311=head1 SEE ALSO 312 313L<crypto(7)>, L<ERR_print_errors(3)> 314 315=head1 HISTORY 316 317ASYNC_init_thread, ASYNC_cleanup_thread, 318ASYNC_start_job, ASYNC_pause_job, ASYNC_get_current_job, ASYNC_get_wait_ctx(), 319ASYNC_block_pause(), ASYNC_unblock_pause() and ASYNC_is_capable() were first 320added in OpenSSL 1.1.0. 321 322=head1 COPYRIGHT 323 324Copyright 2015-2020 The OpenSSL Project Authors. All Rights Reserved. 325 326Licensed under the OpenSSL license (the "License"). You may not use 327this file except in compliance with the License. You can obtain a copy 328in the file LICENSE in the source distribution or at 329L<https://www.openssl.org/source/license.html>. 330 331=cut 332