Add support for dynamically created and destroyed mutexes. This will
authorRichard Levitte <levitte@openssl.org>
Sun, 18 Jun 2000 15:59:04 +0000 (15:59 +0000)
committerRichard Levitte <levitte@openssl.org>
Sun, 18 Jun 2000 15:59:04 +0000 (15:59 +0000)
be needed in some ENGINE code, and might serve elsewhere as well.
Note that it's implemented in such a way that the locking itself is
done through the same CRYPTO_lock function as the static locks.

WARNING: This is currently experimental and untested code (it will get
tested soon, though :-)).

crypto/cpt_err.c
crypto/cryptlib.c
crypto/crypto.h
crypto/stack/safestack.h
doc/crypto/threads.pod
util/libeay.num

index dadd8d8d928ccb564f4c73c572cde02df90663f6..7018b74ca0148ec2a3019e1812e67c31eff493b4 100644 (file)
@@ -67,6 +67,7 @@
 static ERR_STRING_DATA CRYPTO_str_functs[]=
        {
 {ERR_PACK(0,CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX,0),       "CRYPTO_get_ex_new_index"},
+{ERR_PACK(0,CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID,0),      "CRYPTO_get_new_dynlockid"},
 {ERR_PACK(0,CRYPTO_F_CRYPTO_GET_NEW_LOCKID,0), "CRYPTO_get_new_lockid"},
 {ERR_PACK(0,CRYPTO_F_CRYPTO_SET_EX_DATA,0),    "CRYPTO_set_ex_data"},
 {0,NULL}
@@ -74,6 +75,7 @@ static ERR_STRING_DATA CRYPTO_str_functs[]=
 
 static ERR_STRING_DATA CRYPTO_str_reasons[]=
        {
+{CRYPTO_R_NO_DYNLOCK_CREATE_CALLBACK     ,"no dynlock create callback"},
 {0,NULL}
        };
 
index 90156d0072bc8762710973a4a2d6d2f530ac91ab..bc692720c5762e2b506b295e28221591cef2d92a 100644 (file)
 #include <string.h>
 #include "cryptlib.h"
 #include <openssl/crypto.h>
+#include <openssl/safestack.h>
 
 #if defined(WIN32) || defined(WIN16)
 static double SSLeay_MSVC5_hack=0.0; /* and for VC1.5 */
 #endif
 
+DECLARE_STACK_OF(CRYPTO_dynlock);
+IMPLEMENT_STACK_OF(CRYPTO_dynlock);
+
 /* real #defines in crypto.h, keep these upto date */
 static const char* lock_names[CRYPTO_NUM_LOCKS] =
        {
@@ -100,13 +104,30 @@ static const char* lock_names[CRYPTO_NUM_LOCKS] =
 #endif
        };
 
+/* This is for applications to allocate new type names in the non-dynamic
+   array of lock names.  These are numbered with positive numbers.  */
 static STACK *app_locks=NULL;
 
+/* For applications that want a more dynamic way of handling threads, the
+   following stack is used.  These are externally numbered with negative
+   numbers.  */
+static STACK_OF(CRYPTO_dynlock) *dyn_locks=NULL;
+
+
 static void (MS_FAR *locking_callback)(int mode,int type,
        const char *file,int line)=NULL;
 static int (MS_FAR *add_lock_callback)(int *pointer,int amount,
        int type,const char *file,int line)=NULL;
 static unsigned long (MS_FAR *id_callback)(void)=NULL;
+static CRYPTO_dynlock *(MS_FAR *dynlock_create_callback)(const char *file,
+       int line)=NULL;
+static void (MS_FAR *dynlock_locking_callback)(int mode, CRYPTO_dynlock *l,
+       const char *file,int line)=NULL;
+static void (MS_FAR *dynlock_destroy_callback)(CRYPTO_dynlock *l,
+       const char *file,int line)=NULL;
+static int (MS_FAR *add_dynlock_callback)(int *pointer,int amount,
+       CRYPTO_dynlock *l,const char *file,int line)=NULL;
+
 int CRYPTO_get_new_lockid(char *name)
        {
        char *str;
@@ -126,7 +147,10 @@ int CRYPTO_get_new_lockid(char *name)
                return(0);
                }
        if ((str=BUF_strdup(name)) == NULL)
+               {
+               CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_LOCKID,ERR_R_MALLOC_FAILURE);
                return(0);
+               }
        i=sk_push(app_locks,str);
        if (!i)
                OPENSSL_free(str);
