Add ASYNC_JOB pools
authorMatt Caswell <matt@openssl.org>
Wed, 22 Jul 2015 16:50:51 +0000 (17:50 +0100)
committerMatt Caswell <matt@openssl.org>
Fri, 20 Nov 2015 23:33:46 +0000 (23:33 +0000)
It is expensive to create the ASYNC_JOB objects due to the "makecontext"
call. This change adds support for pools of ASYNC_JOB objects so that we
don't have to create a new ASYNC_JOB every time we want to use one.

Reviewed-by: Rich Salz <rsalz@openssl.org>
apps/Makefile
apps/s_server.c
crypto/async/async.c
include/openssl/async.h
include/openssl/safestack.h
util/libeay.num

index 932f615..a6d931c 100644 (file)
@@ -802,29 +802,29 @@ s_client.o: ../include/openssl/tls1.h ../include/openssl/txt_db.h
 s_client.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
 s_client.o: ../include/openssl/x509v3.h apps.h progs.h s_apps.h s_client.c
 s_client.o: timeouts.h
-s_server.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s_server.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-s_server.o: ../include/openssl/comp.h ../include/openssl/conf.h
-s_server.o: ../include/openssl/crypto.h ../include/openssl/dh.h
-s_server.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s_server.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s_server.o: ../include/openssl/ecdsa.h ../include/openssl/engine.h
-s_server.o: ../include/openssl/err.h ../include/openssl/evp.h
-s_server.o: ../include/openssl/hmac.h ../include/openssl/lhash.h
-s_server.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s_server.o: ../include/openssl/ocsp.h ../include/openssl/opensslconf.h
-s_server.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-s_server.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-s_server.o: ../include/openssl/pkcs7.h ../include/openssl/rand.h
-s_server.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-s_server.o: ../include/openssl/sha.h ../include/openssl/srp.h
-s_server.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-s_server.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
-s_server.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-s_server.o: ../include/openssl/tls1.h ../include/openssl/txt_db.h
-s_server.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
-s_server.o: ../include/openssl/x509v3.h apps.h progs.h s_apps.h s_server.c
-s_server.o: timeouts.h
+s_server.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/async.h
+s_server.o: ../include/openssl/bio.h ../include/openssl/bn.h
+s_server.o: ../include/openssl/buffer.h ../include/openssl/comp.h
+s_server.o: ../include/openssl/conf.h ../include/openssl/crypto.h
+s_server.o: ../include/openssl/dh.h ../include/openssl/dtls1.h
+s_server.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
+s_server.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
+s_server.o: ../include/openssl/engine.h ../include/openssl/err.h
+s_server.o: ../include/openssl/evp.h ../include/openssl/hmac.h
+s_server.o: ../include/openssl/lhash.h ../include/openssl/obj_mac.h
+s_server.o: ../include/openssl/objects.h ../include/openssl/ocsp.h
+s_server.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
+s_server.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
+s_server.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
+s_server.o: ../include/openssl/rand.h ../include/openssl/rsa.h
+s_server.o: ../include/openssl/safestack.h ../include/openssl/sha.h
+s_server.o: ../include/openssl/srp.h ../include/openssl/srtp.h
+s_server.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
+s_server.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
+s_server.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
+s_server.o: ../include/openssl/txt_db.h ../include/openssl/x509.h
+s_server.o: ../include/openssl/x509_vfy.h ../include/openssl/x509v3.h apps.h
+s_server.o: progs.h s_apps.h s_server.c timeouts.h
 s_socket.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 s_socket.o: ../include/openssl/buffer.h ../include/openssl/comp.h
 s_socket.o: ../include/openssl/conf.h ../include/openssl/crypto.h
index 548eacb..6fb8f67 100644 (file)
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <openssl/async.h>
 
 #include <openssl/e_os2.h>
 
@@ -1657,8 +1658,10 @@ int s_server_main(int argc, char *argv[])
     else
         SSL_CTX_sess_set_cache_size(ctx, 128);
 
