| RSA BSAFE Micro Edition Suite |
Streamlined security for mobile and embedded devices |
 
![]() |
/* $Id: thread.c,v 1.35 2005/02/04 04:59:59 jmckee Exp $ */ /* * Copyright (C) 1998-2003 RSA Security Inc. * * This file shall only be used to demonstrate how to interface to an * RSA Security Inc. licensed development product. * * You have a royalty-free right to use, reproduce and distribute this * demonstration file, provided that you agree that RSA Security Inc. * has no warranty, implied or otherwise, or liability for this * demonstration file (including any modified version). This software * is provided "as is" without warranties or representations of any * kind. RSA Security disclaims all conditions and warranties, statutory * and otherwise, both express and implied, with respect to the software, * its quality and performance, including but not limited to, all * implied warranties of merchantability, fitness for a particular * purpose, title and noninfringement of third party rights. Without * limiting the foregoing, RSA Security does not warrant that the * software is error-free or that errors in the product will be * corrected. You agree that RSA Security shall not be liable for any * direct, indirect, incidental, special, consequential, punitive or * other damages whatsoever resulting from your use of this software * or any modified version. * * */ #include "r_prod.h" #define MAX_THREAD_NUMBER 256 /* Include the header files for the callbacks */ #include "../cb/thread/mt_cb.h" void app_thread_main(void *arg); BIO *bio_err = NULL; BIO *bio_out = NULL; static int app_lockid = 0; static int start_lockid = 0; static int shared_var = 0; static int no_concurrency = 0; int no_lock = 0; /* Switch on for no locking - should break */ /* * 10 threads and 1000 loops should produce a non-zero result * in the test if locking is disabled via -no_lock */ int thread_number = 3; int number_of_loops = 3; int main(int argc, char *argv[]) { R_LIB_CTX *lib_ctx = NULL; int ret = R_ERROR_FAILED; int badop = 0; int trace = 0; int stats = 0; #ifdef NO_SOFTWARE_CRYPTO R_FIPS140_OPERATING_MODE_T operating_mode = PRODUCT_FIPS140_MODE_DEFAULT; #endif /* NO_SOFTWARE_CRYPTO */ bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); bio_out = BIO_new_fp(stdout, BIO_NOCLOSE); BIO_set_flags(bio_err, BIO_FLAGS_FLUSH_ON_WRITE); BIO_set_flags(bio_out, BIO_FLAGS_FLUSH_ON_WRITE); argc--; argv++; while (argc >= 1) { if (Strcmp(*argv, "-trace") == 0) { trace = 1; } else if (Strcmp(*argv, "-no_lock") == 0) { no_lock = 1; } else if (Strcmp(*argv, "-stats") == 0) { stats = 1; } #ifdef NO_SOFTWARE_CRYPTO else if (Strcmp(*argv, "-no_fips140") == 0) { operating_mode = NON_FIPS140_MODE; } else if (Strcmp(*argv, "-fips140_ssl") == 0) { operating_mode = FIPS140_SSL_MODE; } #endif /* NO_SOFTWARE_CRYPTO */ else if (Strcmp(*argv, "-threads") == 0) { if (--argc < 1) { goto bad; } thread_number = atoi(*(++argv)); if (thread_number == 0) { thread_number = 1; } if (thread_number > MAX_THREAD_NUMBER) { thread_number = MAX_THREAD_NUMBER; } } else if (Strcmp(*argv, "-loops") == 0) { if (--argc < 1) { goto bad; } number_of_loops = atoi(*(++argv)); if (number_of_loops == 0) { number_of_loops = 1; } } else { BIO_printf(bio_err, "Unknown option %s\n", *argv); badop = 1; break; } argc--; argv++; } if (badop) { bad: BIO_printf(bio_err, "Usage: thread [-trace] [-no_lock] [-stats] [-loops N] [-threads N]\n"); #ifdef NO_SOFTWARE_CRYPTO BIO_printf(bio_err, " [-no_fips140] [-fips140_ssl]\n"); #endif /* NO_SOFTWARE_CRYPTO */ goto end; } /* * Create the library context. Retrieve the default resource list and * create a library context to provide access to all configurable aspects * of the library. */ #ifdef NO_SOFTWARE_CRYPTO /* * For FIPS140 shared library builds set the operating mode required * first */ switch (operating_mode) { #ifdef PRODUCT_FIPS140_ENABLE_FIPS140_OPERATING_MODE case FIPS140_MODE: PRODUCT_FIPS140_ENABLE_FIPS140_OPERATING_MODE(); break; #endif case NON_FIPS140_MODE: PRODUCT_FIPS140_ENABLE_NON_FIPS140_OPERATING_MODE(); break; case FIPS140_SSL_MODE: PRODUCT_FIPS140_ENABLE_FIPS140_SSL_OPERATING_MODE(); break; } #endif /* NO_SOFTWARE_CRYPTO */ /* Perform the standard library initialization */ if (PRODUCT_LIBRARY_NEW(PRODUCT_DEFAULT_RESOURCE_LIST(), R_RES_FLAG_DEF, &lib_ctx) != R_ERROR_NONE) { BIO_printf(bio_err, "ERROR: unable to create library context\n"); goto end; } /* * Activate thread tracing. Trace the activities of the threads to view * when threads start and stop. */ /* * The APP* routines are in the relevant OS-specific included files * located in ../cb/mt_{thread_api_name}.c */ APP_thread_trace(trace); /* Reserve a lock identifier from the library for local use */ /* Register a new lock with the library for local use */ app_lockid = R_lockid_new("applock"); start_lockid = R_lockid_new("startlock"); if ((app_lockid <= 0) || (start_lockid <= 0)) { BIO_printf(bio_err, "Unable to retrieve a lockid\n"); goto end; } BIO_printf(bio_out, "app_lockid = %ld\n", app_lockid); BIO_printf(bio_out, "start_lockid = %ld\n", start_lockid); /* * Register the locking callbacks. This involves initializing all the * locks. R_lock_num() returns the number of locks required, including the * locally added lock. */ /* Register the callbacks to use to perform locking */ APP_locking_cb_add(); /* * Execute the threads. Ensure the threads have not been initialized and * then create all the new threads. Wait for the last thread to finish and * then show the thread statistics to view the thread usage. */ /* Start the threads */ if (APP_thread_initialize(thread_number)) { int i; R_lock_w(start_lockid); for (i = 0; i < thread_number; i++) { APP_thread_create((void (*)(void *)) app_thread_main, (void *) NULL, NULL); } R_unlock_w(start_lockid); /* Wait for all the threads to finish */ APP_thread_finalize(thread_number); } if (stats) { APP_thread_show_stats(); } /* * Check the state of the shared resources. The resources should be zero to * indicate that the locking in each thread worked correctly. */ if (no_concurrency) goto end; BIO_printf(bio_out, "shared_var: %d - %s\n", shared_var, shared_var == (number_of_loops*thread_number) ? "OK" : "ERROR"); if (shared_var == (number_of_loops*thread_number)) { ret = R_ERROR_NONE; } end: /* * Clean up. Destroy the dynamically allocated objects and return an exit * code. */ APP_locking_cb_delete(); if (bio_err != NULL) { BIO_free(bio_err); } if (bio_out != NULL) { BIO_free(bio_out); } if (lib_ctx != NULL) { PRODUCT_LIBRARY_FREE(lib_ctx); } return(R_ERROR_EXIT_CODE(ret)); } void app_thread_main(void *arg) { int i; int value; /* * If the threading code is working, all threads will be kicked off and hit * this point very quickly. Since each thread then sleeps for at least 1 * second, all of them should see a shared_var value of 0 at this point. * If they do not, it is because the threads are not running concurrently. */ if (shared_var != 0) { BIO_printf(bio_out, "Thread is not concurrent\n"); no_concurrency=1; return; } /* * Try to get a read lock, so everyone starts at the same time. * This will deadlock if the threads are not concurrent. */ R_lock_r(start_lockid); R_unlock_r(start_lockid); BIO_printf(bio_out, "thread start %ld\n", R_thread_id()); for (i = 0; i < number_of_loops; i++) { /* * Retrieve the local lock and use it to indicate that data is about to * be updated */ if (!no_lock) { R_lock_w(app_lockid); } /* Perform the update on the shared resource */ value=shared_var+1; /* * Make a system call to increase the chances of the thread being * swapped out for another. Note this is the system call that must be * protected. */ /* * Sleep here to increase the chance of another thread being executed */ R_sleep(1); /* Undo the update on the shared resource */ shared_var=value; /* * Release the local lock to indicate that the data has finished being * updated */ if (!no_lock) { R_unlock_w(app_lockid); } } /* Signal the end of the current thread */ BIO_printf(bio_out, "thread exit %ld\n", R_thread_id()); }