The OpenSSL library does not directly contain support for thread
safe code. Instead it relies on application code to register some
callbacks to perform the locking required. Under eCos there are two
ways of doing this: through the POSIX compatibility package and
directly using eCos APIs.
POSIX locking support is already available in OpenSSL. Example code
is available in src/crypto/threads/th-lock.c,
and similar code is tested in the mttest test
program. However, this code will only work in threads that have been
created using pthread_create(), or in the
main() application thread.
eCos locking support uses lower level primitives and can be used from
any kind of thread. In order to provide locking, an application must
register two callbacks with the library, and set up an array of
locks that the library will request it to lock and unlock. The
following code does this:
// Forward definitions for callback functions.
void ecos_locking_callback(int mode, int type, char *file, int line);
unsigned long ecos_thread_id_callback(void);
// Pointer to array of locks.
static cyg_mutex_t *lock_cs;
// This function allocates and initializes the lock array
// and registers the callbacks. This should be called
// after the OpenSSL library has been initialized and
// before any new threads are created.
void thread_setup(void)
{
int i;
// Allocate lock array according to OpenSSL's requirements
lock_cs=OPENSSL_malloc(CRYPTO_num_locks() * sizeof(cyg_mutex_t));
// Initialize the locks
for (i=0; i<CRYPTO_num_locks(); i++)
{
cyg_mutex_init(&(lock_cs[i]));
}
// Register callbacks
CRYPTO_set_id_callback((unsigned long (*)())ecos_thread_id_callback);
CRYPTO_set_locking_callback((void (*)())ecos_locking_callback);
}
// This function deallocates the lock array and deregisters the
// callbacks. It should be called after all threads have
// terminated.
void thread_cleanup(void)
{
int i;
// Deregister locking callback. No real need to
// deregister id callback.
CRYPTO_set_locking_callback(NULL);
// Destroy the locks
for (i=0; i<CRYPTO_num_locks(); i++)
{
cyg_mutex_destroy(&(lock_cs[i]));
}
// Release the lock array.
OPENSSL_free(lock_cs);
}
// Locking callback. The type, file and line arguments are
// ignored. The file and line may be used to identify the site of the
// call in the OpenSSL library for diagnostic purposes if required.
void ecos_locking_callback(int mode, int type, char *file, int line)
{
if (mode & CRYPTO_LOCK)
{
cyg_mutex_lock(&(lock_cs[type]));
}
else
{
cyg_mutex_unlock(&(lock_cs[type]));
}
}
// Thread id callback.
unsigned long ecos_thread_id_callback(void)
{
return (unsigned long)cyg_thread_get_id(cyg_thread_self());
}
Example code similar to this can be found in the
mttest_ecos test program.