-    if (async)
+    if (async) {
         SSL_CTX_set_mode(ctx, SSL_MODE_ASYNC);
+        ASYNC_init_pool(0, 0, 0);
+    }
 
 #ifndef OPENSSL_NO_SRTP
     if (srtp_profiles != NULL) {
@@ -1970,6 +1973,9 @@ int s_server_main(int argc, char *argv[])
     bio_s_out = NULL;
     BIO_free(bio_s_msg);
     bio_s_msg = NULL;
+    if (async) {
+        ASYNC_free_pool();
+    }
     return (ret);
 }
 
index c0f362e..6fed197 100644 (file)
 #define ASYNC_JOB_PAUSED    2
 #define ASYNC_JOB_STOPPING  3
 
+static size_t pool_max_size = 0;
+static size_t curr_size = 0;
+
+DECLARE_STACK_OF(ASYNC_JOB)
+static STACK_OF(ASYNC_JOB) *pool = NULL;
+
 
 static ASYNC_CTX *ASYNC_CTX_new(void)
 {
@@ -121,22 +127,60 @@ static void ASYNC_JOB_free(ASYNC_JOB *job)
     }
 }
 
-void ASYNC_start_func(void)
-{
+static ASYNC_JOB *async_get_pool_job(void) {
     ASYNC_JOB *job;
 
-    /* Run the job */
-    job = ASYNC_get_ctx()->currjob;
-    job->ret = job->func(job->funcargs);
-
-    /* Stop the job */
-    job->status = ASYNC_JOB_STOPPING;
-    if(!ASYNC_FIBRE_swapcontext(&job->fibrectx,
-                                &ASYNC_get_ctx()->dispatcher, 0)) {
+    if (pool == NULL) {
         /*
-         * Should not happen. Getting here will close the thread...can't do much
-         * about it
+         * Pool has not been initialised, so init with the defaults, i.e.
+         * global pool, with no max size and no pre-created jobs
          */
+        if (ASYNC_init_pool(0, 0, 0) == 0)
+            return NULL;
+    }
+
+    job = sk_ASYNC_JOB_pop(pool);
+    if (job == NULL) {
+        /* Pool is empty */
+        if (pool_max_size && curr_size >= pool_max_size) {
+            /* Pool is at max size. We cannot continue */
+            return NULL;
+        }
+        job = ASYNC_JOB_new();
+        if (job) {
+            ASYNC_FIBRE_makecontext(&job->fibrectx);
+            curr_size++;
+        }
+    }
+    return job;
+}
+
+static void async_release_job(ASYNC_JOB *job) {
+    if(job->funcargs)
+        OPENSSL_free(job->funcargs);
+    job->funcargs = NULL;
+    /* Ignore error return */
+    sk_ASYNC_JOB_push(pool, job);
+}
+
+void ASYNC_start_func(void)
+{
+    ASYNC_JOB *job;
+
+    while (1) {
+        /* Run the job */
+        job = ASYNC_get_ctx()->currjob;
+        job->ret = job->func(job->funcargs);
+
+        /* Stop the job */
+        job->status = ASYNC_JOB_STOPPING;
+        if(!ASYNC_FIBRE_swapcontext(&job->fibrectx,
+                                    &ASYNC_get_ctx()->dispatcher, 1)) {
+            /*
+             * Should not happen. Getting here will close the thread...can't do much
+             * about it
+             */
+        }
     }
 }
 
@@ -155,7 +199,7 @@ int ASYNC_start_job(ASYNC_JOB **job, int *ret, int (*func)(void *),
         if(ASYNC_get_ctx()->currjob) {
             if(ASYNC_get_ctx()->currjob->status == ASYNC_JOB_STOPPING) {
                 *ret = ASYNC_get_ctx()->currjob->ret;
-                ASYNC_JOB_free(ASYNC_get_ctx()->currjob);
+                async_release_job(ASYNC_get_ctx()->currjob);
                 ASYNC_get_ctx()->currjob = NULL;
                 *job = NULL;
                 ASYNC_CTX_free();
@@ -179,7 +223,7 @@ int ASYNC_start_job(ASYNC_JOB **job, int *ret, int (*func)(void *),
             }
 
             /* Should not happen */
-            ASYNC_JOB_free(ASYNC_get_ctx()->currjob);
+            async_release_job(ASYNC_get_ctx()->currjob);
             ASYNC_get_ctx()->currjob = NULL;
             *job = NULL;
             ASYNC_CTX_free();
@@ -187,15 +231,15 @@ int ASYNC_start_job(ASYNC_JOB **job, int *ret, int (*func)(void *),
         }
 
         /* Start a new job */
-        if(!(ASYNC_get_ctx()->currjob = ASYNC_JOB_new())) {
+        if(!(ASYNC_get_ctx()->currjob = async_get_pool_job())) {
             ASYNC_CTX_free();
-            return ASYNC_ERR;
+            return ASYNC_NO_JOBS;
         }
 
         if(args != NULL) {
             ASYNC_get_ctx()->currjob->funcargs = OPENSSL_malloc(size);
             if(!ASYNC_get_ctx()->currjob->funcargs) {
-                ASYNC_JOB_free(ASYNC_get_ctx()->currjob);
+                async_release_job(ASYNC_get_ctx()->currjob);
                 ASYNC_get_ctx()->currjob = NULL;
                 ASYNC_CTX_free();
                 return ASYNC_ERR;
@@ -206,14 +250,13 @@ int ASYNC_start_job(ASYNC_JOB **job, int *ret, int (*func)(void *),
         }
 
         ASYNC_get_ctx()->currjob->func = func;
-        ASYNC_FIBRE_makecontext(&ASYNC_get_ctx()->currjob->fibrectx);
         if(!ASYNC_FIBRE_swapcontext(&ASYNC_get_ctx()->dispatcher,
             &ASYNC_get_ctx()->currjob->fibrectx, 1))
             goto err;
     }
 
 err:
-    ASYNC_JOB_free(ASYNC_get_ctx()->currjob);
+    async_release_job(ASYNC_get_ctx()->currjob);
     ASYNC_get_ctx()->currjob = NULL;
     *job = NULL;
     ASYNC_CTX_free();
@@ -247,3 +290,48 @@ int ASYNC_in_job(void)
 
     return 0;
 }
+
+int ASYNC_init_pool(unsigned int local, size_t max_size, size_t init_size)
+{
+    if (local != 0) {
+        /* We only support a global pool so far */
+        return 0;
+    }
+
+    pool_max_size = max_size;
+    pool = sk_ASYNC_JOB_new_null();
+    if (pool == NULL) {
+        return 0;
+    }
+    /* Pre-create jobs as required */
+    while (init_size) {
+        ASYNC_JOB *job;
+        job = ASYNC_JOB_new();
+        if (job) {
+            ASYNC_FIBRE_makecontext(&job->fibrectx);
+            job->funcargs = NULL;
+            sk_ASYNC_JOB_push(pool, job);
+            curr_size++;
+            init_size--;
+        } else {
+            /*
+             * Not actually fatal because we already created the pool, just skip
+             * creation of any more jobs
+             */
+            init_size = 0;
+        }
+    }
+
+    return 1;
+}
+
+void ASYNC_free_pool(void)
+{
+    ASYNC_JOB *job;
+
+    do {
+        job = sk_ASYNC_JOB_pop(pool);
+        ASYNC_JOB_free(job);
+    } while (job);
+    sk_ASYNC_JOB_free(pool);
+}
index ff59857..1cd7992 100644 (file)
@@ -63,8 +63,12 @@ extern "C" {
 typedef struct async_job_st ASYNC_JOB;
 
 #define ASYNC_ERR      0
-#define ASYNC_PAUSE    1
-#define ASYNC_FINISH   2
+#define ASYNC_NO_JOBS  1
+#define ASYNC_PAUSE    2
+#define ASYNC_FINISH   3
+
+int ASYNC_init_pool(unsigned int local, size_t max_size, size_t init_size);
+void ASYNC_free_pool(void);
 
 int ASYNC_start_job(ASYNC_JOB **job, int *ret, int (*func)(void *),
                          void *args, size_t size);
index 785bec6..f2fa57c 100644 (file)
@@ -412,6 +412,29 @@ DECLARE_SPECIAL_STACK_OF(OPENSSL_BLOCK, void)
 # define sk_ASN1_VALUE_sort(st) SKM_sk_sort(ASN1_VALUE, (st))
 # define sk_ASN1_VALUE_is_sorted(st) SKM_sk_is_sorted(ASN1_VALUE, (st))
 
+# define sk_ASYNC_JOB_new(cmp) SKM_sk_new(ASYNC_JOB, (cmp))
+# define sk_ASYNC_JOB_new_null() SKM_sk_new_null(ASYNC_JOB)
+# define sk_ASYNC_JOB_free(st) SKM_sk_free(ASYNC_JOB, (st))
+# define sk_ASYNC_JOB_num(st) SKM_sk_num(ASYNC_JOB, (st))
+# define sk_ASYNC_JOB_value(st, i) SKM_sk_value(ASYNC_JOB, (st), (i))
+# define sk_ASYNC_JOB_set(st, i, val) SKM_sk_set(ASYNC_JOB, (st), (i), (val))
+# define sk_ASYNC_JOB_zero(st) SKM_sk_zero(ASYNC_JOB, (st))
+# define sk_ASYNC_JOB_push(st, val) SKM_sk_push(ASYNC_JOB, (st), (val))
+# define sk_ASYNC_JOB_unshift(st, val) SKM_sk_unshift(ASYNC_JOB, (st), (val))
+# define sk_ASYNC_JOB_find(st, val) SKM_sk_find(ASYNC_JOB, (st), (val))
+# define sk_ASYNC_JOB_find_ex(st, val) SKM_sk_find_ex(ASYNC_JOB, (st), (val))
+# define sk_ASYNC_JOB_delete(st, i) SKM_sk_delete(ASYNC_JOB, (st), (i))
+# define sk_ASYNC_JOB_delete_ptr(st, ptr) SKM_sk_delete_ptr(ASYNC_JOB, (st), (ptr))
+# define sk_ASYNC_JOB_insert(st, val, i) SKM_sk_insert(ASYNC_JOB, (st), (val), (i))
+# define sk_ASYNC_JOB_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ASYNC_JOB, (st), (cmp))
+# define sk_ASYNC_JOB_dup(st) SKM_sk_dup(ASYNC_JOB, st)
+# define sk_ASYNC_JOB_pop_free(st, free_func) SKM_sk_pop_free(ASYNC_JOB, (st), (free_func))
+# define sk_ASYNC_JOB_deep_copy(st, copy_func, free_func) SKM_sk_deep_copy(ASYNC_JOB, (st), (copy_func), (free_func))
+# define sk_ASYNC_JOB_shift(st) SKM_sk_shift(ASYNC_JOB, (st))
+# define sk_ASYNC_JOB_pop(st) SKM_sk_pop(ASYNC_JOB, (st))
+# define sk_ASYNC_JOB_sort(st) SKM_sk_sort(ASYNC_JOB, (st))
+# define sk_ASYNC_JOB_is_sorted(st) SKM_sk_is_sorted(ASYNC_JOB, (st))
+
 # define sk_BIO_new(cmp) SKM_sk_new(BIO, (cmp))
 # define sk_BIO_new_null() SKM_sk_new_null(BIO)
 # define sk_BIO_free(st) SKM_sk_free(BIO, (st))
index 8a6c4c5..4b6893d 100755 (executable)
@@ -4654,3 +4654,5 @@ ASYNC_pause_job                         5013      EXIST::FUNCTION:
 ASYNC_job_is_waiting                    5014   NOEXIST::FUNCTION:
 ASYNC_in_job                            5015   EXIST::FUNCTION:
 ASYNC_start_job                         5016   EXIST::FUNCTION:
+ASYNC_init_pool                         5017   EXIST::FUNCTION:
+ASYNC_free_pool                         5018   EXIST::FUNCTION: