Thread Safety

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.

2017-02-09
Documentation license for this page: eCosPro License