@@ -140,30 +164,112 @@ int CRYPTO_num_locks(void)
        return CRYPTO_NUM_LOCKS;
        }
 
+int CRYPTO_get_new_dynlockid(void)
+       {
+       int i = 0;
+       CRYPTO_dynlock *pointer = NULL;
+
+       if (dynlock_create_callback == NULL)
+               {
+               CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID,CRYPTO_R_NO_DYNLOCK_CREATE_CALLBACK);
+               return(0);
+               }
+       if ((dyn_locks == NULL)
+               && ((dyn_locks=sk_new_null()) == NULL))
+               {
+               CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID,ERR_R_MALLOC_FAILURE);
+               return(0);
+               }
+
+       pointer = dynlock_create_callback(__FILE__,__LINE__);
+       if (pointer == NULL)
+               {
+               CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID,ERR_R_MALLOC_FAILURE);
+               return(0);
+               }
+       i=sk_CRYPTO_dynlock_push(dyn_locks,pointer);
+       if (!i)
+               dynlock_destroy_callback(pointer,__FILE__,__LINE__);
+       else
+               i += 1; /* to avoid 0 */
+       return -i;
+       }
+
+void CRYPTO_destroy_dynlockid(int i)
+       {
+       if (i)
+               i = -i-1;
+       if (dyn_locks == NULL || i >= sk_CRYPTO_dynlock_num(dyn_locks))
+               return;
+       if (dynlock_destroy_callback == NULL)
+               return;
+       dynlock_destroy_callback(sk_CRYPTO_dynlock_value(dyn_locks, i),
+               __FILE__,__LINE__);
+       sk_CRYPTO_dynlock_set(dyn_locks, i, NULL);
+       }
+
+CRYPTO_dynlock *CRYPTO_get_dynlock_value(int i)
+       {
+       if (i)
+               i = -i-1;
+       if (dyn_locks == NULL || i >= sk_CRYPTO_dynlock_num(dyn_locks))
+               return NULL;
+       return sk_CRYPTO_dynlock_value(dyn_locks, i);
+       }
+
 void (*CRYPTO_get_locking_callback(void))(int mode,int type,const char *file,
                int line)
        {
        return(locking_callback);
        }
 
+void (*CRYPTO_get_dynlock_lock_callback(void))(int mode,CRYPTO_dynlock *l,
+                                              const char *file,int line)
+       {
+       return(dynlock_locking_callback);
+       }
+
 int (*CRYPTO_get_add_lock_callback(void))(int *num,int mount,int type,
                                          const char *file,int line)
        {
        return(add_lock_callback);
        }
 
+int (*CRYPTO_get_add_dynlock_callback(void))(int *num,int mount,
+                                            CRYPTO_dynlock *l,
+                                            const char *file,int line)
+       {
+       return(add_dynlock_callback);
+       }
+
 void CRYPTO_set_locking_callback(void (*func)(int mode,int type,
                                              const char *file,int line))
        {
        locking_callback=func;
        }
 
+void CRYPTO_set_dynlock_locking_callback(void (*func)(int mode,
+                                                     CRYPTO_dynlock *l,
+                                                     const char *file,
+                                                     int line))
+       {
+       dynlock_locking_callback=func;
+       }
+
 void CRYPTO_set_add_lock_callback(int (*func)(int *num,int mount,int type,
                                              const char *file,int line))
        {
        add_lock_callback=func;
        }
 
+void CRYPTO_set_add_dynlock_lock_callback(int (*func)(int *num,int mount,
+                                                     CRYPTO_dynlock *l,
+                                                     const char *file,
+                                                     int line))
+       {
+       add_dynlock_callback=func;
+       }
+
 unsigned long (*CRYPTO_get_id_callback(void))(void)
        {
        return(id_callback);
@@ -220,14 +326,23 @@ void CRYPTO_lock(int mode, int type, const char *file, int line)
                        CRYPTO_get_lock_name(type), file, line);
                }
 #endif
