From b4dc1a71c928fdc0ec885ed5745b0d17b094ff7e Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Thu, 31 Jan 2008 19:23:02 +0200 Subject: [PATCH] Added SILC Rand API, SILC Global Variables API and silcruntime.h.in The SILC Rand API provides simple PRNG. The PRNG implementation uses the Mersenne Twister PRNG. Added test program for it too. The SILC Global Variables API provides portable way to add process global or thread global variables. On some platforms global variables cannot be directly used and this API provides portable way to use them. Added support for Unix, Windows and Symbian. Added test program too. Other changes include the addition of silcruntime.h.in the main SILC Runtime Toolkit header file. Added also silc_hash_destructor, a generic destructor callback for convenience. --- TODO | 14 +- lib/silcutil/Makefile.ad | 8 +- lib/silcutil/silcglobal.c | 172 +++++++++++++++++ lib/silcutil/silcglobal.h | 138 ++++++++++++++ lib/silcutil/silchashtable.c | 8 + lib/silcutil/silchashtable.h | 105 ++++++----- lib/silcutil/silcrand.c | 149 +++++++++++++++ lib/silcutil/silcrand.h | 87 +++++++++ lib/silcutil/silcruntime.h.in | 209 +++++++++++++++++++++ lib/silcutil/silcthread.c | 4 + lib/silcutil/silcthread_i.h | 13 +- lib/silcutil/symbian/silcsymbianthread.cpp | 60 +++++- lib/silcutil/tests/Makefile.am | 6 +- lib/silcutil/tests/test_silcglobal.c | 121 ++++++++++++ lib/silcutil/tests/test_silcrand.c | 55 ++++++ lib/silcutil/unix/silcunixthread.c | 83 +++++++- lib/silcutil/win32/silcwin32thread.c | 86 ++++++++- 17 files changed, 1251 insertions(+), 67 deletions(-) create mode 100644 lib/silcutil/silcglobal.c create mode 100644 lib/silcutil/silcglobal.h create mode 100644 lib/silcutil/silcrand.c create mode 100644 lib/silcutil/silcrand.h create mode 100644 lib/silcutil/silcruntime.h.in create mode 100644 lib/silcutil/tests/test_silcglobal.c create mode 100644 lib/silcutil/tests/test_silcrand.c diff --git a/TODO b/TODO index 4a432c67..ac3b6ac2 100644 --- a/TODO +++ b/TODO @@ -41,12 +41,18 @@ General Runtime library, lib/silcutil/ ============================== - o Simple SILC Rand API for pseudo-random numbers. use SILC Crypto - Toolkit for really good random numbers. + o Unix socket support to Socket Stream API (local socket stream). - o file removing, chmod, rmmod, etc. chdir, rmdir etc. to + o Simple SILC Rand API for pseudo-random numbers. (***DONE) + + o file removing, chmod, rmmod, etc. chdir, rmdir, stat, etc. to lib/silcutil/silcfileutil.h. + o mmap API + + o silc_file_readfile and silc_file_writefile should perhaps do the thing + with mmap, as it's probably a bit faster. + o silc_malloc et. al. to respect --with-alignment. o Fix universal time decoding (doesn't accept all formats) in silctime.c. @@ -155,8 +161,6 @@ Runtime library, lib/silcutil/ (o Fast mutex implementation. Fast rwlock implementation. Mutex and rwlock implementation using atomic operations.) not for now. - (o mmap) maybe - lib/silcutil/symbian/ ===================== diff --git a/lib/silcutil/Makefile.ad b/lib/silcutil/Makefile.ad index 3456e38d..b1ce5fd0 100644 --- a/lib/silcutil/Makefile.ad +++ b/lib/silcutil/Makefile.ad @@ -66,7 +66,9 @@ libsilcutil_la_SOURCES = \ silcerrno.c \ silcgetopt.c \ silcregex.c \ - silcthreadqueue.c + silcthreadqueue.c \ + silcrand.c \ + silcglobal.c include_HEADERS = \ $(SILC_DIST_HEADER) \ @@ -117,7 +119,9 @@ include_HEADERS = \ silcerrno.h \ silcgetopt.h \ silcregex.h \ - silcthreadqueue.h + silcthreadqueue.h \ + silcrand.h \ + silcglobal.h SILC_EXTRA_DIST = diff --git a/lib/silcutil/silcglobal.c b/lib/silcutil/silcglobal.c new file mode 100644 index 00000000..eae95cee --- /dev/null +++ b/lib/silcutil/silcglobal.c @@ -0,0 +1,172 @@ +/* + + silcglobal.c + + Author: Pekka Riikonen + + Copyright (C) 2008 Pekka Riikonen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*/ + +#include "silcruntime.h" + +/****************************** Global Storage ******************************/ + +/* Set global variable */ + +void *silc_global_set_var(const char *name, SilcUInt32 variable_size, + void *initial_value, SilcBool in_tls) +{ + SilcTls tls = silc_thread_get_tls(); + SilcBool ret; + char *var_name; + void *var; + + SILC_LOG_DEBUG(("Adding %s variable '%s' of %d bytes", + in_tls ? "Tls" : "global", name, variable_size)); + + if (!variable_size) { + silc_set_errno(SILC_ERR_INVALID_ARGUMENT); + return NULL; + } + + if (!tls) { + /* Initialize Tls for this thread */ + tls = silc_thread_tls_init(); + if (!tls) + return NULL; + } + + if (!in_tls) { + if (!tls->variables) { + tls->variables = silc_hash_table_alloc(NULL, 0, + silc_hash_string, NULL, + silc_hash_string_compare, NULL, + silc_hash_destructor, NULL, + TRUE); + if (!tls->variables) + return NULL; + } + } else { + if (!tls->tls_variables) { + tls->tls_variables = silc_hash_table_alloc(NULL, 0, + silc_hash_string, NULL, + silc_hash_string_compare, NULL, + silc_hash_destructor, NULL, + TRUE); + if (!tls->tls_variables) + return NULL; + } + } + + /* Allocate the variable */ + var = silc_malloc(variable_size); + if (!var) + return NULL; + + /* Initialize the variable */ + if (initial_value) + memcpy(var, initial_value, variable_size); + else + memset(var, 0, variable_size); + + var_name = silc_strdup(name); + if (!var_name) { + silc_free(var); + return NULL; + } + + /* Add the variable */ + if (!in_tls) { + silc_mutex_lock(tls->lock); + ret = silc_hash_table_set(tls->variables, var_name, var); + silc_mutex_unlock(tls->lock); + } else { + ret = silc_hash_table_set(tls->tls_variables, var_name, var); + } + + if (!ret) { + silc_free(var); + silc_free(var_name); + var = NULL; + } + + return var; +} + +/* Get global variable */ + +void *silc_global_get_var(const char *name, SilcBool in_tls) +{ + SilcTls tls = silc_thread_get_tls(); + void *variable; + SilcBool ret; + + SILC_LOG_DEBUG(("Find %s variable named '%s'", in_tls ? "Tls" : "global", + name)); + + if (!tls) { + silc_set_errno(SILC_ERR_NOT_FOUND); + return NULL; + } + + if (!in_tls && !tls->variables) { + silc_set_errno(SILC_ERR_NOT_FOUND); + return NULL; + } + + if (in_tls && !tls->tls_variables) { + silc_set_errno(SILC_ERR_NOT_FOUND); + return NULL; + } + + if (!in_tls) { + silc_mutex_lock(tls->lock); + ret = silc_hash_table_find(tls->variables, (void *)name, NULL, &variable); + silc_mutex_unlock(tls->lock); + } else { + ret = silc_hash_table_find(tls->tls_variables, (void *)name, NULL, + &variable); + } + + if (!ret) + return NULL; + + return variable; +} + +/* Delete global variable */ + +SilcBool silc_global_del_var(const char *name, SilcBool in_tls) +{ + SilcTls tls = silc_thread_get_tls(); + + SILC_LOG_DEBUG(("Delete %s variable '%s'", in_tls ? "Tls" : "global", name)); + + if (!tls) { + silc_set_errno(SILC_ERR_NOT_FOUND); + return FALSE; + } + + if (!in_tls && !tls->variables) { + silc_set_errno(SILC_ERR_NOT_FOUND); + return FALSE; + } + + if (in_tls && !tls->tls_variables) { + silc_set_errno(SILC_ERR_NOT_FOUND); + return FALSE; + } + + return silc_hash_table_del(in_tls ? tls->tls_variables : tls->variables, + (void *)name); +} diff --git a/lib/silcutil/silcglobal.h b/lib/silcutil/silcglobal.h new file mode 100644 index 00000000..4895af5f --- /dev/null +++ b/lib/silcutil/silcglobal.h @@ -0,0 +1,138 @@ +/* + + silcglobal.h + + Author: Pekka Riikonen + + Copyright (C) 2008 Pekka Riikonen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*/ + +/****h* silcutil/Global Variable Interface + * + * DESCRIPTION + * + * The Global Variable API can be used to set variables as global in the + * process or in current thread. On some platforms, like Symbian, global + * variables cannot be used directly. This API can be used to write + * portable code that can use global variables on all supported platforms. + * + * EXAMPLE + * + * // Initialize global buffer + * unsigned char buffer[256]; + * silc_global_set_va("somebuf", sizeof(buffer), NULL, FALSE); + * + * // Retrieve the buffer + * unsigned char *buf = silc_global_get_var("somebuf", FALSE); + * + * // Set integer and its value global in the current thread + * SilcUInt32 integer = 100; + * silc_global_set_var("someint", 4, &integer, TRUE); + * + * // Retrieve the integer and change its value + * SilcUInt32 *intptr = silc_global_get_var("someint", TRUE); + * *intptr = 200; + * + ***/ + +#ifndef SILCGLOBAL_H +#define SILCGLOBAL_H + +/****f* silcutil/silc_global_set_var + * + * SYNOPSIS + * + * void *silc_global_set_var(const char *name, SilcUInt32 variable_size, + * void *initial_value, SilcBool tls); + * + * DESCRIPTION + * + * Sets a variable of size of `variable_size' bytes as a global variable + * under the name of `name'. If `initial_value' is non-NULL it is + * considered to be the initial value of the stored variable. If it is + * NULL this will initialize the variable as all zeroes. + * + * If variable with `name' already exists it will be replaced with the + * `initial_value' or as all zeroes, and the old pointer will become + * invalid. + * + * If `tls' is FALSE the variable is visible to all threads in the process. + * If it is TRUE the variable is visible only in the current thread. The + * variable can be retrieved using the same name by calling the + * silc_thread_global_get_var. + * + * Returns NULL and sets silc_errno if the variable could not be added, or + * a pointer to the added variable otherwise. + * + * EXAMPLE + * + * // Initialize global buffer + * unsigned char buffer[256]; + * silc_global_set_va("somebuf", sizeof(buffer), NULL, FALSE); + * + * // Retrieve the buffer + * unsigned char *buf = silc_global_get_var("somebuf", FALSE); + * + * // Set integer global + * SilcUInt32 integer = 100; + * silc_global_set_var("someint", 4, &integer, FALSE); + * + * // Retrieve the integer and change its value + * SilcUInt32 *intptr = silc_global_get_var("someint", FALSE); + * *intptr = 200; + * + * // Set structure as global in the thread + * silc_global_set_va("somestruct", sizeof(*context), NULL, TRUE); + * + * // Retrieve the context + * context = silc_global_get_var("somestruct", TRUE); + * + ***/ +void *silc_global_set_var(const char *name, SilcUInt32 variable_size, + void *initial_value, SilcBool tls); + +/****f* silcutil/silc_global_get_var + * + * SYNOPSIS + * + * void *silc_global_get_var(const char *name, SilcBool tls); + * + * DESCRIPTION + * + * Returns the variable from the global variable storage that has been + * stored under the name `name'. If `tls' is FALSE this fetches the + * variable from global storage, if it is TRUE it is fetched from the + * Thread-local storage. Returns NULL if such variable does not exist + * and sets silc_errno. + * + ***/ +void *silc_global_get_var(const char *name, SilcBool tls); + +/****f* silcutil/silc_global_del_var + * + * SYNOPSIS + * + * SilcBool silc_global_del_var(const char *name, SilcBool tls); + * + * DESCRIPTION + * + * Deletes the global variable named `name'. Returns TRUE if it was + * deleted, FALSE if such variable does not exist and sets silc_errno. + * + * If variable is not deleted before the process or thread is destroyed + * it will be deleted and freed automatically. + * + ***/ +SilcBool silc_global_del_var(const char *name, SilcBool tls); + +#endif /* SILCGLOBAL_H */ diff --git a/lib/silcutil/silchashtable.c b/lib/silcutil/silchashtable.c index f440be49..7c3d7cbf 100644 --- a/lib/silcutil/silchashtable.c +++ b/lib/silcutil/silchashtable.c @@ -1119,3 +1119,11 @@ SilcBool silc_hash_utf8_compare(void *key1, void *key2, void *user_context) return FALSE; return !memcmp(key1, key2, l2); } + +/* Generic destructor */ + +void silc_hash_destructor(void *key, void *context, void *user_context) +{ + silc_free(key); + silc_free(context); +} diff --git a/lib/silcutil/silchashtable.h b/lib/silcutil/silchashtable.h index 966ffc46..624d18a4 100644 --- a/lib/silcutil/silchashtable.h +++ b/lib/silcutil/silchashtable.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2001 - 2007 Pekka Riikonen + Copyright (C) 2001 - 2008 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,7 +17,7 @@ */ -/****h* silcutil/SILC Hash Table Interface +/****h* silcutil/Hash Table Interface * * DESCRIPTION * @@ -30,7 +30,7 @@ * table. * * The interface provides many ways to search the hash table including - * an extended interface where caller can specify its own hash and comparison + * an extended interface where caller can specify their own hash and comparison * functions. The interface also supports SilcStack and all memory allocated * by the hash table can be allocated from SilcStack. * @@ -40,6 +40,9 @@ * SilcHashTableList structure and traverse the hash table inside while() * using the list structure. Both are equally fast. * + * The interface also provides many utility hashing and comparison functions + * that caller may use with SilcHashTable. + * * The hash table is not thread safe. If same SilcHashtable context is used * in multi thread environment concurrency control must be employed. * @@ -48,7 +51,7 @@ #ifndef SILCHASHTABLE_H #define SILCHASHTABLE_H -/****s* silcutil/SilcHashTableAPI/SilcHashTable +/****s* silcutil/SilcHashTable * * NAME * @@ -64,7 +67,7 @@ ***/ typedef struct SilcHashTableStruct *SilcHashTable; -/****s* silcutil/SilcHashTableAPI/SilcHashTableList +/****s* silcutil/SilcHashTableList * * NAME * @@ -98,7 +101,7 @@ struct SilcHashTableListStruct { }; /***/ -/****f* silcutil/SilcHashTableAPI/SilcHashFunction +/****f* silcutil/SilcHashFunction * * SYNOPSIS * @@ -114,7 +117,7 @@ struct SilcHashTableListStruct { ***/ typedef SilcUInt32 (*SilcHashFunction)(void *key, void *user_context); -/****f* silcutil/SilcHashTableAPI/SilcHashCompare +/****f* silcutil/SilcHashCompare * * SYNOPSIS * @@ -133,7 +136,7 @@ typedef SilcUInt32 (*SilcHashFunction)(void *key, void *user_context); typedef SilcBool (*SilcHashCompare)(void *key1, void *key2, void *user_context); -/****f* silcutil/SilcHashTableAPI/SilcHashDestructor +/****f* silcutil/SilcHashDestructor * * SYNOPSIS * @@ -151,7 +154,7 @@ typedef SilcBool (*SilcHashCompare)(void *key1, void *key2, typedef void (*SilcHashDestructor)(void *key, void *context, void *user_context); -/****f* silcutil/SilcHashTableAPI/SilcHashForeach +/****f* silcutil/SilcHashForeach * * SYNOPSIS * @@ -169,7 +172,7 @@ typedef void (*SilcHashForeach)(void *key, void *context, void *user_context); /* Simple hash table interface */ -/****f* silcutil/SilcHashTableAPI/silc_hash_table_alloc +/****f* silcutil/silc_hash_table_alloc * * SYNOPSIS * @@ -205,7 +208,7 @@ SilcHashTable silc_hash_table_alloc(SilcStack stack, void *destructor_user_context, SilcBool auto_rehash); -/****f* silcutil/SilcHashTableAPI/silc_hash_table_free +/****f* silcutil/silc_hash_table_free * * SYNOPSIS * @@ -223,7 +226,7 @@ SilcHashTable silc_hash_table_alloc(SilcStack stack, ***/ void silc_hash_table_free(SilcHashTable ht); -/****f* silcutil/SilcHashTableAPI/silc_hash_table_size +/****f* silcutil/silc_hash_table_size * * SYNOPSIS * @@ -237,7 +240,7 @@ void silc_hash_table_free(SilcHashTable ht); ***/ SilcUInt32 silc_hash_table_size(SilcHashTable ht); -/****f* silcutil/SilcHashTableAPI/silc_hash_table_count +/****f* silcutil/silc_hash_table_count * * SYNOPSIS * @@ -252,7 +255,7 @@ SilcUInt32 silc_hash_table_size(SilcHashTable ht); ***/ SilcUInt32 silc_hash_table_count(SilcHashTable ht); -/****f* silcutil/SilcHashTableAPI/silc_hash_table_add +/****f* silcutil/silc_hash_table_add * * SYNOPSIS * @@ -268,7 +271,7 @@ SilcUInt32 silc_hash_table_count(SilcHashTable ht); ***/ SilcBool silc_hash_table_add(SilcHashTable ht, void *key, void *context); -/****f* silcutil/SilcHashTableAPI/silc_hash_table_set +/****f* silcutil/silc_hash_table_set * * SYNOPSIS * @@ -285,7 +288,7 @@ SilcBool silc_hash_table_add(SilcHashTable ht, void *key, void *context); ***/ SilcBool silc_hash_table_set(SilcHashTable ht, void *key, void *context); -/****f* silcutil/SilcHashTableAPI/silc_hash_table_del +/****f* silcutil/silc_hash_table_del * * SYNOPSIS * @@ -300,7 +303,7 @@ SilcBool silc_hash_table_set(SilcHashTable ht, void *key, void *context); ***/ SilcBool silc_hash_table_del(SilcHashTable ht, void *key); -/****f* silcutil/SilcHashTableAPI/silc_hash_table_del_by_context +/****f* silcutil/silc_hash_table_del_by_context * * SYNOPSIS * @@ -318,7 +321,7 @@ SilcBool silc_hash_table_del(SilcHashTable ht, void *key); SilcBool silc_hash_table_del_by_context(SilcHashTable ht, void *key, void *context); -/****f* silcutil/SilcHashTableAPI/silc_hash_table_find +/****f* silcutil/silc_hash_table_find * * SYNOPSIS * @@ -337,7 +340,7 @@ SilcBool silc_hash_table_del_by_context(SilcHashTable ht, void *key, SilcBool silc_hash_table_find(SilcHashTable ht, void *key, void **ret_key, void **ret_context); -/****f* silcutil/SilcHashTableAPI/silc_hash_table_find_by_context +/****f* silcutil/silc_hash_table_find_by_context * * SYNOPSIS * @@ -358,7 +361,7 @@ SilcBool silc_hash_table_find(SilcHashTable ht, void *key, SilcBool silc_hash_table_find_by_context(SilcHashTable ht, void *key, void *context, void **ret_key); -/****f* silcutil/SilcHashTableAPI/silc_hash_table_find_foreach +/****f* silcutil/silc_hash_table_find_foreach * * SYNOPSIS * @@ -385,7 +388,7 @@ SilcBool silc_hash_table_find_by_context(SilcHashTable ht, void *key, void silc_hash_table_find_foreach(SilcHashTable ht, void *key, SilcHashForeach foreach, void *user_context); -/****f* silcutil/SilcHashTableAPI/silc_hash_table_foreach +/****f* silcutil/silc_hash_table_foreach * * SYNOPSIS * @@ -407,7 +410,7 @@ void silc_hash_table_find_foreach(SilcHashTable ht, void *key, void silc_hash_table_foreach(SilcHashTable ht, SilcHashForeach foreach, void *user_context); -/****f* silcutil/SilcHashTableAPI/silc_hash_table_rehash +/****f* silcutil/silc_hash_table_rehash * * SYNOPSIS * @@ -423,7 +426,7 @@ void silc_hash_table_foreach(SilcHashTable ht, SilcHashForeach foreach, ***/ void silc_hash_table_rehash(SilcHashTable ht, SilcUInt32 new_size); -/****f* silcutil/SilcHashTableAPI/silc_hash_table_list +/****f* silcutil/silc_hash_table_list * * SYNOPSIS * @@ -445,7 +448,7 @@ void silc_hash_table_rehash(SilcHashTable ht, SilcUInt32 new_size); ***/ void silc_hash_table_list(SilcHashTable ht, SilcHashTableList *htl); -/****f* silcutil/SilcHashTableAPI/silc_hash_table_list_reset +/****f* silcutil/silc_hash_table_list_reset * * SYNOPSIS * @@ -459,7 +462,7 @@ void silc_hash_table_list(SilcHashTable ht, SilcHashTableList *htl); ***/ void silc_hash_table_list_reset(SilcHashTableList *htl); -/****f* silcutil/SilcHashTableAPI/silc_hash_table_get +/****f* silcutil/silc_hash_table_get * * SYNOPSIS * @@ -488,7 +491,7 @@ SilcBool silc_hash_table_get(SilcHashTableList *htl, /* Extended hash table interface (same as above but with specific hash and comparison functions). */ -/****f* silcutil/SilcHashTableAPI/silc_hash_table_add_ext +/****f* silcutil/silc_hash_table_add_ext * * SYNOPSIS * @@ -513,7 +516,7 @@ SilcBool silc_hash_table_add_ext(SilcHashTable ht, SilcHashFunction hash, void *hash_user_context); -/****f* silcutil/SilcHashTableAPI/silc_hash_table_set_ext +/****f* silcutil/silc_hash_table_set_ext * * SYNOPSIS * @@ -538,7 +541,7 @@ SilcBool silc_hash_table_set_ext(SilcHashTable ht, SilcHashFunction hash, void *hash_user_context); -/****f* silcutil/SilcHashTableAPI/silc_hash_table_del_ext +/****f* silcutil/silc_hash_table_del_ext * * SYNOPSIS * @@ -572,7 +575,7 @@ SilcBool silc_hash_table_del_ext(SilcHashTable ht, void *key, SilcHashDestructor destructor, void *destructor_user_context); -/****f* silcutil/SilcHashTableAPI/silc_hash_table_del_by_context_ext +/****f* silcutil/silc_hash_table_del_by_context_ext * * SYNOPSIS * @@ -610,7 +613,7 @@ SilcBool silc_hash_table_del_by_context_ext(SilcHashTable ht, void *key, SilcHashDestructor destructor, void *destructor_user_context); -/****f* silcutil/SilcHashTableAPI/silc_hash_table_find_ext +/****f* silcutil/silc_hash_table_find_ext * * SYNOPSIS * @@ -642,7 +645,7 @@ SilcBool silc_hash_table_find_ext(SilcHashTable ht, void *key, SilcHashCompare compare, void *compare_user_context); -/****f* silcutil/SilcHashTableAPI/silc_hash_table_find_by_context_ext +/****f* silcutil/silc_hash_table_find_by_context_ext * * SYNOPSIS * @@ -677,7 +680,7 @@ SilcBool silc_hash_table_find_by_context_ext(SilcHashTable ht, void *key, SilcHashCompare compare, void *compare_user_context); -/****f* silcutil/SilcHashTableAPI/silc_hash_table_find_foreach_ext +/****f* silcutil/silc_hash_table_find_foreach_ext * * SYNOPSIS * @@ -718,7 +721,7 @@ void silc_hash_table_find_foreach_ext(SilcHashTable ht, void *key, SilcHashForeach foreach, void *foreach_user_context); -/****f* silcutil/SilcHashTableAPI/silc_hash_table_rehash_ext +/****f* silcutil/silc_hash_table_rehash_ext * * SYNOPSIS * @@ -743,7 +746,7 @@ void silc_hash_table_rehash_ext(SilcHashTable ht, SilcUInt32 new_size, /* Hash functions */ -/****f* silcutil/SilcHashTableAPI/silc_hash_string +/****f* silcutil/silc_hash_string * * SYNOPSIS * @@ -758,7 +761,7 @@ void silc_hash_table_rehash_ext(SilcHashTable ht, SilcUInt32 new_size, ***/ SilcUInt32 silc_hash_string(void *key, void *user_context); -/****f* silcutil/SilcHashTableAPI/silc_hash_string_case +/****f* silcutil/silc_hash_string_case * * SYNOPSIS * @@ -774,7 +777,7 @@ SilcUInt32 silc_hash_string(void *key, void *user_context); ***/ SilcUInt32 silc_hash_string_case(void *key, void *user_context); -/****f* silcutil/SilcHashTableAPI/silc_hash_utf8_string +/****f* silcutil/silc_hash_utf8_string * * SYNOPSIS * @@ -789,7 +792,7 @@ SilcUInt32 silc_hash_string_case(void *key, void *user_context); ***/ SilcUInt32 silc_hash_utf8_string(void *key, void *user_context); -/****f* silcutil/SilcHashTableAPI/silc_hash_uint +/****f* silcutil/silc_hash_uint * * SYNOPSIS * @@ -804,7 +807,7 @@ SilcUInt32 silc_hash_utf8_string(void *key, void *user_context); ***/ SilcUInt32 silc_hash_uint(void *key, void *user_context); -/****f* silcutil/SilcHashTableAPI/silc_hash_ptr +/****f* silcutil/silc_hash_ptr * * SYNOPSIS * @@ -819,7 +822,7 @@ SilcUInt32 silc_hash_uint(void *key, void *user_context); ***/ SilcUInt32 silc_hash_ptr(void *key, void *user_context); -/****f* silcutil/SilcHashTableAPI/silc_hash_data +/****f* silcutil/silc_hash_data * * SYNOPSIS * @@ -835,7 +838,7 @@ SilcUInt32 silc_hash_data(void *key, void *user_context); /* Comparison functions */ -/****f* silcutil/SilcHashTableAPI/silc_hash_string_compare +/****f* silcutil/silc_hash_string_compare * * SYNOPSIS * @@ -850,7 +853,7 @@ SilcUInt32 silc_hash_data(void *key, void *user_context); ***/ SilcBool silc_hash_string_compare(void *key1, void *key2, void *user_context); -/****f* silcutil/SilcHashTableAPI/silc_hash_string_case_compare +/****f* silcutil/silc_hash_string_case_compare * * SYNOPSIS * @@ -866,7 +869,7 @@ SilcBool silc_hash_string_compare(void *key1, void *key2, void *user_context); SilcBool silc_hash_string_case_compare(void *key1, void *key2, void *user_context); -/****f* silcutil/SilcHashTableAPI/silc_hash_utf8_compare +/****f* silcutil/silc_hash_utf8_compare * * SYNOPSIS * @@ -881,7 +884,7 @@ SilcBool silc_hash_string_case_compare(void *key1, void *key2, ***/ SilcBool silc_hash_utf8_compare(void *key1, void *key2, void *user_context); -/****f* silcutil/SilcHashTableAPI/silc_hash_data_compare +/****f* silcutil/silc_hash_data_compare * * SYNOPSIS * @@ -895,4 +898,20 @@ SilcBool silc_hash_utf8_compare(void *key1, void *key2, void *user_context); ***/ SilcBool silc_hash_data_compare(void *key1, void *key2, void *user_context); +/* Destructor functions */ + +/****f* silcutil/silc_hash_destructor + * + * SYNOPSIS + * + * void silc_hash_destructor(void *key, void *context, void *user_context); + * + * DESCRIPTION + * + * A generic destructor for SilcHashTable. This will call silc_free for + * `key' and `context'. + * + ***/ +void silc_hash_destructor(void *key, void *context, void *user_context); + #endif diff --git a/lib/silcutil/silcrand.c b/lib/silcutil/silcrand.c new file mode 100644 index 00000000..10dcc2cd --- /dev/null +++ b/lib/silcutil/silcrand.c @@ -0,0 +1,149 @@ +/* + + silcrand.c + + Author: Pekka Riikonen + + Copyright (C) 2008 Pekka Riikonen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*/ + +#include "silcruntime.h" + +/************************* Types and definitions ****************************/ + +/* Random number state context size */ +#define SILC_RAND_STATE_SIZE 624 +#define SILC_RAND_STATE_FULL_SIZE ((SILC_RAND_STATE_SIZE + 1) * \ + sizeof(SilcUInt32)) + +/* State position offset */ +#define SILC_RAND_STATE_POS (SILC_RAND_STATE_SIZE + 1) - 1 + +/************************ Static utility functions **************************/ + +/* Refresh the state */ + +void silc_rand_refresh(SilcUInt32 *rs) +{ + SilcUInt32 i, c; + + for (i = 0; i < SILC_RAND_STATE_SIZE - 1; i++) { + c = (rs[i] & 0x80000000UL) | (rs[i + 1] & 0x7fffffffUL); + if (c & 1) + rs[i] = rs[(i + 397) % SILC_RAND_STATE_SIZE] ^ (c >> 1) ^ 0x9908b0dfUL; + else + rs[i] = rs[(i + 397) % SILC_RAND_STATE_SIZE] ^ (c >> 1); + } + + c = (rs[i] & 0x80000000UL) | (rs[0] & 0x7fffffffUL); + if (c & 1) + rs[i] = rs[(i + 397) % SILC_RAND_STATE_SIZE] ^ (c >> 1) ^ 0x9908b0dfUL; + else + rs[i] = rs[(i + 397) % SILC_RAND_STATE_SIZE] ^ (c >> 1); + + rs[SILC_RAND_STATE_POS] = 0; +} + +/* Seed */ + +static void silc_rand_seed_state(SilcUInt32 *rs, SilcUInt32 seed) +{ + SilcUInt32 c, i; + + rs[0] = seed; + for (i = 1; i < SILC_RAND_STATE_SIZE; i++) { + c = rs[i - 1]; + rs[i] = (1812433253UL * ((c ^ (c >> 30)) + 1)); + } + + silc_rand_refresh(rs); +} + +/* Return random state or create it. */ + +static SilcUInt32 *silc_rand_state(SilcBool seed) +{ + SilcUInt32 *rs; + + rs = silc_global_get_var("srtrs", TRUE); + if (!rs) { + rs = silc_global_set_var("srtrs", SILC_RAND_STATE_FULL_SIZE, NULL, TRUE); + if (!rs) + return NULL; + + if (seed) + silc_rand_seed_state(rs, (SilcUInt32)silc_time_usec()); + } + + return rs; +} + +/* Temper next position and return the value */ + +SilcUInt32 silc_rand_temper(SilcUInt32 *rs) +{ + SilcUInt32 val; + + /* Refresh if necessary */ + if (++rs[SILC_RAND_STATE_POS] >= SILC_RAND_STATE_SIZE) + silc_rand_refresh(rs); + + /* Temper */ + val = rs[rs[SILC_RAND_STATE_POS]]; + val = val ^ (val >> 11); + val = val ^ ((val << 7) & 0x9d2c5680UL); + val = val ^ ((val << 15) & 0xefc60000UL); + return val ^ (val >> 18); +} + +/******************************* SILC Rand API ******************************/ + +/* Seed the generator */ + +void silc_rand_seed(SilcUInt32 seed) +{ + SilcUInt32 *rs; + + rs = silc_rand_state(FALSE); + if (!rs) + return; + + silc_rand_seed_state(rs, seed); +} + +/* Return 32-bit random number */ + +SilcUInt32 silc_rand(void) +{ + SilcUInt32 *rs; + + rs = silc_rand_state(TRUE); + if (!rs) + return 0x23456789 + (SilcUInt32)silc_time_usec(); + + return silc_rand_temper(rs); +} + +/* Return 64-bit random number */ + +SilcUInt64 silc_rand64(void) +{ + SilcUInt32 *rs; + + rs = silc_rand_state(TRUE); + if (!rs) + return 0x1234567891234567 + silc_time_usec(); + + return (SilcUInt64)(((SilcUInt64)silc_rand_temper(rs) << 32) | + silc_rand_temper(rs)); +} diff --git a/lib/silcutil/silcrand.h b/lib/silcutil/silcrand.h new file mode 100644 index 00000000..6d8abbab --- /dev/null +++ b/lib/silcutil/silcrand.h @@ -0,0 +1,87 @@ +/* + + silcrand.h + + Author: Pekka Riikonen + + Copyright (C) 2008 Pekka Riikonen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*/ + +/****h* silcutil/Random Number Interface + * + * DESCRIPTION + * + * Interface for generating pseudo-random numbers. This random number + * generator must not be used in applications needing cryptographically + * strong random numbers. For that purpose the SILC Crypto Toolkit should + * be used. + * + * The implementation uses Mersenne Twister random number generator. + * + * The SILC Rand API is thread-safe. Each thread can use the API at the + * same time without affecting the random state of other threads. + * + * EXAMPLE + * + * silc_rand_seed(seed); + * printf("Random number: %lu", silc_rand()); + * + ***/ + +#ifndef SILCRAND_H +#define SILCRAND_H + +/****f* silcutil/silc_rand_seed + * + * SYNOPSIS + * + * void silc_rand_seed(SilcUInt32 seed); + * + * DESCRIPTION + * + * Seed the random number generator with the value `seed'. This should + * be called before starting to retrieve random numbers and the `seed' + * itself should be random or non-determinable. It is also wise to reseed + * the random number generator periodically if random numbers are used + * a lot. + * + ***/ +void silc_rand_seed(SilcUInt32 seed); + +/****f* silcutil/silc_rand + * + * SYNOPSIS + * + * SilcUInt32 silc_rand(void); + * + * DESCRIPTION + * + * Returns 32-bit random number. + * + ***/ +SilcUInt32 silc_rand(void); + +/****f* silcutil/silc_rand64 + * + * SYNOPSIS + * + * SilcUInt64 silc_rand64(void) + * + * DESCRIPTION + * + * Returns 64-bit random number. + * + ***/ +SilcUInt64 silc_rand64(void); + +#endif /* SILCRAND_H */ diff --git a/lib/silcutil/silcruntime.h.in b/lib/silcutil/silcruntime.h.in new file mode 100644 index 00000000..9736eed5 --- /dev/null +++ b/lib/silcutil/silcruntime.h.in @@ -0,0 +1,209 @@ +/* + + silcruntime.h + + Author: Pekka Riikonen + + Copyright (C) 2008 Pekka Riikonen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*/ + +#ifndef SILCRUNTIME_H +#define SILCRUNTIME_H + +/* Version check macro. Use this to check that package is of specific + version compile time. Use the __SILC_XXX_VERSION below in comparison. + Example: + + #if __SILC_RUNTIME_VERSION < SILC_VERSION(1,2,0) + ... + #endif +*/ +#ifndef SILC_VERSION +#define SILC_VERSION(a, b, c) (((a) << 24) + ((b) << 16) + ((c) << 8) +#endif /* !SILC_VERSION */ + +/* SILC Runtime Toolkit version */ +@__RUNTIME_PACKAGE_VERSION@ + +/* Compilation time defines, for third-party software. Use these to check + in configuration/compilation time how the SILC Runtime Toolkit was + configured/compiled. */ +@__SILC_HAVE_PTHREAD@ +@__SILC_ENABLE_DEBUG@ + +/* Types */ +#define SILC_SIZEOF_LONG_LONG @SILC_SIZEOF_LONG_LONG@ +#define SILC_SIZEOF_LONG @SILC_SIZEOF_LONG@ +#define SILC_SIZEOF_INT @SILC_SIZEOF_INT@ +#define SILC_SIZEOF_SHORT @SILC_SIZEOF_SHORT@ +#define SILC_SIZEOF_CHAR @SILC_SIZEOF_CHAR@ +#define SILC_SIZEOF_VOID_P @SILC_SIZEOF_VOID_P@ + +/* Detect OS */ +#define SILC_UNIX + +#ifdef WIN32 +#ifndef SILC_WIN32 +#define SILC_WIN32 +#undef SILC_UNIX +#endif +#endif + +#if defined(__EPOC32__) || defined(__SYMBIAN32__) +#ifndef SILC_SYMBIAN +#define SILC_SYMBIAN +#undef SILC_UNIX +#undef SILC_WIN32 +#endif +#endif + +#if defined(__MACH__) && defined(__APPLE__) +#ifndef SILC_MACOSX +#define SILC_MACOSX +#undef SILC_WIN32 +#undef SILC_SYMBIAN +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Platform specific includes */ +#if defined(SILC_WIN32) +#include +#endif + +#if defined(SILC_SYMBIAN) +#include +#endif + +#if defined(HAVE_SILCDEFS_H) + +/* Automatically generated configuration header. These are included only + when the SILC Runtime Toolkit itself is compiled. */ +#ifndef SILC_SYMBIAN +#include "silcdefs.h" +#else +#include "../../symbian/silcdefs.h" +#endif /* SILC_SYMBIAN */ +#include "silcdistdefs.h" +#include "silccompile.h" + +#else + +/* Autodetect CPU so that inline assembly in headers are enabled */ + +#if defined(__i386__) +#undef SILC_I386 +#undef SILC_I486 +#define SILC_I386 +#define SILC_I486 +#endif /* __i386__ */ + +#if defined(__i486__) +#undef SILC_I386 +#undef SILC_I486 +#define SILC_I386 +#define SILC_I486 +#endif /* __i486__ */ + +#if defined(__i586__) +#undef SILC_I386 +#undef SILC_I486 +#undef SILC_I586 +#define SILC_I386 +#define SILC_I486 +#define SILC_I586 +#endif /* __i586__ */ + +#if defined(__i686__) +#undef SILC_I386 +#undef SILC_I486 +#undef SILC_I586 +#undef SILC_I686 +#define SILC_I386 +#define SILC_I486 +#define SILC_I586 +#define SILC_I686 +#endif /* __i686__ */ + +#if defined(__x86_64__) +#undef SILC_X86_64 +#define SILC_X86_64 +#endif /* __x86_64__ */ + +#if defined(__ia64__) +#undef SILC_IA64 +#define SILC_IA64 +#endif /* __ia64__ */ + +#if defined(__ppc__) || defined(__ppc64__) +#undef SILC_POWERPC +#define SILC_POWERPC +#endif /* __ppc__ || __ppc64__ */ + +#ifndef SILC_ALIGNMENT +#define SILC_ALIGNMENT SILC_SIZEOF_VOID_P +#endif /* SILC_ALIGNMENT */ + +#endif /* HAVE_SILCDEFS_H */ + +/* SILC Runtime Toolkit includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +} +#endif + +#endif /* SILCRUNTIME_H */ diff --git a/lib/silcutil/silcthread.c b/lib/silcutil/silcthread.c index aad875a0..c8507034 100644 --- a/lib/silcutil/silcthread.c +++ b/lib/silcutil/silcthread.c @@ -585,6 +585,8 @@ void silc_thread_pool_purge(SilcThreadPool tp) /*************************** Thread-local Storage ***************************/ +/* Set Tls context */ + void silc_thread_tls_set(void *context) { SilcTls tls = silc_thread_get_tls(); @@ -599,6 +601,8 @@ void silc_thread_tls_set(void *context) tls->thread_context = context; } +/* Get Tls context */ + void *silc_thread_tls_get(void) { SilcTls tls = silc_thread_get_tls(); diff --git a/lib/silcutil/silcthread_i.h b/lib/silcutil/silcthread_i.h index d0d2fd73..f7c6697f 100644 --- a/lib/silcutil/silcthread_i.h +++ b/lib/silcutil/silcthread_i.h @@ -29,12 +29,17 @@ with silc_calloc and freeable with silc_free, and must also be able to pre-allocate from stack. */ typedef struct SilcTlsObject { - SilcStack stack; /* Global stack */ - SilcSchedule schedule; /* Global scheduler */ + SilcMutex lock; /* Global lock, shared */ + SilcHashTable variables; /* Global variables, shared */ + SilcHashTable tls_variables; /* Tls variables */ + SilcStack stack; /* Thread's stack */ + SilcSchedule schedule; /* Thread's scheduler */ void *thread_context; /* Context set with SILC Tls API */ void *platform_context; /* Platform specific context */ char error_reason[256]; /* Reason for the error */ SilcResult error; /* Errno, last error */ + unsigned int shared_data : 1; /* Set when shares data with other + threads in the Tls. */ } *SilcTls, SilcTlsStruct; /* The internal Tls API. Implementation is platform specific. */ @@ -46,4 +51,8 @@ SilcTls silc_thread_tls_init(void); /* Return current thread's Tls structure. */ SilcTls silc_thread_get_tls(void); +/* Uninitialize whole Tls system (free shared data), called only once per + process. */ +void silc_thread_tls_uninit(void); + #endif /* SILCTHREAD_I_H */ diff --git a/lib/silcutil/symbian/silcsymbianthread.cpp b/lib/silcutil/symbian/silcsymbianthread.cpp index 05a2e893..4d08efaf 100644 --- a/lib/silcutil/symbian/silcsymbianthread.cpp +++ b/lib/silcutil/symbian/silcsymbianthread.cpp @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2006 - 2007 Pekka Riikonen + Copyright (C) 2006 - 2008 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,10 +17,14 @@ */ -#include "silc.h" +#include "silcruntime.h" #include #include +/************************ Static utility functions **************************/ + +static SilcTls silc_thread_tls_init_shared(SilcTls other); + /**************************** SILC Thread API *******************************/ extern "C" { @@ -31,9 +35,8 @@ struct SilcSymbianThread { SilcThreadStart start_func; void *context; SilcBool waitable; -#else - void *tmp; #endif + SilcTls tls; }; /* The actual thread function */ @@ -45,12 +48,12 @@ static TInt silc_thread_start(TAny *context) SilcThreadStart start_func = tc->start_func; void *user_context = tc->context; SilcBool waitable = tc->waitable; + SilcTls tls, other = tc->tls; void *ret = NULL; - SilcTls tls; silc_free(tc); - tls = silc_thread_tls_init(); + tls = silc_thread_tls_init_shared(other); CTrapCleanup *cs = CTrapCleanup::New(); if (cs) { @@ -66,6 +69,8 @@ static TInt silc_thread_start(TAny *context) delete cs; } + if (tls->tls_variables) + silc_hash_table_free(tls->tls_variables); silc_free(tls); silc_thread_exit(ret); @@ -429,6 +434,31 @@ SilcTls silc_thread_tls_init(void) Dll::SetTls(tls); + /* Allocate global lock */ + silc_mutex_alloc(&tls->lock); + + return tls; +} + +static SilcTls silc_thread_tls_init_shared(SilcTls other) +{ + SilcTls tls; + + if (silc_thread_get_tls()) + return silc_thread_get_tls(); + + /* Allocate Tls for the thread */ + tls = (SilcTls)silc_calloc(1, sizeof(*tls)); + if (!tls) + return NULL; + + Dll::SetTls(tls); + + /* Take shared data */ + tls->shared_data = 1; + tls->lock = other->lock; + tls->variables = other->variables; + return tls; } @@ -437,4 +467,22 @@ SilcTls silc_thread_get_tls(void) return STATIC_CAST(SilcTls, Dll::Tls()); } +void silc_thread_tls_uninit(void) +{ + SilcTls tls = silc_thread_get_tls(); + + if (!tls || tls->shared_data) + return; + + if (tls->tls_variables) + silc_hash_table_free(tls->tls_variables); + if (tls->variables) + silc_hash_table_free(tls->variables); + if (tls->lock) + silc_mutex_free(tls->lock); + + tls->variables = NULL; + tls->lock = NULL; +} + } /* extern "C" */ diff --git a/lib/silcutil/tests/Makefile.am b/lib/silcutil/tests/Makefile.am index e4997279..3b81a73a 100644 --- a/lib/silcutil/tests/Makefile.am +++ b/lib/silcutil/tests/Makefile.am @@ -23,14 +23,16 @@ check_PROGRAMS = \ test_silcnet test_silcstack test_silcmime test_silcfdstream \ test_silcatomic test_silcmutex test_silctime test_silcthread \ test_silcdll test_silcenv test_silctimer test_silcbitops \ - test_silcregex test_silcbuffmt test_silcdir test_silcthreadqueue + test_silcregex test_silcbuffmt test_silcdir test_silcthreadqueue \ + test_silcrand test_silcglobal TESTS = test_silcstrutil test_silcstringprep test_silchashtable \ test_silclist test_silcfsm test_silcasync test_silcschedule \ test_silcnet test_silcstack test_silcmime test_silcfdstream \ test_silcatomic test_silctime test_silcthread \ test_silcdll test_silcenv test_silctimer test_silcbitops \ - test_silcregex test_silcbuffmt test_silcdir test_silcthreadqueue + test_silcregex test_silcbuffmt test_silcdir test_silcthreadqueue \ + test_silcrand test_silcglobal LIBS = $(SILC_COMMON_LIBS) LDADD = -L.. -L../.. -lsrt diff --git a/lib/silcutil/tests/test_silcglobal.c b/lib/silcutil/tests/test_silcglobal.c new file mode 100644 index 00000000..6ca7e728 --- /dev/null +++ b/lib/silcutil/tests/test_silcglobal.c @@ -0,0 +1,121 @@ +/* Global storage tests */ + +#include "silcruntime.h" + +int main(int argc, char **argv) +{ + SilcBool success = FALSE; + unsigned char *vbuf, *vbuf2; + unsigned char init[20]; + + if (argc > 1 && !strcmp(argv[1], "-d")) { + silc_log_debug(TRUE); + silc_log_quick(TRUE); + silc_log_debug_hexdump(TRUE); + silc_log_set_debug_string("*global*"); + } + + SILC_LOG_DEBUG(("Set global var")); + if (!silc_global_set_var("vbuf", 10, NULL, FALSE)) + goto err; + + SILC_LOG_DEBUG(("Retrieve var")); + vbuf = silc_global_get_var("vbuf", FALSE); + if (!vbuf) + goto err; + + SILC_LOG_DEBUG(("Change value")); + memset(vbuf, 'F', 10); + + SILC_LOG_DEBUG(("Retrieve var")); + vbuf = silc_global_get_var("vbuf", FALSE); + if (!vbuf) + goto err; + if (vbuf[0] != 'F') + goto err; + + SILC_LOG_DEBUG(("Retrieve var (must not find)")); + vbuf = silc_global_get_var("vbuf2", FALSE); + if (vbuf) + goto err; + SILC_LOG_DEBUG(("Retrieve var (must not find)")); + vbuf = silc_global_get_var("VBUF", FALSE); + if (vbuf) + goto err; + SILC_LOG_DEBUG(("Retrieve var (must not find)")); + vbuf = silc_global_get_var("vbuf", TRUE); + if (vbuf) + goto err; + + SILC_LOG_DEBUG(("Reset same var")); + if (!silc_global_set_var("vbuf", 20, NULL, FALSE)) + goto err; + + SILC_LOG_DEBUG(("Retrieve var")); + vbuf = silc_global_get_var("vbuf", FALSE); + if (!vbuf) + goto err; + + SILC_LOG_DEBUG(("Change value")); + memset(vbuf, 'F', 20); + + SILC_LOG_DEBUG(("Retrieve var")); + vbuf = silc_global_get_var("vbuf", FALSE); + if (!vbuf) + goto err; + if (vbuf[19] != 'F') + goto err; + + SILC_LOG_DEBUG(("Reset Tls var with initial value")); + memset(init, 'D', 20); + if (!silc_global_set_var("vbuf", 20, init, TRUE)) + goto err; + + SILC_LOG_DEBUG(("Retrieve var")); + vbuf2 = silc_global_get_var("vbuf", TRUE); + if (vbuf == vbuf2) + goto err; + if (!vbuf2) + goto err; + if (vbuf2[19] != 'D') + goto err; + + SILC_LOG_DEBUG(("Change value")); + memset(vbuf2, 'T', 20); + + SILC_LOG_DEBUG(("Retrieve Tls var")); + vbuf = silc_global_get_var("vbuf", TRUE); + if (!vbuf) + goto err; + if (vbuf[0] != 'T') + goto err; + + SILC_LOG_DEBUG(("Retrieve global var")); + vbuf = silc_global_get_var("vbuf", FALSE); + if (!vbuf) + goto err; + if (vbuf[19] != 'F') + goto err; + + SILC_LOG_DEBUG(("Delete global var")); + silc_global_del_var("vbuf", FALSE); + SILC_LOG_DEBUG(("Retrieve var (must not find)")); + vbuf = silc_global_get_var("vbuf", FALSE); + if (vbuf) + goto err; + + SILC_LOG_DEBUG(("Delete Tls var")); + silc_global_del_var("vbuf", TRUE); + SILC_LOG_DEBUG(("Retrieve var (must not find)")); + vbuf = silc_global_get_var("vbuf", TRUE); + if (vbuf) + goto err; + + success = TRUE; + + err: + SILC_LOG_DEBUG(("Testing was %s", success ? "SUCCESS" : "FAILURE")); + fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE"); + + return !success; +} diff --git a/lib/silcutil/tests/test_silcrand.c b/lib/silcutil/tests/test_silcrand.c new file mode 100644 index 00000000..37e2a14d --- /dev/null +++ b/lib/silcutil/tests/test_silcrand.c @@ -0,0 +1,55 @@ +/* PRNG tests */ + +#include "silcruntime.h" + +int main(int argc, char **argv) +{ + SilcBool success = FALSE; + SilcUInt32 num, seen; + SilcUInt64 lnum; + int i; + + silc_runtime_init(); + + if (argc > 1 && !strcmp(argv[1], "-d")) { + silc_log_debug(TRUE); + silc_log_quick(TRUE); + silc_log_debug_hexdump(TRUE); + silc_log_set_debug_string("*rand*"); + } + + num = silc_rand(); + SILC_LOG_DEBUG(("Number: %lu", num)); + + SILC_LOG_DEBUG(("Seed RNG")); + silc_rand_seed(1); + + for (i = 0; i < 1000; i++) { + num = silc_rand(); + SILC_LOG_DEBUG(("Number: %lu", num)); + } + + seen = silc_rand(); + for (i = 0; i < 10000000; i++) { + num = silc_rand(); + if (num == seen) + goto err; + } + + for (i = 0; i < 1000; i++) { + if (!(i % 100)) + silc_rand_seed((SilcUInt32)lnum); + lnum = silc_rand64(); + SILC_LOG_DEBUG(("Number: %p", lnum)); + } + + success = TRUE; + + err: + SILC_LOG_DEBUG(("Testing was %s", success ? "SUCCESS" : "FAILURE")); + fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE"); + + silc_runtime_uninit(); + + return !success; +} diff --git a/lib/silcutil/unix/silcunixthread.c b/lib/silcutil/unix/silcunixthread.c index 2a826251..286a26db 100644 --- a/lib/silcutil/unix/silcunixthread.c +++ b/lib/silcutil/unix/silcunixthread.c @@ -19,9 +19,14 @@ #include "silcruntime.h" +/************************ Static utility functions **************************/ + +static SilcTls silc_thread_tls_init_shared(SilcTls other); + /**************************** SILC Thread API *******************************/ typedef struct { + SilcTls tls; SilcThreadStart start_func; void *context; } *SilcThreadStartContext; @@ -31,10 +36,11 @@ static void *silc_thread_start(void *context) SilcThreadStartContext c = context; SilcThreadStart start_func = c->start_func; void *start_context = c->context; + SilcTls other = c->tls; silc_free(c); - silc_thread_tls_init(); + silc_thread_tls_init_shared(other); return start_func(start_context); } @@ -58,6 +64,7 @@ SilcThread silc_thread_create(SilcThreadStart start_func, void *context, return NULL; c->start_func = start_func; c->context = context; + c->tls = silc_thread_get_tls(); if (pthread_attr_init(&attr)) { silc_set_errno_posix(errno); @@ -348,7 +355,13 @@ static pthread_once_t key_once = PTHREAD_ONCE_INIT; static void silc_thread_tls_destructor(void *context) { - silc_free(context); + SilcTls tls = context; + + if (tls->tls_variables) + silc_hash_table_free(tls->tls_variables); + tls->tls_variables = NULL; + + silc_free(tls); } static void silc_thread_tls_alloc(void) @@ -373,8 +386,36 @@ SilcTls silc_thread_tls_init(void) SILC_LOG_ERROR(("Error allocating Thread-local storage")); return NULL; } + pthread_setspecific(key, tls); + + /* Allocate global lock */ + silc_mutex_alloc(&tls->lock); + + return tls; +} +static SilcTls silc_thread_tls_init_shared(SilcTls other) +{ + SilcTls tls; + + pthread_once(&key_once, silc_thread_tls_alloc); + + if (silc_thread_get_tls()) + return silc_thread_get_tls(); + + /* Allocate Tls for the thread */ + tls = silc_calloc(1, sizeof(*tls)); + if (!tls) { + SILC_LOG_ERROR(("Error allocating Thread-local storage")); + return NULL; + } pthread_setspecific(key, tls); + + /* Take shared data */ + tls->shared_data = 1; + tls->lock = other->lock; + tls->variables = other->variables; + return tls; } @@ -385,6 +426,26 @@ SilcTls silc_thread_get_tls(void) return pthread_getspecific(key); } +void silc_thread_tls_uninit(void) +{ + SilcTls tls = silc_thread_get_tls(); + + if (!tls || tls->shared_data) + return; + + /* Main thread cleanup */ + if (tls->tls_variables) + silc_hash_table_free(tls->tls_variables); + if (tls->variables) + silc_hash_table_free(tls->variables); + if (tls->lock) + silc_mutex_free(tls->lock); + tls->variables = NULL; + tls->lock = NULL; + silc_free(tls); + pthread_setspecific(key, NULL); +} + #else SilcTlsStruct tls; @@ -397,12 +458,30 @@ SilcTls silc_thread_tls_init(void) tls_ptr = &tls; memset(tls_ptr, 0, sizeof(*tls_ptr)); + + atexit(silc_thread_tls_uninit); + return tls_ptr; } +static SilcTls silc_thread_tls_init_shared(SilcTls other) +{ + return silc_thread_tls_init(); +} + SilcTls silc_thread_get_tls(void) { return tls_ptr; } +void silc_thread_tls_uninit(void) +{ + if (tls.tls_variables) + silc_hash_table_free(tls.tls_variables); + if (tls.variables) + silc_hash_table_free(tls.variables); + if (tls.lock) + silc_mutex_free(tls.lock); +} + #endif diff --git a/lib/silcutil/win32/silcwin32thread.c b/lib/silcutil/win32/silcwin32thread.c index fa35683d..aa0cfaaf 100644 --- a/lib/silcutil/win32/silcwin32thread.c +++ b/lib/silcutil/win32/silcwin32thread.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2001 - 2007 Pekka Riikonen + Copyright (C) 2001 - 2008 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -16,9 +16,12 @@ GNU General Public License for more details. */ -/* $Id$ */ -#include "silc.h" +#include "silcruntime.h" + +/************************ Static utility functions **************************/ + +static SilcTls silc_thread_tls_init_shared(SilcTls other); /**************************** SILC Thread API *******************************/ @@ -30,6 +33,7 @@ typedef struct { SilcThreadStart start_func; void *context; SilcBool waitable; + SilcTls tls; } *SilcWin32Thread; /* Actual routine that is called by WIN32 when the thread is created. @@ -39,14 +43,16 @@ typedef struct { unsigned __stdcall silc_thread_win32_start(void *context) { SilcWin32Thread thread = (SilcWin32Thread)context; - SilcTls tls; + SilcTls other = thread->tls, tls; - tls = silc_thread_tls_init(); + tls = silc_thread_tls_init_shared(other); if (tls) tls->platform_context = thread; silc_thread_exit(thread->start_func(thread->context)); + if (tls->tls_variables) + silc_hash_table_free(tls->tls_variables); silc_free(tls); return 0; @@ -68,6 +74,7 @@ SilcThread silc_thread_create(SilcThreadStart start_func, void *context, thread->start_func = start_func; thread->context = context; thread->waitable = waitable; + thread->tls = silc_thread_get_tls(); thread->thread = _beginthreadex(NULL, 0, (LPTHREAD_START_ROUTINE)silc_thread_win32_start, (void *)thread, 0, &id); @@ -429,8 +436,44 @@ SilcTls silc_thread_tls_init(void) SILC_LOG_ERROR(("Error allocating Thread-local storage")); return NULL; } + TlsSetValue(silc_tls, tls); + + /* Allocate global lock */ + silc_mutex_alloc(&tls->lock); + + return tls; +} + +static SilcTls silc_thread_tls_init_shared(SilcTls other) +{ + SilcTls tls; + + if (!silc_tls_set) { + silc_tls = TlsAlloc(); + if (silc_tls == TLS_OUT_OF_INDEXES) { + SILC_LOG_ERROR(("Error creating Thread-local storage")); + return NULL; + } + + silc_tls_set = TRUE; + } + + if (silc_thread_get_tls()) + return silc_thread_get_tls(); + /* Allocate Tls for the thread */ + tls = silc_calloc(1, sizeof(*tls)); + if (!tls) { + SILC_LOG_ERROR(("Error allocating Thread-local storage")); + return NULL; + } TlsSetValue(silc_tls, tls); + + /* Take shared data */ + tls->shared_data = 1; + tls->lock = other->lock; + tls->variables = other->variables; + return tls; } @@ -439,6 +482,24 @@ SilcTls silc_thread_get_tls(void) return (SilcTls)TlsGetValue(silc_tls); } +void silc_thread_tls_uninit(void) +{ + SilcTls tls = silc_thread_get_tls(); + + if (!tls || tls->shared_data) + return; + + if (tls->tls_variables) + silc_hash_table_free(tls->tls_variables); + if (tls->variables) + silc_hash_table_free(tls->variables); + if (tls->lock) + silc_mutex_free(tls->lock); + + tls->variables = NULL; + tls->lock = NULL; +} + #else SilcTlsStruct tls; @@ -454,9 +515,24 @@ SilcTls silc_thread_tls_init(void) return tls_ptr; } +static SilcTls silc_thread_tls_init_shared(SilcTls other) +{ + return silc_thread_tls_init(); +} + SilcTls silc_thread_get_tls(void) { return tls_ptr; } +void silc_thread_tls_uninit(void) +{ + if (tls.tls_variables) + silc_hash_table_free(tls.tls_variables); + if (tls.variables) + silc_hash_table_free(tls.variables); + if (tls.lock) + silc_mutex_free(tls.lock); +} + #endif /* SILC_THREADS */ -- 2.24.0