提交 c7922304 编写于 作者: R Richard Levitte

Add support for dynamically created and destroyed mutexes. This will

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 :-)).
上级 a8b07aa4
......@@ -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}
};
......
......@@ -60,11 +60,15 @@
#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))
......
......@@ -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
......@@ -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))
......
......@@ -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
......
......@@ -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
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册