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.
(o Fast mutex implementation. Fast rwlock implementation. Mutex and
rwlock implementation using atomic operations.) not for now.
- (o mmap) maybe
-
lib/silcutil/symbian/
=====================
silcerrno.c \
silcgetopt.c \
silcregex.c \
- silcthreadqueue.c
+ silcthreadqueue.c \
+ silcrand.c \
+ silcglobal.c
include_HEADERS = \
$(SILC_DIST_HEADER) \
silcerrno.h \
silcgetopt.h \
silcregex.h \
- silcthreadqueue.h
+ silcthreadqueue.h \
+ silcrand.h \
+ silcglobal.h
SILC_EXTRA_DIST =
--- /dev/null
+/*
+
+ silcglobal.c
+
+ Author: Pekka Riikonen <priikone@silcnet.org>
+
+ 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);
+}
--- /dev/null
+/*
+
+ silcglobal.h
+
+ Author: Pekka Riikonen <priikone@silcnet.org>
+
+ 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 */
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);
+}
Author: Pekka Riikonen <priikone@silcnet.org>
- 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
*/
-/****h* silcutil/SILC Hash Table Interface
+/****h* silcutil/Hash Table Interface
*
* DESCRIPTION
*
* 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.
*
* 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.
*
#ifndef SILCHASHTABLE_H
#define SILCHASHTABLE_H
-/****s* silcutil/SilcHashTableAPI/SilcHashTable
+/****s* silcutil/SilcHashTable
*
* NAME
*
***/
typedef struct SilcHashTableStruct *SilcHashTable;
-/****s* silcutil/SilcHashTableAPI/SilcHashTableList
+/****s* silcutil/SilcHashTableList
*
* NAME
*
};
/***/
-/****f* silcutil/SilcHashTableAPI/SilcHashFunction
+/****f* silcutil/SilcHashFunction
*
* SYNOPSIS
*
***/
typedef SilcUInt32 (*SilcHashFunction)(void *key, void *user_context);
-/****f* silcutil/SilcHashTableAPI/SilcHashCompare
+/****f* silcutil/SilcHashCompare
*
* SYNOPSIS
*
typedef SilcBool (*SilcHashCompare)(void *key1, void *key2,
void *user_context);
-/****f* silcutil/SilcHashTableAPI/SilcHashDestructor
+/****f* silcutil/SilcHashDestructor
*
* SYNOPSIS
*
typedef void (*SilcHashDestructor)(void *key, void *context,
void *user_context);
-/****f* silcutil/SilcHashTableAPI/SilcHashForeach
+/****f* silcutil/SilcHashForeach
*
* SYNOPSIS
*
/* Simple hash table interface */
-/****f* silcutil/SilcHashTableAPI/silc_hash_table_alloc
+/****f* silcutil/silc_hash_table_alloc
*
* SYNOPSIS
*
void *destructor_user_context,
SilcBool auto_rehash);
-/****f* silcutil/SilcHashTableAPI/silc_hash_table_free
+/****f* silcutil/silc_hash_table_free
*
* SYNOPSIS
*
***/
void silc_hash_table_free(SilcHashTable ht);
-/****f* silcutil/SilcHashTableAPI/silc_hash_table_size
+/****f* silcutil/silc_hash_table_size
*
* SYNOPSIS
*
***/
SilcUInt32 silc_hash_table_size(SilcHashTable ht);
-/****f* silcutil/SilcHashTableAPI/silc_hash_table_count
+/****f* silcutil/silc_hash_table_count
*
* SYNOPSIS
*
***/
SilcUInt32 silc_hash_table_count(SilcHashTable ht);
-/****f* silcutil/SilcHashTableAPI/silc_hash_table_add
+/****f* silcutil/silc_hash_table_add
*
* SYNOPSIS
*
***/
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
*
***/
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
*
***/
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
*
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
*
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
*
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
*
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
*
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
*
***/
void silc_hash_table_rehash(SilcHashTable ht, SilcUInt32 new_size);
-/****f* silcutil/SilcHashTableAPI/silc_hash_table_list
+/****f* silcutil/silc_hash_table_list
*
* SYNOPSIS
*
***/
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
*
***/
void silc_hash_table_list_reset(SilcHashTableList *htl);
-/****f* silcutil/SilcHashTableAPI/silc_hash_table_get
+/****f* silcutil/silc_hash_table_get
*
* SYNOPSIS
*
/* 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
*
SilcHashFunction hash,
void *hash_user_context);
-/****f* silcutil/SilcHashTableAPI/silc_hash_table_set_ext
+/****f* silcutil/silc_hash_table_set_ext
*
* SYNOPSIS
*
SilcHashFunction hash,
void *hash_user_context);
-/****f* silcutil/SilcHashTableAPI/silc_hash_table_del_ext
+/****f* silcutil/silc_hash_table_del_ext
*
* SYNOPSIS
*
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
*
SilcHashDestructor destructor,
void *destructor_user_context);
-/****f* silcutil/SilcHashTableAPI/silc_hash_table_find_ext
+/****f* silcutil/silc_hash_table_find_ext
*
* SYNOPSIS
*
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
*
SilcHashCompare compare,
void *compare_user_context);
-/****f* silcutil/SilcHashTableAPI/silc_hash_table_find_foreach_ext
+/****f* silcutil/silc_hash_table_find_foreach_ext
*
* SYNOPSIS
*
SilcHashForeach foreach,
void *foreach_user_context);
-/****f* silcutil/SilcHashTableAPI/silc_hash_table_rehash_ext
+/****f* silcutil/silc_hash_table_rehash_ext
*
* SYNOPSIS
*
/* Hash functions */
-/****f* silcutil/SilcHashTableAPI/silc_hash_string
+/****f* silcutil/silc_hash_string
*
* SYNOPSIS
*
***/
SilcUInt32 silc_hash_string(void *key, void *user_context);
-/****f* silcutil/SilcHashTableAPI/silc_hash_string_case
+/****f* silcutil/silc_hash_string_case
*
* SYNOPSIS
*
***/
SilcUInt32 silc_hash_string_case(void *key, void *user_context);
-/****f* silcutil/SilcHashTableAPI/silc_hash_utf8_string
+/****f* silcutil/silc_hash_utf8_string
*
* SYNOPSIS
*
***/
SilcUInt32 silc_hash_utf8_string(void *key, void *user_context);
-/****f* silcutil/SilcHashTableAPI/silc_hash_uint
+/****f* silcutil/silc_hash_uint
*
* SYNOPSIS
*
***/
SilcUInt32 silc_hash_uint(void *key, void *user_context);
-/****f* silcutil/SilcHashTableAPI/silc_hash_ptr
+/****f* silcutil/silc_hash_ptr
*
* SYNOPSIS
*
***/
SilcUInt32 silc_hash_ptr(void *key, void *user_context);
-/****f* silcutil/SilcHashTableAPI/silc_hash_data
+/****f* silcutil/silc_hash_data
*
* SYNOPSIS
*
/* Comparison functions */
-/****f* silcutil/SilcHashTableAPI/silc_hash_string_compare
+/****f* silcutil/silc_hash_string_compare
*
* SYNOPSIS
*
***/
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
*
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
*
***/
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
*
***/
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
--- /dev/null
+/*
+
+ silcrand.c
+
+ Author: Pekka Riikonen <priikone@silcnet.org>
+
+ 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));
+}
--- /dev/null
+/*
+
+ silcrand.h
+
+ Author: Pekka Riikonen <priikone@silcnet.org>
+
+ 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 */
--- /dev/null
+/*
+
+ silcruntime.h
+
+ Author: Pekka Riikonen <priikone@silcnet.org>
+
+ 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 <silcwin32.h>
+#endif
+
+#if defined(SILC_SYMBIAN)
+#include <silcsymbian.h>
+#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 <silcerrno.h>
+#include <silctypes.h>
+#include <silcbitops.h>
+#include <silcmutex.h>
+#include <silcatomic.h>
+#include <silcgetopt.h>
+#include <silcstack.h>
+#include <silcmemory.h>
+#include <silclist.h>
+#include <silcdlist.h>
+#include <silcsnprintf.h>
+#include <silctime.h>
+#include <silctimer.h>
+#include <silccond.h>
+#include <silcglobal.h>
+#include <silcthread.h>
+#include <silcthreadqueue.h>
+#include <silcschedule.h>
+#include <silclog.h>
+#include <silcfileutil.h>
+#include <silcdir.h>
+#include <silcbuffer.h>
+#include <silcbuffmt.h>
+#include <silcasync.h>
+#include <silcregex.h>
+#include <silcenv.h>
+#include <silcdll.h>
+#include <silchashtable.h>
+#include <silcstream.h>
+#include <silcnet.h>
+#include <silcbase64.h>
+#include <silcstrutil.h>
+#include <silcutf8.h>
+#include <silcstringprep.h>
+#include <silcutil.h>
+#include <silcconfig.h>
+#include <silcfsm.h>
+#include <silcsocketstream.h>
+#include <silcfdstream.h>
+#include <silcmime.h>
+#include <silcrand.h>
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SILCRUNTIME_H */
/*************************** Thread-local Storage ***************************/
+/* Set Tls context */
+
void silc_thread_tls_set(void *context)
{
SilcTls tls = silc_thread_get_tls();
tls->thread_context = context;
}
+/* Get Tls context */
+
void *silc_thread_tls_get(void)
{
SilcTls tls = silc_thread_get_tls();
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. */
/* 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 */
Author: Pekka Riikonen <priikone@silcnet.org>
- 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
*/
-#include "silc.h"
+#include "silcruntime.h"
#include <e32base.h>
#include <e32std.h>
+/************************ Static utility functions **************************/
+
+static SilcTls silc_thread_tls_init_shared(SilcTls other);
+
/**************************** SILC Thread API *******************************/
extern "C" {
SilcThreadStart start_func;
void *context;
SilcBool waitable;
-#else
- void *tmp;
#endif
+ SilcTls tls;
};
/* The actual thread function */
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) {
delete cs;
}
+ if (tls->tls_variables)
+ silc_hash_table_free(tls->tls_variables);
silc_free(tls);
silc_thread_exit(ret);
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;
}
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" */
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
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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;
+}
#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;
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);
}
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);
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)
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;
}
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;
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
Author: Pekka Riikonen <priikone@silcnet.org>
- 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
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 *******************************/
SilcThreadStart start_func;
void *context;
SilcBool waitable;
+ SilcTls tls;
} *SilcWin32Thread;
/* Actual routine that is called by WIN32 when the thread is created.
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;
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);
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;
}
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;
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 */