+static int test_ASYNC_start_job_ex(void)
+{
+ ASYNC_JOB *job = NULL;
+ int funcret;
+ ASYNC_WAIT_CTX *waitctx = NULL;
+ OSSL_LIB_CTX *libctx = OSSL_LIB_CTX_new();
+ OSSL_LIB_CTX *oldctx, *tmpctx, *globalctx;
+ int ret = 0;
+
+ if (libctx == NULL) {
+ fprintf(stderr,
+ "test_ASYNC_start_job_ex() failed to create libctx\n");
+ goto err;
+ }
+
+ globalctx = oldctx = OSSL_LIB_CTX_set0_default(libctx);
+
+ if ((waitctx = ASYNC_WAIT_CTX_new()) == NULL
+ || ASYNC_start_job(&job, waitctx, &funcret, change_deflt_libctx,
+ NULL, 0)
+ != ASYNC_PAUSE) {
+ fprintf(stderr,
+ "test_ASYNC_start_job_ex() failed to start job\n");
+ goto err;
+ }
+
+ /* Reset the libctx temporarily to find out what it is*/
+ tmpctx = OSSL_LIB_CTX_set0_default(oldctx);
+ oldctx = OSSL_LIB_CTX_set0_default(tmpctx);
+ if (tmpctx != libctx) {
+ fprintf(stderr,
+ "test_ASYNC_start_job_ex() failed - unexpected libctx\n");
+ goto err;
+ }
+
+ if (ASYNC_start_job(&job, waitctx, &funcret, change_deflt_libctx, NULL, 0)
+ != ASYNC_PAUSE) {
+ fprintf(stderr,
+ "test_ASYNC_start_job_ex() - restarting job failed\n");
+ goto err;
+ }
+
+ /* Reset the libctx and continue with the global default libctx */
+ tmpctx = OSSL_LIB_CTX_set0_default(oldctx);
+ if (tmpctx != libctx) {
+ fprintf(stderr,
+ "test_ASYNC_start_job_ex() failed - unexpected libctx\n");
+ goto err;
+ }
+
+ if (ASYNC_start_job(&job, waitctx, &funcret, change_deflt_libctx, NULL, 0)
+ != ASYNC_FINISH
+ || funcret != 1) {
+ fprintf(stderr,
+ "test_ASYNC_start_job_ex() - finishing job failed\n");
+ goto err;
+ }
+
+ /* Reset the libctx temporarily to find out what it is*/
+ tmpctx = OSSL_LIB_CTX_set0_default(libctx);
+ OSSL_LIB_CTX_set0_default(tmpctx);
+ if (tmpctx != globalctx) {
+ fprintf(stderr,
+ "test_ASYNC_start_job_ex() failed - global libctx check failed\n");
+ goto err;
+ }
+
+ ret = 1;
+ err:
+ ASYNC_WAIT_CTX_free(waitctx);
+ ASYNC_cleanup_thread();
+ OSSL_LIB_CTX_free(libctx);
+ return ret;
+}
+
+static void *test_alloc_stack(size_t *num)
+{
+ custom_alloc_used = 1;
+ return OPENSSL_malloc(*num);
+}
+
+static void test_free_stack(void *addr)
+{
+ custom_free_used = 1;
+ OPENSSL_free(addr);
+}
+
+static int test_ASYNC_set_mem_functions(void)
+{
+ ASYNC_stack_alloc_fn alloc_fn;
+ ASYNC_stack_free_fn free_fn;
+
+ /* Not all platforms support this */
+ if (ASYNC_set_mem_functions(test_alloc_stack, test_free_stack) == 0) return 1;
+
+ ASYNC_get_mem_functions(&alloc_fn, &free_fn);
+
+ if ((alloc_fn != test_alloc_stack) || (free_fn != test_free_stack)) {
+ fprintf(stderr,
+ "test_ASYNC_set_mem_functions() - setting and retrieving custom allocators failed\n");
+ return 0;
+ }
+
+ if (!ASYNC_init_thread(1, 1)) {
+ fprintf(stderr,
+ "test_ASYNC_set_mem_functions() - failed initialising ctx pool\n");
+ return 0;
+ }
+ ASYNC_cleanup_thread();
+
+ if (!custom_alloc_used || !custom_free_used) {
+ fprintf(stderr,
+ "test_ASYNC_set_mem_functions() - custom allocation functions not used\n");
+
+ return 0;
+ }
+
+ return 1;
+}
+