Added SILC Rand API, SILC Global Variables API and silcruntime.h.in
authorPekka Riikonen <priikone@silcnet.org>
Thu, 31 Jan 2008 17:23:02 +0000 (19:23 +0200)
committerPekka Riikonen <priikone@silcnet.org>
Thu, 31 Jan 2008 17:23:02 +0000 (19:23 +0200)
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.

17 files changed:
TODO
lib/silcutil/Makefile.ad
lib/silcutil/silcglobal.c [new file with mode: 0644]
lib/silcutil/silcglobal.h [new file with mode: 0644]
lib/silcutil/silchashtable.c
lib/silcutil/silchashtable.h
lib/silcutil/silcrand.c [new file with mode: 0644]
lib/silcutil/silcrand.h [new file with mode: 0644]
lib/silcutil/silcruntime.h.in [new file with mode: 0644]
lib/silcutil/silcthread.c
lib/silcutil/silcthread_i.h
lib/silcutil/symbian/silcsymbianthread.cpp
lib/silcutil/tests/Makefile.am
lib/silcutil/tests/test_silcglobal.c [new file with mode: 0644]
lib/silcutil/tests/test_silcrand.c [new file with mode: 0644]
lib/silcutil/unix/silcunixthread.c
lib/silcutil/win32/silcwin32thread.c

diff --git a/TODO b/TODO
index 4a432c6782316fd6ed3e236daa8233ea87dc7fa7..ac3b6ac21caac85ff83cd234969656bd3b6b5ea0 100644 (file)
--- 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/
 =====================
index 3456e38d37d7cff1f1730df5d0da39c36bd8128b..b1ce5fd05301be11f24d68881a2be538d7e0855a 100644 (file)
@@ -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 (file)
index 0000000..eae95ce
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+
+  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);
+}
diff --git a/lib/silcutil/silcglobal.h b/lib/silcutil/silcglobal.h
new file mode 100644 (file)
index 0000000..4895af5
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+
+  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 */
index f440be49488a7829153046ccaf58a79a0f60a87f..7c3d7cbfbad5b899de73eec3c1673a251b6c68d3 100644 (file)
@@ -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);
+}
index 966ffc469e3d2a3fe1ae6bae591c8599726af738..624d18a4331d5097688af5f7965984ece1ea555f 100644 (file)
@@ -4,7 +4,7 @@
 
   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
@@ -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 (file)
index 0000000..10dcc2c
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+
+  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));
+}
diff --git a/lib/silcutil/silcrand.h b/lib/silcutil/silcrand.h
new file mode 100644 (file)
index 0000000..6d8abba
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+
+  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 */
diff --git a/lib/silcutil/silcruntime.h.in b/lib/silcutil/silcruntime.h.in
new file mode 100644 (file)
index 0000000..9736eed
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+
+  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 */
index aad875a000091b862e219b967cafa905fa674018..c8507034e1eb9900f4c40a33fb82c56659ffaa8b 100644 (file)
@@ -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();
index d0d2fd737f2dd66a775e086f9ad0a41116c2fb65..f7c6697f1b2be45e4cb6d0a8e3017d739811f8f4 100644 (file)
    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 */
index 05a2e893b294a22ed8b72e20ad838e0dc35dda49..4d08efaf1a1c71d639bddbfe0fcf6d7fd15a2048 100644 (file)
@@ -4,7 +4,7 @@
 
   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" {
@@ -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" */
index e4997279f5a3b872b4e50d485bc90111aeaa710a..3b81a73a6433c14afbd7d9bd150b8164ce767167 100644 (file)
@@ -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 (file)
index 0000000..6ca7e72
--- /dev/null
@@ -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 (file)
index 0000000..37e2a14
--- /dev/null
@@ -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;
+}
index 2a826251a2ae0825e73f535678e6002d1c9b89af..286a26db7fba5e4f3da8b7315fc1e304e7b6929b 100644 (file)
 
 #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
index fa35683dbe4b19b5ebd96de2d9f8d52c45d1ca2a..aa0cfaafd5068efc79e633635b02004bf263ccd5 100644 (file)
@@ -4,7 +4,7 @@
 
   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 *******************************/
 
@@ -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 */