-       if (locking_callback != NULL)
-               locking_callback(mode,type,file,line);
+       if (type < 0)
+               {
+               int i = -type-1;
+               if (i < sk_CRYPTO_dynlock_num(dyn_locks))
+                       dynlock_locking_callback(mode,
+                               sk_CRYPTO_dynlock_value(dyn_locks,i),
+                               file,line);
+               }
+       else
+               if (locking_callback != NULL)
+                       locking_callback(mode,type,file,line);
        }
 
 int CRYPTO_add_lock(int *pointer, int amount, int type, const char *file,
             int line)
        {
-       int ret;
+       int ret = 0;
 
        if (add_lock_callback != NULL)
                {
@@ -235,7 +350,21 @@ int CRYPTO_add_lock(int *pointer, int amount, int type, const char *file,
                int before= *pointer;
 #endif
 
-               ret=add_lock_callback(pointer,amount,type,file,line);
+               if (type < 0)
+                       {
+                       int i = -type-1;
+                       if (i >= sk_CRYPTO_dynlock_num(dyn_locks))
+                               /* FIXME: This is superbly dangerous if there
+                                  are threads competing on this value, but
+                                  hey, if the user used an invalid lock... */
+                               ret=(*pointer + amount);
+                       else
+                               ret=add_dynlock_callback(pointer,amount,
+                                       sk_CRYPTO_dynlock_value(dyn_locks,i),
+                                       file,line);
+                       }
+               else
+                       ret=add_lock_callback(pointer,amount,type,file,line);
 #ifdef LOCK_DEBUG
                fprintf(stderr,"ladd:%08lx:%2d+%2d->%2d %-18s %s:%d\n",
                        CRYPTO_thread_id(),
@@ -266,7 +395,7 @@ int CRYPTO_add_lock(int *pointer, int amount, int type, const char *file,
 const char *CRYPTO_get_lock_name(int type)
        {
        if (type < 0)
-               return("ERROR");
+               return("dynamic");
        else if (type < CRYPTO_NUM_LOCKS)
                return(lock_names[type]);
        else if (type-CRYPTO_NUM_LOCKS >= sk_num(app_locks))
index 9a3a6f8b00fc9ee0a2ced2df3376f6fd2baf7f1e..9e5f2e29226b325df0dd580ac0a3eff881ecf3da 100644 (file)
@@ -150,6 +150,12 @@ extern "C" {
 #define CRYPTO_add(a,b,c)      ((*(a))+=(b))
 #endif
 
+/* Some applications as well as some parts of OpenSSL need to allocate
+   and deallocate locks in a dynamic fashion.  The following typedef
+   makes this possible in a type-safe manner.  */
+typedef struct CRYPTO_dynlock_value CRYPTO_dynlock;
+
+
 /* The following can be used to detect memory leaks in the SSLeay library.
  * It used, it turns on malloc checking */
 
@@ -299,6 +305,16 @@ unsigned long CRYPTO_thread_id(void);
 const char *CRYPTO_get_lock_name(int type);
 int CRYPTO_add_lock(int *pointer,int amount,int type, const char *file,
                    int line);
+void CRYPTO_set_dynlock_create_callback(CRYPTO_dynlock *(*dyn_create_function)
+       (char *file, int line));
+void CRYPTO_set_dynlock_lock_callback(void (*dyn_lock_function)
+       (int mode, CRYPTO_dynlock *l, const char *file, int line));
+void CRYPTO_set_dynlock_destroy_callback(void (*dyn_destroy_function)
+       (CRYPTO_dynlock *l, const char *file, int line));
+void CRYPTO_set_dynlock_size(int dynlock_size);
+int CRYPTO_get_new_dynlockid(void);
+void CRYPTO_destroy_dynlockid(int i);
+CRYPTO_dynlock *CRYPTO_get_dynlock_value(int i);
 
 /* CRYPTO_set_mem_functions includes CRYPTO_set_locked_mem_functions --
  * call the latter last if you need different functions */
@@ -371,12 +387,15 @@ void ERR_load_CRYPTO_strings(void);
 
 /* Function codes. */
 #define CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX                100
+#define CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID               103
 #define CRYPTO_F_CRYPTO_GET_NEW_LOCKID                  101
 #define CRYPTO_F_CRYPTO_SET_EX_DATA                     102
 
 /* Reason codes. */
+#define CRYPTO_R_NO_DYNLOCK_CREATE_CALLBACK             100
 
 #ifdef  __cplusplus
 }
 #endif
 #endif
+
index 8cc022b456f5034de4b8201600f293aaed14770c..1a550244acb7adf94daac90e804fcdc3dc569f83 100644 (file)
@@ -164,6 +164,26 @@ STACK_OF(type) \
 #endif
 
 /* This block of defines is updated by util/mkstack.pl, please do not touch! */
+#define sk_CRYPTO_dynlock_new(st) SKM_sk_new(CRYPTO_dynlock, (st))
+#define sk_CRYPTO_dynlock_new_null() SKM_sk_new_null(CRYPTO_dynlock)
+#define sk_CRYPTO_dynlock_free(st) SKM_sk_free(CRYPTO_dynlock, (st))
+#define sk_CRYPTO_dynlock_num(st) SKM_sk_num(CRYPTO_dynlock, (st))
+#define sk_CRYPTO_dynlock_value(st, i) SKM_sk_value(CRYPTO_dynlock, (st), (i))
+#define sk_CRYPTO_dynlock_set(st, i, val) SKM_sk_set(CRYPTO_dynlock, (st), (i), (val))
+#define sk_CRYPTO_dynlock_zero(st) SKM_sk_zero(CRYPTO_dynlock, (st))
+#define sk_CRYPTO_dynlock_push(st, val) SKM_sk_push(CRYPTO_dynlock, (st), (val))
+#define sk_CRYPTO_dynlock_unshift(st, val) SKM_sk_unshift(CRYPTO_dynlock, (st), (val))
+#define sk_CRYPTO_dynlock_find(st, val) SKM_sk_find(CRYPTO_dynlock, (st), (val))
+#define sk_CRYPTO_dynlock_delete(st, i) SKM_sk_delete(CRYPTO_dynlock, (st), (i))
+#define sk_CRYPTO_dynlock_delete_ptr(st, ptr) SKM_sk_delete_ptr(CRYPTO_dynlock, (st), (ptr))
+#define sk_CRYPTO_dynlock_insert(st, val, i) SKM_sk_insert(CRYPTO_dynlock, (st), (val), (i))
+#define sk_CRYPTO_dynlock_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(CRYPTO_dynlock, (st), (cmp))
+#define sk_CRYPTO_dynlock_dup(st) SKM_sk_dup(CRYPTO_dynlock, st)
+#define sk_CRYPTO_dynlock_pop_free(st, free_func) SKM_sk_pop_free(CRYPTO_dynlock, (st), (free_func))
+#define sk_CRYPTO_dynlock_shift(st) SKM_sk_shift(CRYPTO_dynlock, (st))
+#define sk_CRYPTO_dynlock_pop(st) SKM_sk_pop(CRYPTO_dynlock, (st))
+#define sk_CRYPTO_dynlock_sort(st) SKM_sk_sort(CRYPTO_dynlock, (st))
+
 #define sk_CRYPTO_EX_DATA_FUNCS_new(st) SKM_sk_new(CRYPTO_EX_DATA_FUNCS, (st))
 #define sk_CRYPTO_EX_DATA_FUNCS_new_null() SKM_sk_new_null(CRYPTO_EX_DATA_FUNCS)
 #define sk_CRYPTO_EX_DATA_FUNCS_free(st) SKM_sk_free(CRYPTO_EX_DATA_FUNCS, (st))
index 5da056f3f82366182888269b41727088441c24fb..a31b170806f8694e90a100d44d4ce9c961f3e9dd 100644 (file)
@@ -15,10 +15,27 @@ CRYPTO_set_locking_callback, CRYPTO_set_id_callback - OpenSSL thread support
 
  int CRYPTO_num_locks(void);
 
+
+ /* struct CRYPTO_dynlock_value needs to be defined by the user */
+ typedef struct CRYPTO_dynlock_value CRYPTO_dynlock;
+
+ void CRYPTO_set_dynlock_create_callback(CRYPTO_dynlock *(*dyn_create_function)
+       (char *file, int line));
+ void CRYPTO_set_dynlock_lock_callback(void (*dyn_lock_function)
+       (int mode, CRYPTO_dynlock *l, const char *file, int line));
+ void CRYPTO_set_dynlock_destroy_callback(void (*dyn_destroy_function)
+       (CRYPTO_dynlock *l, const char *file, int line));
+
+ int CRYPTO_get_new_dynlockid(void);
+
+ void CRYPTO_destroy_dynlockid(int i);
+
+ void CRYPTO_lock(int mode, int n, const char *file, int line);
+
 =head1 DESCRIPTION
 
 OpenSSL can safely be used in multi-threaded applications provided
-that two callback functions are set.
+that at least two callback functions are set.
 
 locking_function(int mode, int n, const char *file, int line) is
 needed to perform locking on shared data stuctures. Multi-threaded
@@ -35,9 +52,55 @@ id_function(void) is a function that returns a thread ID. It is not
 needed on Windows nor on platforms where getpid() returns a different
 ID for each thread (most notably Linux).
 
+Additionally, OpenSSL supports dynamic locks, and sometimes, some parts
+of OpenSSL need it for better performance.  To enable this, the following
+is required:
+
+=item *
+Three additional callback function, dyn_create_function, dyn_lock_function
+and dyn_destroy_function.
+
+=item *
+A structure defined with the data that each lock needs to handle.
+
+struct CRYPTO_dynlock_value has to be defined to contain whatever structure
+is needed to handle locks.
+
+dyn_create_function(const char *file, int line) is needed to create a
+lock.  Multi-threaded applications might crash at random if it is not set.
+
+dyn_lock_function(int mode, CRYPTO_dynlock *l, const char *file, int line)
+is needed to perform locking off dynamic lock nunmbered n. Multi-threaded
+applications might crash at random if it is not set.
+
+dyn_destroy_function(CRYPTO_dynlock *l, const char *file, int line) is
+needed to destroy the lock l. Multi-threaded applications might crash at
+random if it is not set.
+
+CRYPTO_get_new_dynlockid() is used to create locks.  It will call
+dyn_create_function for the actual creation.
+
+CRYPTO_destroy_dynlockid() is used to destroy locks.  It will call
+dyn_destroy_function for the actual destruction.
+
+CRYPTO_lock() is used to lock and unlock the locks.  mode is a bitfield
+describing what should be done with the lock.  n is the number of the
+lock as returned from CRYPTO_get_new_dynlockid().  mode can be combined
+from the following values.  These values are pairwise exclusive, with
+undefined behavior if misused (for example, CRYPTO_READ and CRYPTO_WRITE
+should not be used together):
+
+       CRYPTO_LOCK     0x01
+       CRYPTO_UNLOCK   0x02
+       CRYPTO_READ     0x04
+       CRYPTO_WRITE    0x08
+
 =head1 RETURN VALUES
 
 CRYPTO_num_locks() returns the required number of locks.
+
+CRYPTO_get_new_dynlockid() returns the index to the newly created lock.
+
 The other functions return no values.
 
 =head1 NOTE
@@ -62,6 +125,7 @@ Solaris, Irix and Win32.
 CRYPTO_set_locking_callback() and CRYPTO_set_id_callback() are
 available in all versions of SSLeay and OpenSSL.
 CRYPTO_num_locks() was added in OpenSSL 0.9.4.
+All functions dealing with dynamic locks were added in OpenSSL 0.9.5b-dev.
 
 =head1 SEE ALSO
 
index fdb90afd5c3efcad12dbaec55f861767dd444b58..311afa19fe1dbbeab5537b2d297c06d1d8128169 100755 (executable)
@@ -1810,3 +1810,10 @@ i2d_RSA_NET                             2406
 d2i_RSA_NET_2                           2407
 d2i_RSA_NET                             2408
 DSO_bind_func                           2409
+CRYPTO_get_new_dynlockid                2410
+sk_new_null                             2411
+CRYPTO_set_dynlock_destroy_callback     2412
+CRYPTO_destroy_dynlockid                2413
+CRYPTO_set_dynlock_size                 2414
+CRYPTO_set_dynlock_create_callback      2415
+CRYPTO_set_dynlock_lock_callback        2416