diff options
author | Stef Walter <stefw@collabora.co.uk> | 2011-10-10 17:32:34 +0200 |
---|---|---|
committer | Stef Walter <stefw@collabora.co.uk> | 2011-10-10 17:32:34 +0200 |
commit | 73880f950a7dadf712730222ac1b6ea11400746f (patch) | |
tree | 60614947ff4d469ab5020c0146aafdb23e466f9b /tests | |
parent | 630ce95d7b9ec3ac3cbe71f75910711369274314 (diff) |
Only call C_Initialize and C_Finalize once per module
* Do not concurretnly call C_Initialize or C_Finalize in a module
* The PKCS#11 spec indicates that mone thread should call those functions.
* It's reasonable for a module to expect to only be initialized or
finalized in one thread.
* In particular NSS does not lock its C_Initialize or C_Finalize.
Diffstat (limited to 'tests')
-rw-r--r-- | tests/mock-module.c | 4 | ||||
-rw-r--r-- | tests/test-init.c | 105 |
2 files changed, 106 insertions, 3 deletions
diff --git a/tests/mock-module.c b/tests/mock-module.c index a1a6a7e..201fffc 100644 --- a/tests/mock-module.c +++ b/tests/mock-module.c @@ -156,8 +156,8 @@ CK_RV mock_C_Finalize (CK_VOID_PTR reserved) { debug (("C_Finalize: enter")); - return_val_if_fail (pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - return_val_if_fail (!reserved, CKR_ARGUMENTS_BAD); + return_val_if_fail (pkcs11_initialized != 0, CKR_CRYPTOKI_NOT_INITIALIZED); + return_val_if_fail (reserved == NULL, CKR_ARGUMENTS_BAD); pthread_mutex_lock (&init_mutex); diff --git a/tests/test-init.c b/tests/test-init.c index 5d96d81..d57b49f 100644 --- a/tests/test-init.c +++ b/tests/test-init.c @@ -39,6 +39,7 @@ #include <sys/wait.h> #include <assert.h> +#include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -94,7 +95,6 @@ test_fork_initialization (CuTest *tc) CuAssertTrue (tc, rv == CKR_OK); } - static CK_RV mock_C_Initialize__with_recursive (CK_VOID_PTR init_args) { @@ -120,6 +120,108 @@ test_recursive_initialization (CuTest *tc) CuAssertTrue (tc, rv == CKR_FUNCTION_FAILED); } +static pthread_mutex_t race_mutex = PTHREAD_MUTEX_INITIALIZER; +static int initialization_count = 0; +static int finalization_count = 0; + +#include "private.h" + +static CK_RV +mock_C_Initialize__threaded_race (CK_VOID_PTR init_args) +{ + struct timespec ts = { 0, 100 * 1000 * 1000 }; + + /* Atomically increment value */ + pthread_mutex_lock (&race_mutex); + initialization_count += 1; + pthread_mutex_unlock (&race_mutex); + + nanosleep (&ts, NULL); + return CKR_OK; +} + +static CK_RV +mock_C_Finalize__threaded_race (CK_VOID_PTR reserved) +{ + struct timespec ts = { 0, 100 * 1000 * 1000 }; + + /* Atomically increment value */ + pthread_mutex_lock (&race_mutex); + finalization_count += 1; + pthread_mutex_unlock (&race_mutex); + + nanosleep (&ts, NULL); + return CKR_OK; +} + +static void * +initialization_thread (void *data) +{ + CuTest *tc = data; + CK_RV rv; + + rv = p11_kit_initialize_module (&module); + CuAssertTrue (tc, rv == CKR_OK); + + return tc; +} + +static void * +finalization_thread (void *data) +{ + CuTest *tc = data; + CK_RV rv; + + rv = p11_kit_finalize_module (&module); + CuAssertTrue (tc, rv == CKR_OK); + + return tc; +} + +static void +test_threaded_initialization (CuTest *tc) +{ + static const int num_threads = 100; + pthread_t threads[num_threads]; + void *retval; + int ret; + int i; + + /* Build up our own function list */ + memcpy (&module, &mock_module_no_slots, sizeof (CK_FUNCTION_LIST)); + module.C_Initialize = mock_C_Initialize__threaded_race; + module.C_Finalize = mock_C_Finalize__threaded_race; + + initialization_count = 0; + finalization_count = 0; + + for (i = 0; i < num_threads; i++) { + ret = pthread_create (&threads[i], NULL, initialization_thread, tc); + CuAssertIntEquals (tc, 0, ret); + } + + for (i = 0; i < num_threads; i++) { + ret = pthread_join (threads[i], &retval); + CuAssertIntEquals (tc, 0, ret); + CuAssertPtrEquals (tc, tc, retval); + } + + for (i = 0; i < num_threads; i++) { + ret = pthread_create (&threads[i], NULL, finalization_thread, tc); + CuAssertIntEquals (tc, 0, ret); + } + + for (i = 0; i < num_threads; i++) { + ret = pthread_join (threads[i], &retval); + CuAssertIntEquals (tc, 0, ret); + CuAssertPtrEquals (tc, tc, retval); + } + + /* C_Initialize should have been called exactly once */ + CuAssertIntEquals (tc, 1, initialization_count); + CuAssertIntEquals (tc, 1, finalization_count); +} + int main (void) { @@ -129,6 +231,7 @@ main (void) SUITE_ADD_TEST (suite, test_fork_initialization); SUITE_ADD_TEST (suite, test_recursive_initialization); + SUITE_ADD_TEST (suite, test_threaded_initialization); CuSuiteRun (suite); CuSuiteSummary (suite, output); |