summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Jennings <mej@kainx.org>2006-07-13 23:03:45 +0000
committerMichael Jennings <mej@kainx.org>2006-07-13 23:03:45 +0000
commit1f7ded81f9871bb18c7bb0eefa9668f223a31899 (patch)
tree57762f0b958d501980c6aa7485952d8c9bad24bc
parentf6fc5e71127f6648bcc4106eea6ecfe40dadcd16 (diff)
downloadlibast-1f7ded81f9871bb18c7bb0eefa9668f223a31899.tar.gz
Thu Jul 13 14:02:08 2006 Michael Jennings (mej)
Added thread, mutex, and condition interfaces along with their corresponding pthreads-based implementations. Not quite done yet, and not tested. Added dynamically-loadable module object class along with corresponding unit tests. Appears to work fine. ---------------------------------------------------------------------- SVN revision: 23882
-rw-r--r--ChangeLog9
-rwxr-xr-xautogen.sh4
-rw-r--r--configure.in1
-rw-r--r--include/libast.h12
-rw-r--r--include/libast/Makefile.am6
-rw-r--r--include/libast/condition_if.h73
-rw-r--r--include/libast/list_if.h4
-rw-r--r--include/libast/module.h83
-rw-r--r--include/libast/mutex_if.h71
-rw-r--r--include/libast/pthreads.h121
-rw-r--r--include/libast/thread_if.h96
-rw-r--r--libast.m4200
-rw-r--r--src/Makefile.am12
-rw-r--r--src/array.c1
-rw-r--r--src/module.c307
-rw-r--r--src/msgs.c30
-rw-r--r--src/pthreads.c733
-rw-r--r--test/test.c490
18 files changed, 2014 insertions, 239 deletions
diff --git a/ChangeLog b/ChangeLog
index 193cfe0..33d33f9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -787,3 +787,12 @@ Added sprintf() routines for string classes.
Began work on UTF-8/Unicode strings.
----------------------------------------------------------------------
+Thu Jul 13 14:02:08 2006 Michael Jennings (mej)
+
+Added thread, mutex, and condition interfaces along with their
+corresponding pthreads-based implementations. Not quite done yet, and
+not tested.
+
+Added dynamically-loadable module object class along with
+corresponding unit tests. Appears to work fine.
+----------------------------------------------------------------------
diff --git a/autogen.sh b/autogen.sh
index f453e03..afe9439 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -55,9 +55,9 @@ done
export LIBTOOLIZE ACLOCAL AUTOCONF AUTOHEADER AUTOMAKE
# Check for existing libast.m4 we can use. Use the local one if not.
-if test ! -f "`$ACLOCAL --print-ac-dir`/libast.m4"; then
+#if test ! -f "`$ACLOCAL --print-ac-dir`/libast.m4"; then
ACLOCAL_FLAGS="-I . $ACLOCAL_FLAGS"
-fi
+#fi
# Run the stuff.
(set -x && $LIBTOOLIZE -c -f) || abort libtool
diff --git a/configure.in b/configure.in
index d95bd55..623c8ba 100644
--- a/configure.in
+++ b/configure.in
@@ -96,6 +96,7 @@ AST_IMLIB2_SUPPORT()
AST_MMX_SUPPORT()
AST_ARG_REGEXP(REGEXP)
AST_ARG_BACKQUOTE_EXEC(ALLOW_BACKQUOTE_EXEC)
+AST_PTHREADS()
AST_FLAGS()
AC_SUBST(CC)
diff --git a/include/libast.h b/include/libast.h
index d397328..3df49d8 100644
--- a/include/libast.h
+++ b/include/libast.h
@@ -107,10 +107,13 @@ extern int re_exec();
# endif
#endif
+/* Type and object headers that must go first. */
#include <libast/types.h>
#include <libast/obj.h>
+/* Basic objects */
#include <libast/mbuff.h>
+#include <libast/module.h>
#include <libast/objpair.h>
#include <libast/regexp.h>
#include <libast/socket.h>
@@ -119,15 +122,23 @@ extern int re_exec();
#include <libast/url.h>
#include <libast/ustr.h>
+/* Interface classes */
+#include <libast/condition_if.h>
#include <libast/iterator_if.h>
#include <libast/list_if.h>
#include <libast/map_if.h>
+#include <libast/mutex_if.h>
+#include <libast/thread_if.h>
#include <libast/vector_if.h>
+/* List/vector/map implementations */
#include <libast/array.h>
#include <libast/linked_list.h>
#include <libast/dlinked_list.h>
+/* Thread/condition/mutex implementations */
+#include <libast/pthreads.h>
+
#include <libast/avl_tree.h>
/******************************* GENERIC GOOP *********************************/
@@ -2690,6 +2701,7 @@ typedef spif_uint32_t (*spifhash_func_t)(spif_uint8_t *, spif_uint32_t, spif_uin
/* msgs.c */
extern void libast_set_program_name(const char *);
extern void libast_set_program_version(const char *);
+extern spif_bool_t libast_set_silent(spif_bool_t);
extern int libast_dprintf(const char *, ...);
extern void libast_print_error(const char *fmt, ...);
extern void libast_print_warning(const char *fmt, ...);
diff --git a/include/libast/Makefile.am b/include/libast/Makefile.am
index f0e26c7..1052bda 100644
--- a/include/libast/Makefile.am
+++ b/include/libast/Makefile.am
@@ -1,8 +1,9 @@
# $Id: Makefile.am,v 1.6 2001/09/22 16:25:29 mej Exp $
EXTRA_HEADERS = array.h avl_tree.h dlinked_list.h iterator_if.h \
-linked_list.h list_if.h map_if.h mbuff.h obj.h objpair.h regexp.h \
-socket.h str.h sysdefs.h tok.h types.h url.h ustr.h vector_if.h
+linked_list.h list_if.h map_if.h mbuff.h module.h obj.h objpair.h \
+regexp.h socket.h str.h sysdefs.h tok.h types.h url.h ustr.h \
+vector_if.h
install-exec-hook:
$(mkinstalldirs) $(DESTDIR)$(includedir)/$(PACKAGE)
@@ -22,4 +23,5 @@ types.h: types.h.in
sysdefs.h: sysdefs.h.in
(cd $(top_srcdir) && ./config.status)
+
MAINTAINERCLEANFILES = Makefile.in
diff --git a/include/libast/condition_if.h b/include/libast/condition_if.h
new file mode 100644
index 0000000..c3f847c
--- /dev/null
+++ b/include/libast/condition_if.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 1997-2004, Michael Jennings
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies of the Software, its documentation and marketing & publicity
+ * materials, and acknowledgment shall be given in the documentation, materials
+ * and software packages that this Software was used.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _LIBAST_CONDITION_IF_H_
+#define _LIBAST_CONDITION_IF_H_
+
+/*
+ * interface goop
+ */
+
+/* Standard typecast macros.... */
+#define SPIF_CONDITION(o) (SPIF_CAST(condition) (o))
+#define SPIF_CONDITION_CLASS(o) (SPIF_CAST(conditionclass) SPIF_OBJ_CLASS(o))
+
+/* Name of class variable associated with condition interface */
+#define SPIF_CONDITIONCLASS_VAR(type) spif_ ## type ## _conditionclass
+
+/* Check if a condition is NULL */
+#define SPIF_CONDITION_ISNULL(o) (SPIF_CONDITION(o) == SPIF_NULL_TYPE(condition))
+
+/* Check if an object is a condition */
+#define SPIF_OBJ_IS_CONDITION(o) SPIF_OBJ_IS_TYPE(o, condition)
+
+/* Call a method on an instance of an implementation class */
+#define SPIF_CONDITION_CALL_METHOD(o, meth) SPIF_CONDITION_CLASS(o)->meth
+
+/* Calls to the basic functions. */
+#define SPIF_CONDITION_NEW(type) SPIF_CONDITION((SPIF_CLASS(SPIF_CONDITIONCLASS_VAR(type)))->noo())
+#define SPIF_CONDITION_INIT(o) SPIF_OBJ_INIT(o)
+#define SPIF_CONDITION_DONE(o) SPIF_OBJ_DONE(o)
+#define SPIF_CONDITION_DEL(o) SPIF_OBJ_DEL(o)
+#define SPIF_CONDITION_SHOW(o, b, i) SPIF_OBJ_SHOW(o, b, i)
+#define SPIF_CONDITION_COMP(o1, o2) SPIF_OBJ_COMP(o1, o2)
+#define SPIF_CONDITION_DUP(o) SPIF_OBJ_DUP(o)
+#define SPIF_CONDITION_TYPE(o) SPIF_OBJ_TYPE(o)
+
+#define SPIF_CONDITION_BROADCAST(o) SPIF_CAST(bool) ((SPIF_CONDITION_CALL_METHOD((o), broadcast))(o))
+#define SPIF_CONDITION_SIGNAL(o) SPIF_CAST(bool) ((SPIF_CONDITION_CALL_METHOD((o), signal))(o))
+#define SPIF_CONDITION_WAIT(o) SPIF_CAST(bool) ((SPIF_CONDITION_CALL_METHOD((o), wait))(o))
+#define SPIF_CONDITION_WAIT_TIMED(o, t) SPIF_CAST(bool) ((SPIF_CONDITION_CALL_METHOD((o), wait_timed))((o), (t)))
+
+typedef spif_obj_t spif_condition_t;
+
+SPIF_DECL_OBJ(conditionclass) {
+ SPIF_DECL_PARENT_TYPE(class);
+
+ spif_func_t broadcast;
+ spif_func_t signal;
+ spif_func_t wait;
+ spif_func_t wait_timed;
+};
+
+#endif /* _LIBAST_CONDITION_IF_H_ */
diff --git a/include/libast/list_if.h b/include/libast/list_if.h
index 5a07a6a..7c3a4dc 100644
--- a/include/libast/list_if.h
+++ b/include/libast/list_if.h
@@ -56,10 +56,10 @@
#define SPIF_LIST_APPEND(o, item) SPIF_CAST(bool) ((SPIF_LIST_CALL_METHOD((o), append))(o, item))
#define SPIF_LIST_CONTAINS(o, item) SPIF_CAST(bool) ((SPIF_LIST_CALL_METHOD((o), contains))(o, item))
-#define SPIF_LIST_COUNT(o) SPIF_CAST_C(size_t) ((SPIF_LIST_CALL_METHOD((o), count))(o))
+#define SPIF_LIST_COUNT(o) SPIF_CAST(listidx) ((SPIF_LIST_CALL_METHOD((o), count))(o))
#define SPIF_LIST_FIND(o, item) SPIF_CAST(obj) ((SPIF_LIST_CALL_METHOD((o), find))(o, item))
#define SPIF_LIST_GET(o, index) SPIF_CAST(obj) ((SPIF_LIST_CALL_METHOD((o), get))(o, index))
-#define SPIF_LIST_INDEX(o, item) SPIF_CAST_C(size_t) ((SPIF_LIST_CALL_METHOD((o), index))(o, item))
+#define SPIF_LIST_INDEX(o, item) SPIF_CAST(listidx) ((SPIF_LIST_CALL_METHOD((o), index))(o, item))
#define SPIF_LIST_INSERT(o, item) SPIF_CAST(bool) ((SPIF_LIST_CALL_METHOD((o), insert))(o, item))
#define SPIF_LIST_INSERT_AT(o, item, index) SPIF_CAST(bool) ((SPIF_LIST_CALL_METHOD((o), insert_at))(o, item, index))
#define SPIF_LIST_ITERATOR(o) SPIF_CAST(iterator) ((SPIF_LIST_CALL_METHOD((o), iterator))(o))
diff --git a/include/libast/module.h b/include/libast/module.h
new file mode 100644
index 0000000..52eac80
--- /dev/null
+++ b/include/libast/module.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 1997-2004, Michael Jennings
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies of the Software, its documentation and marketing & publicity
+ * materials, and acknowledgment shall be given in the documentation, materials
+ * and software packages that this Software was used.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _LIBAST_MODULE_H_
+#define _LIBAST_MODULE_H_
+
+#define SPIF_MODULE(obj) (SPIF_CAST(module) (obj))
+#define SPIF_MODULE_CLASS(o) (SPIF_CAST(moduleclass) SPIF_OBJ_CLASS(o))
+#define SPIF_OBJ_IS_MODULE(o) (SPIF_OBJ_IS_TYPE(o, module))
+#define SPIF_MODULE_ISNULL(s) SPIF_OBJ_ISNULL(SPIF_OBJ(s))
+#define SPIF_MODULECLASS_VAR(type) spif_ ## type ## _moduleclass
+#define SPIF_MODULE_CALL_METHOD(o, meth) SPIF_MODULE_CLASS(o)->meth
+
+#define SPIF_MODULE_NEW(type) SPIF_MODULE((SPIF_CLASS(SPIF_CLASS_VAR(type)))->noo())
+#define SPIF_MODULE_INIT(obj) SPIF_OBJ_INIT(obj)
+#define SPIF_MODULE_DONE(obj) SPIF_OBJ_DONE(obj)
+#define SPIF_MODULE_DEL(obj) SPIF_OBJ_DEL(obj)
+#define SPIF_MODULE_SHOW(obj, b, i) SPIF_OBJ_SHOW(obj, b, i)
+#define SPIF_MODULE_COMP(o1, o2) SPIF_OBJ_COMP(o1, o2)
+#define SPIF_MODULE_DUP(obj) SPIF_OBJ_DUP(obj)
+#define SPIF_MODULE_TYPE(obj) SPIF_OBJ_TYPE(obj)
+
+typedef spif_ptr_t (spif_getsym_func_t)(spif_charptr_t);
+
+SPIF_DECL_OBJ(module) {
+ SPIF_DECL_PARENT_TYPE(obj);
+ SPIF_DECL_PROPERTY(str, name);
+ SPIF_DECL_PROPERTY(str, path);
+ SPIF_DECL_PROPERTY(ptr, module_handle);
+ SPIF_DECL_PROPERTY(ptr, main_handle);
+};
+
+SPIF_DECL_OBJ(moduleclass) {
+ SPIF_DECL_PARENT_TYPE(class);
+
+ spif_func_t call;
+ spif_func_t getsym;
+ spif_func_t load;
+ spif_func_t run;
+ spif_func_t unload;
+};
+
+extern spif_class_t SPIF_CLASS_VAR(module);
+extern spif_moduleclass_t SPIF_MODULECLASS_VAR(module);
+extern spif_module_t spif_module_new(void);
+extern spif_bool_t spif_module_del(spif_module_t);
+extern spif_bool_t spif_module_init(spif_module_t);
+extern spif_bool_t spif_module_done(spif_module_t);
+extern spif_str_t spif_module_show(spif_module_t, spif_charptr_t, spif_str_t, size_t);
+extern spif_cmp_t spif_module_comp(spif_module_t, spif_module_t);
+extern spif_module_t spif_module_dup(spif_module_t);
+extern spif_classname_t spif_module_type(spif_module_t);
+extern spif_ptr_t spif_module_call(spif_module_t self, spif_charptr_t fname, spif_ptr_t data);
+extern spif_ptr_t spif_module_getsym(spif_module_t self, spif_charptr_t sym);
+extern spif_bool_t spif_module_load(spif_module_t self);
+extern spif_bool_t spif_module_run(spif_module_t self);
+extern spif_bool_t spif_module_unload(spif_module_t self);
+SPIF_DECL_PROPERTY_FUNC(module, str, name);
+SPIF_DECL_PROPERTY_FUNC(module, str, path);
+SPIF_DECL_PROPERTY_FUNC(module, ptr, module_handle);
+SPIF_DECL_PROPERTY_FUNC(module, ptr, main_handle);
+
+#endif /* _LIBAST_MODULE_H_ */
diff --git a/include/libast/mutex_if.h b/include/libast/mutex_if.h
new file mode 100644
index 0000000..c948e16
--- /dev/null
+++ b/include/libast/mutex_if.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 1997-2004, Michael Jennings
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies of the Software, its documentation and marketing & publicity
+ * materials, and acknowledgment shall be given in the documentation, materials
+ * and software packages that this Software was used.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _LIBAST_MUTEX_IF_H_
+#define _LIBAST_MUTEX_IF_H_
+
+/*
+ * interface goop
+ */
+
+/* Standard typecast macros.... */
+#define SPIF_MUTEX(o) (SPIF_CAST(mutex) (o))
+#define SPIF_MUTEX_CLASS(o) (SPIF_CAST(mutexclass) SPIF_OBJ_CLASS(o))
+
+/* Name of class variable associated with mutex interface */
+#define SPIF_MUTEXCLASS_VAR(type) spif_ ## type ## _mutexclass
+
+/* Check if a mutex is NULL */
+#define SPIF_MUTEX_ISNULL(o) (SPIF_MUTEX(o) == SPIF_NULL_TYPE(mutex))
+
+/* Check if an object is a mutex */
+#define SPIF_OBJ_IS_MUTEX(o) SPIF_OBJ_IS_TYPE(o, mutex)
+
+/* Call a method on an instance of an implementation class */
+#define SPIF_MUTEX_CALL_METHOD(o, meth) SPIF_MUTEX_CLASS(o)->meth
+
+/* Calls to the basic functions. */
+#define SPIF_MUTEX_NEW(type) SPIF_MUTEX((SPIF_CLASS(SPIF_MUTEXCLASS_VAR(type)))->noo())
+#define SPIF_MUTEX_INIT(o) SPIF_OBJ_INIT(o)
+#define SPIF_MUTEX_DONE(o) SPIF_OBJ_DONE(o)
+#define SPIF_MUTEX_DEL(o) SPIF_OBJ_DEL(o)
+#define SPIF_MUTEX_SHOW(o, b, i) SPIF_OBJ_SHOW(o, b, i)
+#define SPIF_MUTEX_COMP(o1, o2) SPIF_OBJ_COMP(o1, o2)
+#define SPIF_MUTEX_DUP(o) SPIF_OBJ_DUP(o)
+#define SPIF_MUTEX_TYPE(o) SPIF_OBJ_TYPE(o)
+
+#define SPIF_MUTEX_LOCK() SPIF_CAST(bool) ((SPIF_MUTEX_CALL_METHOD((o), lock))(o))
+#define SPIF_MUTEX_LOCK_NOWAIT() SPIF_CAST(bool) ((SPIF_MUTEX_CALL_METHOD((o), lock_nowait))(o))
+#define SPIF_MUTEX_UNLOCK() SPIF_CAST(bool) ((SPIF_MUTEX_CALL_METHOD((o), unlock))(o))
+
+typedef spif_obj_t spif_mutex_t;
+
+SPIF_DECL_OBJ(mutexclass) {
+ SPIF_DECL_PARENT_TYPE(class);
+
+ spif_func_t lock;
+ spif_func_t lock_nowait;
+ spif_func_t unlock;
+};
+
+#endif /* _LIBAST_MUTEX_IF_H_ */
diff --git a/include/libast/pthreads.h b/include/libast/pthreads.h
new file mode 100644
index 0000000..2b8f59b
--- /dev/null
+++ b/include/libast/pthreads.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 1997-2004, Michael Jennings
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies of the Software, its documentation and marketing & publicity
+ * materials, and acknowledgment shall be given in the documentation, materials
+ * and software packages that this Software was used.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _LIBAST_PTHREADS_H_
+#define _LIBAST_PTHREADS_H_
+
+#define SPIF_PTHREADS(obj) (SPIF_CAST(pthreads) (obj))
+#define SPIF_OBJ_IS_PTHREADS(o) (SPIF_OBJ_IS_TYPE(o, pthreads))
+#define SPIF_PTHREADS_ISNULL(s) SPIF_OBJ_ISNULL(SPIF_OBJ(s))
+
+SPIF_DECL_OBJ(pthreads) {
+ SPIF_DECL_PARENT_TYPE(obj);
+ SPIF_DECL_PROPERTY_C(pthread_t, handle);
+ SPIF_DECL_PROPERTY_C(pthread_t, creator);
+ SPIF_DECL_PROPERTY_C(pthread_attr_t, attr);
+ SPIF_DECL_PROPERTY(thread_func, main_func);
+ SPIF_DECL_PROPERTY(thread_data, data);
+ SPIF_DECL_PROPERTY(list, tls_keys);
+};
+
+#define SPIF_PTHREADS_MUTEX(obj) (SPIF_CAST(pthreads_mutex) (obj))
+#define SPIF_OBJ_IS_PTHREADS_MUTEX(o) (SPIF_OBJ_IS_TYPE(o, pthreads_mutex))
+#define SPIF_PTHREADS_MUTEX_ISNULL(s) SPIF_OBJ_ISNULL(SPIF_OBJ(s))
+
+SPIF_DECL_OBJ(pthreads_mutex) {
+ SPIF_DECL_PARENT_TYPE(obj);
+ SPIF_DECL_PROPERTY(thread, creator);
+ SPIF_DECL_PROPERTY_C(pthread_mutex_t, mutex);
+};
+
+#define SPIF_PTHREADS_CONDITION(obj) (SPIF_CAST(pthreads_condition) (obj))
+#define SPIF_OBJ_IS_PTHREADS_CONDITION(o) (SPIF_OBJ_IS_TYPE(o, pthreads_condition))
+#define SPIF_PTHREADS_CONDITION_ISNULL(s) SPIF_OBJ_ISNULL(SPIF_OBJ(s))
+
+SPIF_DECL_OBJ(pthreads_condition) {
+ SPIF_DECL_PARENT_TYPE(pthreads_mutex);
+ SPIF_DECL_PROPERTY_C(pthread_cond_t, cond);
+};
+
+extern SPIF_TYPE(class) SPIF_CLASS_VAR(pthreads);
+extern SPIF_TYPE(threadclass) SPIF_THREADCLASS_VAR(pthreads);
+extern spif_pthreads_t spif_pthreads_new(void);
+extern spif_pthreads_t spif_pthreads_new_with_func(spif_thread_func_t, spif_thread_data_t);
+extern spif_bool_t spif_pthreads_init(spif_pthreads_t);
+extern spif_bool_t spif_pthreads_init_with_func(spif_pthreads_t, spif_thread_func_t, spif_thread_data_t);
+extern spif_bool_t spif_pthreads_done(spif_pthreads_t);
+extern spif_bool_t spif_pthreads_del(spif_pthreads_t);
+extern spif_str_t spif_pthreads_show(spif_pthreads_t, spif_charptr_t, spif_str_t, size_t);
+extern spif_cmp_t spif_pthreads_comp(spif_pthreads_t, spif_pthreads_t);
+extern spif_pthreads_t spif_pthreads_dup(spif_pthreads_t);
+extern spif_classname_t spif_pthreads_type(spif_pthreads_t);
+extern spif_bool_t spif_pthreads_detach(spif_pthreads_t self);
+extern spif_condition_t spif_pthreads_get_condition(spif_pthreads_t self);
+extern spif_mutex_t spif_pthreads_get_mutex(spif_pthreads_t self);
+extern spif_bool_t spif_pthreads_kill(spif_pthreads_t self, int sig);
+extern spif_bool_t spif_pthreads_run(spif_pthreads_t self);
+extern spif_tls_handle_t spif_pthreads_tls_calloc(spif_pthreads_t self, size_t count, size_t size);
+extern spif_bool_t spif_pthreads_tls_free(spif_pthreads_t self, spif_tls_handle_t handle);
+extern spif_ptr_t spif_pthreads_tls_get(spif_pthreads_t self, spif_tls_handle_t handle);
+extern spif_tls_handle_t spif_pthreads_tls_malloc(spif_pthreads_t self, spif_memidx_t size);
+extern spif_bool_t spif_pthreads_tls_realloc(spif_pthreads_t self, spif_tls_handle_t handle, spif_memidx_t size);
+extern spif_bool_t spif_pthreads_wait(spif_pthreads_t self, spif_condition_t cond);
+extern spif_bool_t spif_pthreads_wait_for(spif_pthreads_t self, spif_pthreads_t other);
+SPIF_DECL_PROPERTY_FUNC_C(pthreads, pthread_t, handle);
+SPIF_DECL_PROPERTY_FUNC_C(pthreads, pthread_t, creator);
+SPIF_DECL_PROPERTY_FUNC_C(pthreads, pthread_attr_t, attr);
+SPIF_DECL_PROPERTY_FUNC(pthreads, thread_func, main_func);
+SPIF_DECL_PROPERTY_FUNC(pthreads, thread_data, data);
+SPIF_DECL_PROPERTY_FUNC(pthreads, list, tls_keys);
+
+extern SPIF_TYPE(mutexclass) SPIF_MUTEXCLASS_VAR(pthreads_mutex);
+extern spif_pthreads_mutex_t spif_pthreads_mutex_new(void);
+extern spif_bool_t spif_pthreads_mutex_init(spif_pthreads_mutex_t);
+extern spif_bool_t spif_pthreads_mutex_done(spif_pthreads_mutex_t);
+extern spif_bool_t spif_pthreads_mutex_del(spif_pthreads_mutex_t);
+extern spif_str_t spif_pthreads_mutex_show(spif_pthreads_mutex_t, spif_charptr_t, spif_str_t, size_t);
+extern spif_cmp_t spif_pthreads_mutex_comp(spif_pthreads_mutex_t, spif_pthreads_mutex_t);
+extern spif_pthreads_mutex_t spif_pthreads_mutex_dup(spif_pthreads_mutex_t);
+extern spif_classname_t spif_pthreads_mutex_type(spif_pthreads_mutex_t);
+extern spif_bool_t spif_pthreads_mutex_lock(spif_pthreads_mutex_t);
+extern spif_bool_t spif_pthreads_mutex_lock_nowait(spif_pthreads_mutex_t);
+extern spif_bool_t spif_pthreads_mutex_unlock(spif_pthreads_mutex_t);
+SPIF_DECL_PROPERTY_FUNC(pthreads_mutex, thread, creator);
+SPIF_DECL_PROPERTY_FUNC_C(pthreads_mutex, pthread_mutex_t, mutex);
+
+extern SPIF_TYPE(conditionclass) SPIF_CONDITIONCLASS_VAR(pthreads_condition);
+extern spif_pthreads_condition_t spif_pthreads_condition_new(void);
+extern spif_bool_t spif_pthreads_condition_init(spif_pthreads_condition_t);
+extern spif_bool_t spif_pthreads_condition_done(spif_pthreads_condition_t);
+extern spif_bool_t spif_pthreads_condition_del(spif_pthreads_condition_t);
+extern spif_str_t spif_pthreads_condition_show(spif_pthreads_condition_t, spif_charptr_t, spif_str_t, size_t);
+extern spif_cmp_t spif_pthreads_condition_comp(spif_pthreads_condition_t, spif_pthreads_condition_t);
+extern spif_pthreads_condition_t spif_pthreads_condition_dup(spif_pthreads_condition_t);
+extern spif_classname_t spif_pthreads_condition_type(spif_pthreads_condition_t);
+extern spif_bool_t spif_pthreads_condition_broadcast(spif_pthreads_condition_t);
+extern spif_bool_t spif_pthreads_condition_signal(spif_pthreads_condition_t);
+extern spif_bool_t spif_pthreads_condition_wait(spif_pthreads_condition_t);
+extern spif_bool_t spif_pthreads_condition_wait_timed(spif_pthreads_condition_t, spif_int32_t);
+SPIF_DECL_PROPERTY_FUNC_C(pthreads_condition, pthread_cond_t, cond);
+
+#endif /* _LIBAST_PTHREADS_H_ */
diff --git a/include/libast/thread_if.h b/include/libast/thread_if.h
new file mode 100644
index 0000000..86654b0
--- /dev/null
+++ b/include/libast/thread_if.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 1997-2004, Michael Jennings
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies of the Software, its documentation and marketing & publicity
+ * materials, and acknowledgment shall be given in the documentation, materials
+ * and software packages that this Software was used.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _LIBAST_THREAD_IF_H_
+#define _LIBAST_THREAD_IF_H_
+
+/*
+ * interface goop
+ */
+
+/* Standard typecast macros.... */
+#define SPIF_THREAD(o) (SPIF_CAST(thread) (o))
+#define SPIF_THREAD_CLASS(o) (SPIF_CAST(threadclass) SPIF_OBJ_CLASS(o))
+
+/* Name of class variable associated with thread interface */
+#define SPIF_THREADCLASS_VAR(type) spif_ ## type ## _threadclass
+
+/* Check if a thread is NULL */
+#define SPIF_THREAD_ISNULL(o) (SPIF_THREAD(o) == SPIF_NULL_TYPE(thread))
+
+/* Check if an object is a thread */
+#define SPIF_OBJ_IS_THREAD(o) SPIF_OBJ_IS_TYPE(o, thread)
+
+/* Call a method on an instance of an implementation class */
+#define SPIF_THREAD_CALL_METHOD(o, meth) SPIF_THREAD_CLASS(o)->meth
+
+/* Calls to the basic functions. */
+#define SPIF_THREAD_NEW(type) SPIF_THREAD((SPIF_CLASS(SPIF_THREADCLASS_VAR(type)))->noo())
+#define SPIF_THREAD_INIT(o) SPIF_OBJ_INIT(o)
+#define SPIF_THREAD_DONE(o) SPIF_OBJ_DONE(o)
+#define SPIF_THREAD_DEL(o) SPIF_OBJ_DEL(o)
+#define SPIF_THREAD_SHOW(o, b, i) SPIF_OBJ_SHOW(o, b, i)
+#define SPIF_THREAD_COMP(o1, o2) SPIF_OBJ_COMP(o1, o2)
+#define SPIF_THREAD_DUP(o) SPIF_OBJ_DUP(o)
+#define SPIF_THREAD_TYPE(o) SPIF_OBJ_TYPE(o)
+
+#define SPIF_THREAD_NEW_WITH_FUNC(type, f, d) SPIF_THREAD((SPIF_CLASS(SPIF_THREADCLASS_VAR(type)))->new_with_func((f), (d)))
+#define SPIF_THREAD_INIT_WITH_FUNC(o, f, d) SPIF_CAST(bool) ((SPIF_THREAD_CALL_METHOD((o), init_with_func))((o), (f), (d)))
+#define SPIF_THREAD_DETACH(o) SPIF_CAST(bool) ((SPIF_THREAD_CALL_METHOD((o), detach))(o))
+#define SPIF_THREAD_GET_CONDITION(o) SPIF_CAST(condition) ((SPIF_THREAD_CALL_METHOD((o), get_condition))())
+#define SPIF_THREAD_GET_MUTEX(o) SPIF_CAST(mutex) ((SPIF_THREAD_CALL_METHOD((o), get_mutex))())
+#define SPIF_THREAD_KILL(o, s) SPIF_CAST(bool) ((SPIF_THREAD_CALL_METHOD((o), kill))((o), (s)))
+#define SPIF_THREAD_RUN(o) SPIF_CAST(bool) ((SPIF_THREAD_CALL_METHOD((o), run))(o))
+#define SPIF_THREAD_TLS_CALLOC(o, c, s) SPIF_CAST(tls_handle) ((SPIF_THREAD_CALL_METHOD((o), tls_calloc))((o), (c), (s)))
+#define SPIF_THREAD_TLS_FREE(o, i) SPIF_CAST(bool) ((SPIF_THREAD_CALL_METHOD((o), tls_free))((o), (i)))
+#define SPIF_THREAD_TLS_GET(o, i) SPIF_CAST(ptr) ((SPIF_THREAD_CALL_METHOD((o), tls_get))((o), (i)))
+#define SPIF_THREAD_TLS_MALLOC(o, s) SPIF_CAST(tls_handle) ((SPIF_THREAD_CALL_METHOD((o), tls_malloc))((o), (s)))
+#define SPIF_THREAD_TLS_REALLOC(o, i, s) SPIF_CAST(bool) ((SPIF_THREAD_CALL_METHOD((o), tls_realloc))((o), (i), (s)))
+#define SPIF_THREAD_WAIT(o, c) SPIF_CAST(bool) ((SPIF_THREAD_CALL_METHOD((o), wait))((o), (c)))
+#define SPIF_THREAD_WAIT_FOR(o, t) SPIF_CAST(bool) ((SPIF_THREAD_CALL_METHOD((o), wait_for))((o), (t)))
+
+typedef spif_obj_t spif_thread_t;
+typedef spif_ptr_t spif_thread_data_t;
+typedef spif_thread_data_t (*spif_thread_func_t)(spif_thread_data_t);
+typedef spif_listidx_t spif_tls_handle_t;
+
+SPIF_DECL_OBJ(threadclass) {
+ SPIF_DECL_PARENT_TYPE(class);
+
+ spif_func_t new_with_func;
+ spif_func_t init_with_func;
+ spif_func_t detach;
+ spif_func_t get_condition;
+ spif_func_t get_mutex;
+ spif_func_t kill;
+ spif_func_t run;
+ spif_func_t tls_calloc;
+ spif_func_t tls_free;
+ spif_func_t tls_get;
+ spif_func_t tls_malloc;
+ spif_func_t tls_realloc;
+ spif_func_t wait;
+ spif_func_t wait_for;
+};
+
+#endif /* _LIBAST_THREAD_IF_H_ */
diff --git a/libast.m4 b/libast.m4
index 19c1ae6..1c75df7 100644
--- a/libast.m4
+++ b/libast.m4
@@ -182,7 +182,7 @@ dnl# LibAST macro for Imlib2 support
dnl#
AC_DEFUN([AST_IMLIB2_SUPPORT], [
AC_ARG_WITH(imlib,
- [ --with-imlib[=DIR] compile with Imlib2 support (default)],
+ [ --with-imlib[=DIR] compile with Imlib2 support (default)],
[
if test "$withval" != "no"; then
if test "$withval" != "yes"; then
@@ -347,7 +347,7 @@ dnl# - arg 1 is the name of the env var to use
dnl#
AC_DEFUN([AST_ARG_DEBUG], [
AC_MSG_CHECKING(for debugging level)
- AC_ARG_WITH(debugging, [ --with-debugging[=num] compile in debugging support. num >= 0], [
+ AC_ARG_WITH(debugging, [ --with-debugging[=num] compile in debugging support. num >= 0], [
if test "$withval" = "yes"; then
withval=4
fi
@@ -368,7 +368,7 @@ AC_DEFUN([AST_ARG_DEBUG], [
])
AC_DEFUN([AST_ARG_REGEXP], [
AC_ARG_WITH(regexp,
- [ --with-regexp[=TYPE] specify the type of regular expression support (bsd, posix, pcre)],
+ [ --with-regexp[=TYPE] specify the type of regular expression support (bsd, posix, pcre)],
[$1=$withval], [$1=yes])
AST_REGEXP_SUPPORT($1)
AC_MSG_CHECKING(for regular expression support)
@@ -377,7 +377,7 @@ AC_DEFUN([AST_ARG_REGEXP], [
AC_DEFUN([AST_ARG_BACKQUOTE_EXEC], [
AC_MSG_CHECKING(if backquote execution support should be enabled)
AC_ARG_WITH(backquote-exec,
- [ --without-backquote-exec disables the execution of commands from inside config files],
+ [ --without-backquote-exec disables the execution of commands from inside config files],
[
if test "$withval" = "no"; then
AC_MSG_RESULT(no)
@@ -688,3 +688,195 @@ exit(1);
AC_MSG_RESULT([unknown, assuming none])
fi
])
+
+dnl# Taken from http://autoconf-archive.cryp.to/acx_pthread.html
+AC_DEFUN([AST_PTHREADS], [
+AC_REQUIRE([AC_CANONICAL_HOST])
+AC_LANG_SAVE
+AC_LANG_C
+ast_pthreads_ok=no
+
+# We used to check for pthread.h first, but this fails if pthread.h
+# requires special compiler flags (e.g. on True64 or Sequent).
+# It gets checked for in the link test anyway.
+
+# First of all, check if the user has set any of the PTHREAD_LIBS,
+# etcetera environment variables, and if threads linking works using
+# them:
+if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ save_LIBS="$LIBS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
+ AC_TRY_LINK_FUNC(pthread_join, ast_pthreads_ok=yes)
+ AC_MSG_RESULT($ast_pthreads_ok)
+ if test x"$ast_pthreads_ok" = xno; then
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+ fi
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+fi
+
+# We must check for the threads library under a number of different
+# names; the ordering is very important because some systems
+# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
+# libraries is broken (non-POSIX).
+
+# Create a list of thread flags to try. Items starting with a "-" are
+# C compiler flags, and other items are library names, except for "none"
+# which indicates that we try without any flags at all, and "pthread-config"
+# which is a program returning the flags for the Pth emulation library.
+
+ast_pthreads_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
+
+# The ordering *is* (sometimes) important. Some notes on the
+# individual items follow:
+
+# pthreads: AIX (must check this before -lpthread)
+# none: in case threads are in libc; should be tried before -Kthread and
+# other compiler flags to prevent continual compiler warnings
+# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
+# -pthreads: Solaris/gcc
+# -mthreads: Mingw32/gcc, Lynx/gcc
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+# doesn't hurt to check since this sometimes defines pthreads too;
+# also defines -D_REENTRANT)
+# ... -mt is also the pthreads flag for HP/aCC
+# pthread: Linux, etcetera
+# --thread-safe: KAI C++
+# pthread-config: use pthread-config program (for GNU Pth library)
+
+case "${host_cpu}-${host_os}" in
+ *solaris*)
+
+ # On Solaris (at least, for some versions), libc contains stubbed
+ # (non-functional) versions of the pthreads routines, so link-based
+ # tests will erroneously succeed. (We need to link with -pthreads/-mt/
+ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
+ # a function called by this macro, so we could check for that, but
+ # who knows whether they'll stub that too in a future libc.) So,
+ # we'll just look for -pthreads and -lpthread first:
+
+ ast_pthreads_flags="-pthreads pthread -mt -pthread $ast_pthreads_flags"
+ ;;
+esac
+
+if test x"$ast_pthreads_ok" = xno; then
+for flag in $ast_pthreads_flags; do
+
+ case $flag in
+ none)
+ AC_MSG_CHECKING([whether pthreads work without any flags])
+ ;;
+
+ -*)
+ AC_MSG_CHECKING([whether pthreads work with $flag])
+ PTHREAD_CFLAGS="$flag"
+ ;;
+
+ pthread-config)
+ AC_CHECK_PROG(ast_pthreads_config, pthread-config, yes, no)
+ if test x"$ast_pthreads_config" = xno; then continue; fi
+ PTHREAD_CFLAGS="`pthread-config --cflags`"
+ PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+ ;;
+
+ *)
+ AC_MSG_CHECKING([for the pthreads library -l$flag])
+ PTHREAD_LIBS="-l$flag"
+ ;;
+ esac
+
+ save_LIBS="$LIBS"
+ save_CFLAGS="$CFLAGS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+ # Check for various functions. We must include pthread.h,
+ # since some functions may be macros. (On the Sequent, we
+ # need a special flag -Kthread to make this header compile.)
+ # We check for pthread_join because it is in -lpthread on IRIX
+ # while pthread_create is in libc. We check for pthread_attr_init
+ # due to DEC craziness with -lpthreads. We check for
+ # pthread_cleanup_push because it is one of the few pthread
+ # functions on Solaris that doesn't have a non-functional libc stub.
+ # We try pthread_create on general principles.
+ AC_TRY_LINK([#include <pthread.h>],
+ [pthread_t th; pthread_join(th, 0);
+ pthread_attr_init(0); pthread_cleanup_push(0, 0);
+ pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
+ [ast_pthreads_ok=yes])
+
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+
+ AC_MSG_RESULT($ast_pthreads_ok)
+ if test "x$ast_pthreads_ok" = xyes; then
+ break;
+ fi
+
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+done
+fi
+
+# Various other checks:
+if test "x$ast_pthreads_ok" = xyes; then
+ save_LIBS="$LIBS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+ # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
+ AC_MSG_CHECKING([for joinable pthread attribute])
+ attr_name=unknown
+ for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+ AC_TRY_LINK([#include <pthread.h>], [int attr=$attr; return attr;],
+ [attr_name=$attr; break])
+ done
+ AC_MSG_RESULT($attr_name)
+ if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
+ AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
+ [Define to necessary symbol if this constant
+ uses a non-standard name on your system.])
+ fi
+
+ AC_MSG_CHECKING([if more special flags are required for pthreads])
+ flag=no
+ case "${host_cpu}-${host_os}" in
+ *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";;
+ *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";;
+ esac
+ AC_MSG_RESULT(${flag})
+ if test "x$flag" != xno; then
+ PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
+ fi
+
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+
+ # More AIX lossage: must compile with cc_r
+ AC_CHECK_PROG(PTHREAD_CC, cc_r, cc_r, ${CC})
+else
+ PTHREAD_CC="$CC"
+fi
+
+AC_SUBST(PTHREAD_LIBS)
+AC_SUBST(PTHREAD_CFLAGS)
+AC_SUBST(PTHREAD_CC)
+
+# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+if test x"$ast_pthreads_ok" = xyes; then
+ ifelse([$1],,AC_DEFINE(HAVE_PTHREADS,1,[Define if you have POSIX threads libraries and header files.]),[$1])
+ :
+else
+ ast_pthreads_ok=no
+ $2
+fi
+AC_LANG_RESTORE
+])dnl AST_PTHREADS
diff --git a/src/Makefile.am b/src/Makefile.am
index 583cd55..c8ecfaf 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -3,11 +3,13 @@
lib_LTLIBRARIES = libast.la
INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/include/$(PACKAGE)
+AM_CFLAGS = $(PTHREAD_CFLAGS)
+AM_LDFLAGS = $(PTHREAD_LIBS)
-libast_la_SOURCES = \
- array.c builtin_hashes.c conf.c debug.c dlinked_list.c file.c \
- linked_list.c mbuff.c mem.c msgs.c obj.c objpair.c options.c \
- regexp.c socket.c str.c strings.c snprintf.c tok.c url.c ustr.c
+libast_la_SOURCES = array.c builtin_hashes.c conf.c debug.c \
+dlinked_list.c file.c linked_list.c mbuff.c mem.c module.c msgs.c \
+obj.c objpair.c options.c pthreads.c regexp.c socket.c str.c strings.c \
+snprintf.c tok.c url.c ustr.c
-libast_la_LDFLAGS = -version-info 2:1:0
+libast_la_LDFLAGS = -version-info 2:2:0
MAINTAINERCLEANFILES = Makefile.in
diff --git a/src/array.c b/src/array.c
index 09fb59e..c432efd 100644
--- a/src/array.c
+++ b/src/array.c
@@ -728,7 +728,6 @@ spif_array_remove(spif_array_t self, spif_obj_t item)
}
left = self->len - i - 1;
- printf("%d %d %d\n", i, left, self->len);
tmp = self->items[i];
memmove(self->items + i, self->items + i + 1, sizeof(spif_obj_t) * left);
self->len--;
diff --git a/src/module.c b/src/module.c
new file mode 100644
index 0000000..19819ca
--- /dev/null
+++ b/src/module.c
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 1997-2004, Michael Jennings
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies of the Software, its documentation and marketing & publicity
+ * materials, and acknowledgment shall be given in the documentation, materials
+ * and software packages that this Software was used.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+static const char __attribute__((unused)) cvs_ident[] = "$Id$";
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <libast_internal.h>
+#include <dlfcn.h>
+
+/* *INDENT-OFF* */
+static SPIF_CONST_TYPE(moduleclass) s_class = {
+ {
+ SPIF_DECL_CLASSNAME(module),
+ (spif_func_t) spif_module_new,
+ (spif_func_t) spif_module_init,
+ (spif_func_t) spif_module_done,
+ (spif_func_t) spif_module_del,
+ (spif_func_t) spif_module_show,
+ (spif_func_t) spif_module_comp,
+ (spif_func_t) spif_module_dup,
+ (spif_func_t) spif_module_type
+ },
+ (spif_func_t) spif_module_call,
+ (spif_func_t) spif_module_getsym,
+ (spif_func_t) spif_module_load,
+ (spif_func_t) spif_module_run,
+ (spif_func_t) spif_module_unload,
+};
+SPIF_TYPE(class) SPIF_CLASS_VAR(module) = SPIF_CAST(class) &s_class;
+SPIF_TYPE(moduleclass) SPIF_MODULECLASS_VAR(module) = &s_class;
+/* *INDENT-ON* */
+
+static const size_t buff_inc = 4096;
+
+spif_module_t
+spif_module_new(void)
+{
+ spif_module_t self;
+
+ self = SPIF_ALLOC(module);
+ if (!spif_module_init(self)) {
+ SPIF_DEALLOC(self);
+ self = SPIF_NULL_TYPE(module);
+ }
+ return self;
+}
+
+spif_bool_t
+spif_module_init(spif_module_t self)
+{
+ ASSERT_RVAL(!SPIF_MODULE_ISNULL(self), FALSE);
+ /* ***NOT NEEDED*** spif_obj_init(SPIF_OBJ(self)); */
+ spif_obj_set_class(SPIF_OBJ(self), SPIF_CLASS(SPIF_MODULECLASS_VAR(module)));
+ self->name = SPIF_NULL_TYPE(str);
+ self->path = SPIF_NULL_TYPE(str);
+ self->module_handle = SPIF_NULL_TYPE(ptr);
+ self->main_handle = dlopen(NULL, RTLD_LAZY);
+ return TRUE;
+}
+
+spif_bool_t
+spif_module_done(spif_module_t self)
+{
+ spif_bool_t ret = TRUE;
+
+ ASSERT_RVAL(!SPIF_MODULE_ISNULL(self), FALSE);
+ if (self->module_handle) {
+ ret = spif_module_unload(self);
+ self->module_handle = SPIF_NULL_TYPE(ptr);
+ }
+ if (!SPIF_STR_ISNULL(self->name)) {
+ spif_str_del(self->name);
+ self->name = SPIF_NULL_TYPE(str);
+ }
+ if (!SPIF_STR_ISNULL(self->path)) {
+ spif_str_del(self->path);
+ self->path = SPIF_NULL_TYPE(str);
+ }
+ return ret;
+}
+
+spif_bool_t
+spif_module_del(spif_module_t self)
+{
+ ASSERT_RVAL(!SPIF_MODULE_ISNULL(self), FALSE);
+ spif_module_done(self);
+ dlclose(self->main_handle);
+ SPIF_DEALLOC(self);
+ return TRUE;
+}
+
+spif_str_t
+spif_module_show(spif_module_t self, spif_charptr_t name, spif_str_t buff, size_t indent)
+{
+ spif_char_t tmp[4096];
+
+ if (SPIF_MODULE_ISNULL(self)) {
+ SPIF_OBJ_SHOW_NULL(module, name, buff, indent, tmp);
+ return buff;
+ }
+
+ memset(tmp, ' ', indent);
+ snprintf(SPIF_CHARPTR_C(tmp) + indent, sizeof(tmp) - indent,
+ "(spif_module_t) %s: %10p { \"",
+ name, SPIF_CAST(ptr) self);
+ if (SPIF_STR_ISNULL(buff)) {
+ buff = spif_str_new_from_ptr(tmp);
+ } else {
+ spif_str_append_from_ptr(buff, tmp);
+ }
+
+ indent += 2;
+ if (indent < sizeof(tmp)) {
+ memset(tmp, ' ', indent);
+ }
+ buff = spif_str_show(self->name, SPIF_CHARPTR("name"), buff, indent);
+ buff = spif_str_show(self->path, SPIF_CHARPTR("path"), buff, indent);
+ snprintf(SPIF_CHARPTR_C(tmp) + indent, sizeof(tmp) - indent, "(spif_ptr_t) module_handle: 0x%p\n", self->module_handle);
+ spif_str_append_from_ptr(buff, tmp);
+
+ snprintf(SPIF_CHARPTR_C(tmp) + indent, sizeof(tmp) - indent, "(spif_ptr_t) main_handle: 0x%p\n", self->main_handle);
+ spif_str_append_from_ptr(buff, tmp);
+
+ snprintf(SPIF_CHARPTR_C(tmp), sizeof(tmp), "}\n");
+ spif_str_append_from_ptr(buff, tmp);
+ return buff;
+}
+
+spif_cmp_t
+spif_module_comp(spif_module_t self, spif_module_t other)
+{
+ spif_cmp_t ret;
+
+ SPIF_OBJ_COMP_CHECK_NULL(self, other);
+ SPIF_OBJ_COMP_CHECK_NULL(self->name, other->name);
+ if (!SPIF_CMP_IS_EQUAL(ret = spif_str_comp(self->name, other->name))) {
+ return ret;
+ }
+ SPIF_OBJ_COMP_CHECK_NULL(self->path, other->path);
+ if (!SPIF_CMP_IS_EQUAL(ret = spif_str_comp(self->path, other->path))) {
+ return ret;
+ }
+ return SPIF_CMP_FROM_INT((int) self->module_handle - (int) other->module_handle);
+}
+
+spif_module_t
+spif_module_dup(spif_module_t self)
+{
+ spif_module_t tmp;
+
+ ASSERT_RVAL(!SPIF_MODULE_ISNULL(self), SPIF_NULL_TYPE(module));
+ tmp = SPIF_ALLOC(module);
+ memcpy(tmp, self, SPIF_SIZEOF_TYPE(module));
+ tmp->name = spif_str_dup(self->name);
+ tmp->path = spif_str_dup(self->path);
+ return tmp;
+}
+
+spif_classname_t
+spif_module_type(spif_module_t self)
+{
+ ASSERT_RVAL(!SPIF_MODULE_ISNULL(self), SPIF_CAST(classname) SPIF_NULLSTR_TYPE(classname));
+ return SPIF_OBJ_CLASSNAME(self);
+}
+
+spif_ptr_t
+spif_module_call(spif_module_t self, spif_charptr_t fname, spif_ptr_t data)
+{
+ spif_func_t fp;
+ spif_charptr_t err;
+
+ fp = SPIF_CAST(func) spif_module_getsym(self, fname);
+ if (SPIF_PTR_ISNULL(err)) {
+ /* No error. Proceed. */
+ return (fp)(data);
+ } else {
+ libast_print_warning("Unable to call function %s() from module \"%s\" -- %s\n", fname, SPIF_STR_STR(self->name), err);
+ }
+ return SPIF_NULL_TYPE(ptr);
+}
+
+spif_ptr_t
+spif_module_getsym(spif_module_t self, spif_charptr_t sym)
+{
+ spif_ptr_t psym;
+ spif_charptr_t err;
+
+ ASSERT_RVAL(!SPIF_MODULE_ISNULL(self), SPIF_NULL_TYPE(ptr));
+ ASSERT_RVAL(!SPIF_PTR_ISNULL(sym), SPIF_NULL_TYPE(ptr));
+ REQUIRE_RVAL(!SPIF_PTR_ISNULL(self->main_handle), SPIF_NULL_TYPE(ptr));
+ dlerror();
+ psym = SPIF_CAST(ptr) dlsym(self->module_handle, (const char *) sym);
+ err = SPIF_CAST(charptr) dlerror();
+ if (SPIF_PTR_ISNULL(err)) {
+ /* No error. Proceed. */
+ return psym;
+ } else {
+ psym = SPIF_CAST(ptr) dlsym(self->main_handle, (const char *) sym);
+ err = SPIF_CAST(charptr) dlerror();
+ if (SPIF_PTR_ISNULL(err)) {
+ /* No error. Proceed. */
+ return psym;
+ } else {
+#ifdef RTLD_DEFAULT
+ psym = SPIF_CAST(ptr) dlsym(RTLD_DEFAULT, (const char *) sym);
+ err = SPIF_CAST(charptr) dlerror();
+ if (SPIF_PTR_ISNULL(err)) {
+ /* No error. Proceed. */
+ return psym;
+ } else
+#endif
+ libast_print_warning("Unable to resolve symbol \"%s\" from module \"%s\" -- %s\n", sym,
+ SPIF_STR_STR(self->name), err);
+ }
+ }
+ return SPIF_NULL_TYPE(ptr);
+}
+
+spif_bool_t
+spif_module_load(spif_module_t self)
+{
+ spif_func_t fp;
+
+ ASSERT_RVAL(!SPIF_MODULE_ISNULL(self), FALSE);
+ REQUIRE_RVAL(!SPIF_STR_ISNULL(self->path), FALSE);
+
+ if (SPIF_STR_ISNULL(self->name)) {
+ spif_stridx_t idx;
+
+ idx = spif_str_rindex(self->path, '/');
+ if (idx == spif_str_get_len(self->path)) {
+ self->name = spif_str_dup(self->path);
+ } else {
+ self->name = spif_str_substr(self->path, idx, 0);
+ }
+ }
+
+ self->module_handle = dlopen(SPIF_STR_STR(self->path), RTLD_LAZY | RTLD_GLOBAL);
+ if (SPIF_PTR_ISNULL(self->module_handle)) {
+ libast_print_error("Unable to dlopen() \"%s\" -- %s\n", SPIF_STR_STR(self->path), dlerror());
+ return FALSE;
+ }
+ fp = spif_module_getsym(self, "init");
+ if (fp) {
+ return (((fp)(self)) ? (TRUE) : (FALSE));
+ } else {
+ return TRUE;
+ }
+}
+
+spif_bool_t
+spif_module_run(spif_module_t self)
+{
+ return ((spif_module_call(self, "run", NULL)) ? (TRUE) : (FALSE));
+}
+
+spif_bool_t
+spif_module_unload(spif_module_t self)
+{
+ spif_func_t fp;
+
+ ASSERT_RVAL(!SPIF_MODULE_ISNULL(self), FALSE);
+ REQUIRE_RVAL(!SPIF_PTR_ISNULL(self->module_handle), FALSE);
+
+ fp = spif_module_getsym(self, "done");
+ if (fp) {
+ if (!(fp)()) {
+ return FALSE;
+ }
+ }
+
+ dlerror();
+ if (dlclose(self->module_handle)) {
+ libast_print_warning("Unable to dlclose() \"%s\" -- %s\n", SPIF_STR_STR(self->path), dlerror());
+ return FALSE;
+ }
+ self->module_handle = SPIF_NULL_TYPE(ptr);
+ return TRUE;
+}
+
+SPIF_DEFINE_PROPERTY_FUNC(module, str, name);
+SPIF_DEFINE_PROPERTY_FUNC(module, str, path);
+SPIF_DEFINE_PROPERTY_FUNC(module, ptr, module_handle);
+SPIF_DEFINE_PROPERTY_FUNC(module, ptr, main_handle);
diff --git a/src/msgs.c b/src/msgs.c
index 83e37c8..9fec44a 100644
--- a/src/msgs.c
+++ b/src/msgs.c
@@ -61,6 +61,14 @@ spif_charptr_t libast_program_name = SPIF_CAST(charptr) PACKAGE;
spif_charptr_t libast_program_version = SPIF_CAST(charptr) VERSION;
/**
+ * Silence mode
+ *
+ * This variable determines whether or not error, warning, and
+ * debugging messages may be printed.
+ */
+static spif_bool_t silent = FALSE;
+
+/**
* Sets the program name.
*
* This function is provided for safe and sane setting of the
@@ -119,6 +127,22 @@ libast_set_program_version(const char *progversion)
}
/**
+ * Sets silent mode.
+ *
+ * This function turns on/off error, warning, and debugging output.
+ *
+ * @param flag Boolean value to set silent flag
+ * @return The new value
+ *
+ * @see silent
+ */
+spif_bool_t
+libast_set_silent(spif_bool_t flag)
+{
+ return (silent = flag);
+}
+
+/**
* Prints debugging output.
*
* This function is the guts behing the D_*() and DPRINTF() families of
@@ -140,6 +164,7 @@ libast_dprintf(const char *format, ...)
int n;
ASSERT_RVAL(!SPIF_PTR_ISNULL(format), SPIF_CAST_C(int) -1);
+ REQUIRE_RVAL(!silent, 0);
REQUIRE_RVAL(libast_program_name != NULL, 0);
va_start(args, format);
n = vfprintf(LIBAST_DEBUG_FD, format, args);
@@ -168,6 +193,7 @@ libast_print_error(const char *fmt, ...)
va_list arg_ptr;
ASSERT(!SPIF_PTR_ISNULL(fmt));
+ REQUIRE(!silent);
REQUIRE(libast_program_name != NULL);
va_start(arg_ptr, fmt);
fprintf(stderr, "%s: Error: ", libast_program_name);
@@ -195,6 +221,7 @@ libast_print_warning(const char *fmt, ...)
va_list arg_ptr;
ASSERT(!SPIF_PTR_ISNULL(fmt));
+ REQUIRE(!silent);
REQUIRE(libast_program_name != NULL);
va_start(arg_ptr, fmt);
fprintf(stderr, "%s: Warning: ", libast_program_name);
@@ -222,7 +249,7 @@ libast_fatal_error(const char *fmt, ...)
va_list arg_ptr;
ASSERT(!SPIF_PTR_ISNULL(fmt));
- if (libast_program_name != NULL) {
+ if ((!silent) && (libast_program_name != NULL)) {
va_start(arg_ptr, fmt);
fprintf(stderr, "%s: FATAL: ", libast_program_name);
vfprintf(stderr, fmt, arg_ptr);
@@ -230,3 +257,4 @@ libast_fatal_error(const char *fmt, ...)
}
exit(-1);
}
+
diff --git a/src/pthreads.c b/src/pthreads.c
new file mode 100644
index 0000000..5cebf09
--- /dev/null
+++ b/src/pthreads.c
@@ -0,0 +1,733 @@
+/*
+ * Copyright (C) 1997-2004, Michael Jennings
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies of the Software, its documentation and marketing & publicity
+ * materials, and acknowledgment shall be given in the documentation, materials
+ * and software packages that this Software was used.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+static const char __attribute__((unused)) cvs_ident[] = "$Id$";
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <libast_internal.h>
+#include <pthread.h>
+
+/* *INDENT-OFF* */
+static SPIF_CONST_TYPE(threadclass) pt_class = {
+ {
+ SPIF_DECL_CLASSNAME(pthreads),
+ (spif_func_t) spif_pthreads_new,
+ (spif_func_t) spif_pthreads_init,
+ (spif_func_t) spif_pthreads_done,
+ (spif_func_t) spif_pthreads_del,
+ (spif_func_t) spif_pthreads_show,
+ (spif_func_t) spif_pthreads_comp,
+ (spif_func_t) spif_pthreads_dup,
+ (spif_func_t) spif_pthreads_type
+ },
+ (spif_func_t) spif_pthreads_new_with_func,
+ (spif_func_t) spif_pthreads_init_with_func,
+ (spif_func_t) spif_pthreads_detach,
+ (spif_func_t) spif_pthreads_get_condition,
+ (spif_func_t) spif_pthreads_get_mutex,
+ (spif_func_t) spif_pthreads_kill,
+ (spif_func_t) spif_pthreads_run,
+ (spif_func_t) spif_pthreads_tls_calloc,
+ (spif_func_t) spif_pthreads_tls_free,
+ (spif_func_t) spif_pthreads_tls_get,
+ (spif_func_t) spif_pthreads_tls_malloc,
+ (spif_func_t) spif_pthreads_tls_realloc,
+ (spif_func_t) spif_pthreads_wait,
+ (spif_func_t) spif_pthreads_wait_for
+};
+SPIF_TYPE(class) SPIF_CLASS_VAR(pthreads) = SPIF_CAST(class) &pt_class;
+SPIF_TYPE(threadclass) SPIF_THREADCLASS_VAR(pthreads) = &pt_class;
+
+static SPIF_CONST_TYPE(mutexclass) ptm_class = {
+ {
+ SPIF_DECL_CLASSNAME(pthreads_mutex),
+ (spif_func_t) spif_pthreads_mutex_new,
+ (spif_func_t) spif_pthreads_mutex_init,
+ (spif_func_t) spif_pthreads_mutex_done,
+ (spif_func_t) spif_pthreads_mutex_del,
+ (spif_func_t) spif_pthreads_mutex_show,
+ (spif_func_t) spif_pthreads_mutex_comp,
+ (spif_func_t) spif_pthreads_mutex_dup,
+ (spif_func_t) spif_pthreads_mutex_type
+ },
+ (spif_func_t) spif_pthreads_mutex_lock,
+ (spif_func_t) spif_pthreads_mutex_lock_nowait,
+ (spif_func_t) spif_pthreads_mutex_unlock
+};
+SPIF_TYPE(class) SPIF_CLASS_VAR(pthreads_mutex) = SPIF_CAST(class) &ptm_class;
+SPIF_TYPE(mutexclass) SPIF_MUTEXCLASS_VAR(pthreads_mutex) = &ptm_class;
+
+static SPIF_CONST_TYPE(conditionclass) ptc_class = {
+ {
+ SPIF_DECL_CLASSNAME(pthreads_condition),
+ (spif_func_t) spif_pthreads_condition_new,
+ (spif_func_t) spif_pthreads_condition_init,
+ (spif_func_t) spif_pthreads_condition_done,
+ (spif_func_t) spif_pthreads_condition_del,
+ (spif_func_t) spif_pthreads_condition_show,
+ (spif_func_t) spif_pthreads_condition_comp,
+ (spif_func_t) spif_pthreads_condition_dup,
+ (spif_func_t) spif_pthreads_condition_type
+ },
+ (spif_func_t) spif_pthreads_condition_broadcast,
+ (spif_func_t) spif_pthreads_condition_signal,
+ (spif_func_t) spif_pthreads_condition_wait,
+ (spif_func_t) spif_pthreads_condition_wait_timed
+};
+SPIF_TYPE(class) SPIF_CLASS_VAR(pthreads_condition) = SPIF_CAST(class) &ptc_class;
+SPIF_TYPE(conditionclass) SPIF_CONDITIONCLASS_VAR(pthreads_condition) = &ptc_class;
+/* *INDENT-ON* */
+
+static void spif_pthreads_tls_destructor(void *ptr);
+
+spif_pthreads_t
+spif_pthreads_new(void)
+{
+ spif_pthreads_t self;
+
+ self = SPIF_ALLOC(pthreads);
+ if (!spif_pthreads_init(self)) {
+ SPIF_DEALLOC(self);
+ self = SPIF_NULL_TYPE(pthreads);
+ }
+ return self;
+}
+
+spif_pthreads_t
+spif_pthreads_new_with_func(spif_thread_func_t func, spif_thread_data_t data)
+{
+ spif_pthreads_t self;
+
+ self = SPIF_ALLOC(pthreads);
+ if (!spif_pthreads_init_with_func(self, func, data)) {
+ SPIF_DEALLOC(self);
+ self = SPIF_NULL_TYPE(pthreads);
+ }
+ return self;
+}
+
+spif_bool_t
+spif_pthreads_init(spif_pthreads_t self)
+{
+ ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), FALSE);
+ /* ***NOT NEEDED*** spif_obj_init(SPIF_OBJ(self)); */
+ spif_obj_set_class(SPIF_OBJ(self), SPIF_CLASS(SPIF_THREADCLASS_VAR(pthreads)));
+ self->handle = (pthread_t) 0;
+ self->creator = (pthread_t) 0;
+ pthread_attr_init(&self->attr);
+ self->main_func = SPIF_NULL_TYPE(thread_func);
+ self->data = SPIF_NULL_TYPE(thread_data);
+ self->tls_keys = SPIF_NULL_TYPE(list);
+ return TRUE;
+}
+
+spif_bool_t
+spif_pthreads_init_with_func(spif_pthreads_t self, spif_thread_func_t func, spif_thread_data_t data)
+{
+ ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), FALSE);
+ /* ***NOT NEEDED*** spif_obj_init(SPIF_OBJ(self)); */
+ spif_obj_set_class(SPIF_OBJ(self), SPIF_CLASS(SPIF_THREADCLASS_VAR(pthreads)));
+ self->handle = (pthread_t) 0;
+ self->creator = (pthread_t) 0;
+ pthread_attr_init(&self->attr);
+ self->main_func = func;
+ self->data = data;
+ self->tls_keys = SPIF_NULL_TYPE(list);
+ return TRUE;
+}
+
+spif_bool_t
+spif_pthreads_done(spif_pthreads_t self)
+{
+ spif_bool_t ret = TRUE;
+
+ ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), FALSE);
+ if (self->handle) {
+ spif_pthreads_kill(self, SIGTERM);
+ self->handle = (pthread_t) 0;
+ }
+ self->creator = pthread_self();
+ pthread_attr_destroy(&self->attr);
+ pthread_attr_init(&self->attr);
+ self->main_func = SPIF_NULL_TYPE(thread_func);
+ if (self->tls_keys) {
+ SPIF_LIST_DEL(self->tls_keys);
+ self->tls_keys = SPIF_NULL_TYPE(list);
+ }
+ return ret;
+}
+
+spif_bool_t
+spif_pthreads_del(spif_pthreads_t self)
+{
+ ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), FALSE);
+ spif_pthreads_done(self);
+ SPIF_DEALLOC(self);
+ return TRUE;
+}
+
+spif_str_t
+spif_pthreads_show(spif_pthreads_t self, spif_charptr_t name, spif_str_t buff, size_t indent)
+{
+ spif_char_t tmp[4096];
+
+ if (SPIF_PTHREADS_ISNULL(self)) {
+ SPIF_OBJ_SHOW_NULL(pthreads, name, buff, indent, tmp);
+ return buff;
+ }
+
+ memset(tmp, ' ', indent);
+ snprintf(SPIF_CHARPTR_C(tmp) + indent, sizeof(tmp) - indent,
+ "(spif_pthreads_t) %s: %10p { \"",
+ name, SPIF_CAST(ptr) self);
+ if (SPIF_STR_ISNULL(buff)) {
+ buff = spif_str_new_from_ptr(tmp);
+ } else {
+ spif_str_append_from_ptr(buff, tmp);
+ }
+
+ indent += 2;
+ if (indent < sizeof(tmp)) {
+ memset(tmp, ' ', indent);
+ }
+ snprintf(SPIF_CHARPTR_C(tmp) + indent, sizeof(tmp) - indent, "(pthread_t) handle: %ld\n", (long) self->handle);
+ spif_str_append_from_ptr(buff, tmp);
+
+ snprintf(SPIF_CHARPTR_C(tmp) + indent, sizeof(tmp) - indent, "(pthread_t) creator: %ld\n", (long) self->creator);
+ spif_str_append_from_ptr(buff, tmp);
+
+ snprintf(SPIF_CHARPTR_C(tmp) + indent, sizeof(tmp) - indent, "(pthread_attr_t) attr: %10p {...}\n", &self->attr);
+ spif_str_append_from_ptr(buff, tmp);
+
+ snprintf(SPIF_CHARPTR_C(tmp) + indent, sizeof(tmp) - indent, "(spif_thread_func_t) main_func: %10p\n", self->main_func);
+ spif_str_append_from_ptr(buff, tmp);
+
+ snprintf(SPIF_CHARPTR_C(tmp) + indent, sizeof(tmp) - indent, "(spif_thread_data_t) data: %10p\n", self->data);
+ spif_str_append_from_ptr(buff, tmp);
+
+ if (SPIF_LIST_ISNULL(self->tls_keys)) {
+ SPIF_OBJ_SHOW_NULL(list, "tls_keys", buff, indent, tmp);
+ } else {
+ buff = SPIF_LIST_SHOW(self->tls_keys, buff, indent);
+ }
+
+ snprintf(SPIF_CHARPTR_C(tmp), sizeof(tmp), "}\n");
+ spif_str_append_from_ptr(buff, tmp);
+ return buff;
+}
+
+spif_cmp_t
+spif_pthreads_comp(spif_pthreads_t self, spif_pthreads_t other)
+{
+ SPIF_OBJ_COMP_CHECK_NULL(self, other);
+ if (pthread_equal(self->handle, other->handle)) {
+ return SPIF_CMP_EQUAL;
+ }
+ return SPIF_OBJ_COMP(self, other);
+}
+
+spif_pthreads_t
+spif_pthreads_dup(spif_pthreads_t self)
+{
+ spif_pthreads_t tmp;
+
+ ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), SPIF_NULL_TYPE(pthreads));
+ tmp = SPIF_ALLOC(pthreads);
+ memcpy(tmp, self, SPIF_SIZEOF_TYPE(pthreads));
+ tmp->tls_keys = SPIF_LIST_DUP(self->tls_keys);
+ return tmp;
+}
+
+spif_classname_t
+spif_pthreads_type(spif_pthreads_t self)
+{
+ ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), SPIF_CAST(classname) SPIF_NULLSTR_TYPE(classname));
+ return SPIF_OBJ_CLASSNAME(self);
+}
+
+spif_bool_t
+spif_pthreads_detach(spif_pthreads_t self)
+{
+ int ret;
+
+ ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), FALSE);
+ REQUIRE_RVAL(self->handle, FALSE);
+
+ ret = pthread_detach(self->handle);
+ if (!ret) {
+ return TRUE;
+ } else if ((errno == EINVAL) || (ret == EINVAL)) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+spif_condition_t
+spif_pthreads_get_condition(spif_pthreads_t self)
+{
+ spif_pthreads_condition_t cond;
+
+ ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), SPIF_NULL_TYPE(condition));
+ cond = spif_pthreads_condition_new();
+ spif_pthreads_mutex_set_creator(SPIF_PTHREADS_MUTEX(cond), SPIF_THREAD(self));
+ return SPIF_CAST(condition) cond;
+}
+
+spif_mutex_t
+spif_pthreads_get_mutex(spif_pthreads_t self)
+{
+ spif_pthreads_mutex_t mutex;
+
+ ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), SPIF_NULL_TYPE(mutex));
+ mutex = spif_pthreads_mutex_new();
+ spif_pthreads_mutex_set_creator(mutex, SPIF_THREAD(self));
+ return SPIF_CAST(mutex) mutex;
+}
+
+spif_bool_t
+spif_pthreads_kill(spif_pthreads_t self, int sig)
+{
+ ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), FALSE);
+ REQUIRE_RVAL(self->handle, FALSE);
+
+ return ((pthread_kill(self->handle, sig)) ? (FALSE) : (TRUE));
+}
+
+spif_bool_t
+spif_pthreads_run(spif_pthreads_t self)
+{
+ ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), FALSE);
+ REQUIRE_RVAL(self->main_func != SPIF_NULL_TYPE(thread_func), FALSE);
+ REQUIRE_RVAL(self->handle == (pthread_t) 0, FALSE);
+
+ if (!pthread_create(&self->handle, &self->attr, self->main_func, self)) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+spif_tls_handle_t
+spif_pthreads_tls_calloc(spif_pthreads_t self, size_t count, size_t size)
+{
+ spif_tls_handle_t handle;
+ spif_ptr_t data;
+
+ ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), SPIF_CAST(tls_handle) -1);
+ REQUIRE_RVAL(count, SPIF_CAST(tls_handle) -1);
+ REQUIRE_RVAL(size, SPIF_CAST(tls_handle) -1);
+
+ handle = spif_pthreads_tls_malloc(self, count * size);
+ data = spif_pthreads_tls_get(self, handle);
+ MEMSET(data, 0, count * size);
+ return handle;
+}
+
+spif_bool_t
+spif_pthreads_tls_free(spif_pthreads_t self, spif_tls_handle_t handle)
+{
+ spif_mbuff_t key;
+
+ ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), FALSE);
+ REQUIRE_RVAL(!SPIF_LIST_ISNULL(self->tls_keys), FALSE);
+
+ key = SPIF_CAST(mbuff) SPIF_LIST_REMOVE_AT(self->tls_keys, handle);
+ if (handle != SPIF_LIST_COUNT(self->tls_keys)) {
+ /* If this isn't the last item in our list, insert an empty placeholder
+ so that numeric indexes which have already been given out will remain valid. */
+ SPIF_LIST_INSERT_AT(self->tls_keys, SPIF_NULL_TYPE(obj), handle);
+ }
+ if (!SPIF_MBUFF_ISNULL(key)) {
+ spif_ptr_t ptr;
+
+ ptr = SPIF_CAST(ptr) pthread_getspecific(*((pthread_key_t *) SPIF_MBUFF_BUFF(key)));
+ if (ptr && !pthread_key_delete(*((pthread_key_t *) SPIF_MBUFF_BUFF(key)))) {
+ FREE(ptr);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+spif_ptr_t
+spif_pthreads_tls_get(spif_pthreads_t self, spif_tls_handle_t handle)
+{
+ spif_mbuff_t key;
+
+ ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), SPIF_NULL_TYPE(ptr));
+ REQUIRE_RVAL(!SPIF_LIST_ISNULL(self->tls_keys), FALSE);
+
+ key = SPIF_CAST(mbuff) SPIF_LIST_GET(self->tls_keys, handle);
+ if (!SPIF_MBUFF_ISNULL(key)) {
+ return (SPIF_CAST(ptr) pthread_getspecific(*((pthread_key_t *) SPIF_MBUFF_BUFF(key))));
+ }
+ return SPIF_NULL_TYPE(ptr);
+}
+
+spif_tls_handle_t
+spif_pthreads_tls_malloc(spif_pthreads_t self, spif_memidx_t size)
+{
+ pthread_key_t key;
+ spif_ptr_t ptr;
+
+ ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), SPIF_CAST(tls_handle) -1);
+
+ if (SPIF_LIST_ISNULL(self->tls_keys)) {
+ self->tls_keys = SPIF_LIST_NEW(array);
+ }
+ ptr = MALLOC(size);
+
+ if (!pthread_key_create(&key, spif_pthreads_tls_destructor)) {
+ spif_mbuff_t tls_key;
+
+ /* Store the pointer. */
+ pthread_setspecific(key, ptr);
+
+ /* The key is actually copied into the mbuff buffer. */
+ tls_key = spif_mbuff_new_from_ptr(SPIF_CAST(byteptr) &key, sizeof(pthread_key_t));
+
+ /* Since the pointer returned by MALLOC() is only stored locally in
+ this function and as keyed in the TLS data store, it cannot be
+ retrieved by any other thread. Thus, thread-local storage. Yay! */
+ if (SPIF_LIST_APPEND(self->tls_keys, tls_key)) {
+ return (SPIF_LIST_COUNT(self->tls_keys) - 1);
+ }
+ }
+ return (SPIF_CAST(tls_handle) -1);
+}
+
+static void
+spif_pthreads_tls_destructor(void *ptr)
+{
+ FREE(ptr);
+}
+
+spif_bool_t
+spif_pthreads_tls_realloc(spif_pthreads_t self, spif_tls_handle_t handle, spif_memidx_t size)
+{
+ spif_mbuff_t key;
+
+ ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), FALSE);
+ REQUIRE_RVAL(!SPIF_LIST_ISNULL(self->tls_keys), FALSE);
+
+ key = SPIF_CAST(mbuff) SPIF_LIST_GET(self->tls_keys, handle);
+ if (!SPIF_MBUFF_ISNULL(key)) {
+ spif_ptr_t ptr;
+
+ ptr = SPIF_CAST(ptr) pthread_getspecific(*((pthread_key_t *) SPIF_MBUFF_BUFF(key)));
+ if (ptr) {
+ ptr = REALLOC(ptr, size);
+ if (ptr) {
+ pthread_setspecific(*((pthread_key_t *) SPIF_MBUFF_BUFF(key)), ptr);
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+spif_bool_t
+spif_pthreads_wait(spif_pthreads_t self, spif_condition_t cond)
+{
+ ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), FALSE);
+ ASSERT_RVAL(!SPIF_PTHREADS_CONDITION_ISNULL(SPIF_PTHREADS_CONDITION(cond)), FALSE);
+}
+
+spif_bool_t
+spif_pthreads_wait_for(spif_pthreads_t self, spif_pthreads_t other)
+{
+ ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), FALSE);
+ ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(other), FALSE);
+}
+
+SPIF_DEFINE_PROPERTY_FUNC_C(pthreads, pthread_t, handle);
+SPIF_DEFINE_PROPERTY_FUNC_C(pthreads, pthread_t, creator);
+SPIF_DEFINE_PROPERTY_FUNC_C(pthreads, pthread_attr_t, attr);
+SPIF_DEFINE_PROPERTY_FUNC(pthreads, thread_func, main_func);
+SPIF_DEFINE_PROPERTY_FUNC(pthreads, thread_data, data);
+SPIF_DEFINE_PROPERTY_FUNC(pthreads, list, tls_keys);
+
+spif_pthreads_mutex_t
+spif_pthreads_mutex_new(void)
+{
+ spif_pthreads_mutex_t self;
+
+ self = SPIF_ALLOC(pthreads_mutex);
+ if (!spif_pthreads_mutex_init(self)) {
+ SPIF_DEALLOC(self);
+ self = SPIF_NULL_TYPE(pthreads_mutex);
+ }
+ return self;
+}
+
+spif_bool_t
+spif_pthreads_mutex_init(spif_pthreads_mutex_t self)
+{
+ ASSERT_RVAL(!SPIF_PTHREADS_MUTEX_ISNULL(self), FALSE);
+ /* ***NOT NEEDED*** spif_obj_init(SPIF_OBJ(self)); */
+ spif_obj_set_class(SPIF_OBJ(self), SPIF_CLASS(SPIF_MUTEXCLASS_VAR(pthreads_mutex)));
+ self->creator = SPIF_NULL_TYPE(thread);
+ pthread_mutex_init(&self->mutex, NULL);
+ return TRUE;
+}
+
+spif_bool_t
+spif_pthreads_mutex_done(spif_pthreads_mutex_t self)
+{
+ spif_bool_t ret = TRUE;
+
+ ASSERT_RVAL(!SPIF_PTHREADS_MUTEX_ISNULL(self), FALSE);
+ self->creator = SPIF_NULL_TYPE(thread);
+ if (!pthread_mutex_unlock(&self->mutex)) {
+ /* It was locked. Destroy it. */
+ pthread_mutex_destroy(&self->mutex);
+ }
+ pthread_mutex_init(&self->mutex, NULL);
+ return ret;
+}
+
+spif_bool_t
+spif_pthreads_mutex_del(spif_pthreads_mutex_t self)
+{
+ ASSERT_RVAL(!SPIF_PTHREADS_MUTEX_ISNULL(self), FALSE);
+ spif_pthreads_mutex_done(self);
+ SPIF_DEALLOC(self);
+ return TRUE;
+}
+
+spif_str_t
+spif_pthreads_mutex_show(spif_pthreads_mutex_t self, spif_charptr_t name, spif_str_t buff, size_t indent)
+{
+ spif_char_t tmp[4096];
+
+ if (SPIF_PTHREADS_MUTEX_ISNULL(self)) {
+ SPIF_OBJ_SHOW_NULL(pthreads_mutex, name, buff, indent, tmp);
+ return buff;
+ }
+
+ memset(tmp, ' ', indent);
+ snprintf(SPIF_CHARPTR_C(tmp) + indent, sizeof(tmp) - indent,
+ "(spif_pthreads_mutex_t) %s: %10p { \"",
+ name, SPIF_CAST(ptr) self);
+ if (SPIF_STR_ISNULL(buff)) {
+ buff = spif_str_new_from_ptr(tmp);
+ } else {
+ spif_str_append_from_ptr(buff, tmp);
+ }
+
+ indent += 2;
+ if (indent < sizeof(tmp)) {
+ memset(tmp, ' ', indent);
+ }
+ if (SPIF_THREAD_ISNULL(self->creator)) {
+ SPIF_OBJ_SHOW_NULL(thread, "creator", buff, indent, tmp);
+ } else {
+ buff = SPIF_THREAD_SHOW(self->creator, buff, indent);
+ }
+
+ snprintf(SPIF_CHARPTR_C(tmp) + indent, sizeof(tmp) - indent, "(pthread_mutex_t) mutex: %10p {...}\n", &self->mutex);
+ spif_str_append_from_ptr(buff, tmp);
+
+ snprintf(SPIF_CHARPTR_C(tmp), sizeof(tmp), "}\n");
+ spif_str_append_from_ptr(buff, tmp);
+ return buff;
+}
+
+spif_cmp_t
+spif_pthreads_mutex_comp(spif_pthreads_mutex_t self, spif_pthreads_mutex_t other)
+{
+ SPIF_OBJ_COMP_CHECK_NULL(self, other);
+ return SPIF_OBJ_COMP(self, other);
+}
+
+spif_pthreads_mutex_t
+spif_pthreads_mutex_dup(spif_pthreads_mutex_t self)
+{
+ spif_pthreads_mutex_t tmp;
+
+ ASSERT_RVAL(!SPIF_PTHREADS_MUTEX_ISNULL(self), SPIF_NULL_TYPE(pthreads_mutex));
+ tmp = SPIF_ALLOC(pthreads_mutex);
+ memcpy(tmp, self, SPIF_SIZEOF_TYPE(pthreads_mutex));
+ return tmp;
+}
+
+spif_classname_t
+spif_pthreads_mutex_type(spif_pthreads_mutex_t self)
+{
+ ASSERT_RVAL(!SPIF_PTHREADS_MUTEX_ISNULL(self), SPIF_CAST(classname) SPIF_NULLSTR_TYPE(classname));
+ return SPIF_OBJ_CLASSNAME(self);
+}
+
+spif_bool_t
+spif_pthreads_mutex_lock(spif_pthreads_mutex_t self)
+{
+
+}
+
+spif_bool_t
+spif_pthreads_mutex_lock_nowait(spif_pthreads_mutex_t self)
+{
+
+}
+
+spif_bool_t
+spif_pthreads_mutex_unlock(spif_pthreads_mutex_t self)
+{
+
+}
+
+SPIF_DEFINE_PROPERTY_FUNC(pthreads_mutex, thread, creator);
+SPIF_DEFINE_PROPERTY_FUNC_C(pthreads_mutex, pthread_mutex_t, mutex);
+
+spif_pthreads_condition_t
+spif_pthreads_condition_new(void)
+{
+ spif_pthreads_condition_t self;
+
+ self = SPIF_ALLOC(pthreads_condition);
+ if (!spif_pthreads_condition_init(self)) {
+ SPIF_DEALLOC(self);
+ self = SPIF_NULL_TYPE(pthreads_condition);
+ }
+ return self;
+}
+
+spif_bool_t
+spif_pthreads_condition_init(spif_pthreads_condition_t self)
+{
+ ASSERT_RVAL(!SPIF_PTHREADS_CONDITION_ISNULL(self), FALSE);
+ spif_pthreads_mutex_init(SPIF_PTHREADS_MUTEX(self));
+ spif_obj_set_class(SPIF_OBJ(self), SPIF_CLASS(SPIF_CONDITIONCLASS_VAR(pthreads_condition)));
+ pthread_cond_init(&self->cond, NULL);
+ return TRUE;
+}
+
+spif_bool_t
+spif_pthreads_condition_done(spif_pthreads_condition_t self)
+{
+ spif_bool_t ret = TRUE;
+
+ ASSERT_RVAL(!SPIF_PTHREADS_CONDITION_ISNULL(self), FALSE);
+ ret = spif_pthreads_mutex_done(SPIF_PTHREADS_MUTEX(self));
+ pthread_cond_destroy(&self->cond);
+ pthread_cond_init(&self->cond, NULL);
+ return ret;
+}
+
+spif_bool_t
+spif_pthreads_condition_del(spif_pthreads_condition_t self)
+{
+ ASSERT_RVAL(!SPIF_PTHREADS_CONDITION_ISNULL(self), FALSE);
+ spif_pthreads_condition_done(self);
+ SPIF_DEALLOC(self);
+ return TRUE;
+}
+
+spif_str_t
+spif_pthreads_condition_show(spif_pthreads_condition_t self, spif_charptr_t name, spif_str_t buff, size_t indent)
+{
+ spif_char_t tmp[4096];
+
+ if (SPIF_PTHREADS_CONDITION_ISNULL(self)) {
+ SPIF_OBJ_SHOW_NULL(pthreads_condition, name, buff, indent, tmp);
+ return buff;
+ }
+
+ memset(tmp, ' ', indent);
+ snprintf(SPIF_CHARPTR_C(tmp) + indent, sizeof(tmp) - indent,
+ "(spif_pthreads_condition_t) %s: %10p { \"",
+ name, SPIF_CAST(ptr) self);
+ if (SPIF_STR_ISNULL(buff)) {
+ buff = spif_str_new_from_ptr(tmp);
+ } else {
+ spif_str_append_from_ptr(buff, tmp);
+ }
+
+ indent += 2;
+ if (indent < sizeof(tmp)) {
+ memset(tmp, ' ', indent);
+ }
+ buff = spif_pthreads_mutex_show(SPIF_PTHREADS_MUTEX(self), "self", buff, indent);
+
+ snprintf(SPIF_CHARPTR_C(tmp) + indent, sizeof(tmp) - indent, "(pthread_cond_t) cond: %10p {...}\n", &self->cond);
+ spif_str_append_from_ptr(buff, tmp);
+
+ snprintf(SPIF_CHARPTR_C(tmp), sizeof(tmp), "}\n");
+ spif_str_append_from_ptr(buff, tmp);
+ return buff;
+}
+
+spif_cmp_t
+spif_pthreads_condition_comp(spif_pthreads_condition_t self, spif_pthreads_condition_t other)
+{
+ SPIF_OBJ_COMP_CHECK_NULL(self, other);
+ return SPIF_OBJ_COMP(self, other);
+}
+
+spif_pthreads_condition_t
+spif_pthreads_condition_dup(spif_pthreads_condition_t self)
+{
+ spif_pthreads_condition_t tmp;
+
+ ASSERT_RVAL(!SPIF_PTHREADS_CONDITION_ISNULL(self), SPIF_NULL_TYPE(pthreads_condition));
+ tmp = SPIF_ALLOC(pthreads_condition);
+ memcpy(tmp, self, SPIF_SIZEOF_TYPE(pthreads_condition));
+ return tmp;
+}
+
+spif_classname_t
+spif_pthreads_condition_type(spif_pthreads_condition_t self)
+{
+ ASSERT_RVAL(!SPIF_PTHREADS_CONDITION_ISNULL(self), SPIF_CAST(classname) SPIF_NULLSTR_TYPE(classname));
+ return SPIF_OBJ_CLASSNAME(self);
+}
+
+spif_bool_t
+spif_pthreads_condition_broadcast(spif_pthreads_condition_t self)
+{
+
+}
+
+spif_bool_t
+spif_pthreads_condition_signal(spif_pthreads_condition_t self)
+{
+
+}
+
+spif_bool_t
+spif_pthreads_condition_wait(spif_pthreads_condition_t self)
+{
+
+}
+
+spif_bool_t
+spif_pthreads_condition_wait_timed(spif_pthreads_condition_t self, spif_int32_t delay)
+{
+
+}
+
+SPIF_DEFINE_PROPERTY_FUNC_C(pthreads_condition, pthread_cond_t, cond);
diff --git a/test/test.c b/test/test.c
index 2fa1764..57658d9 100644
--- a/test/test.c
+++ b/test/test.c
@@ -35,7 +35,6 @@ unsigned short tnum = 0;
int test_macros(void);
int test_mem(void);
int test_strings(void);
-int test_hash_functions(void);
int test_snprintf(void);
int test_options(void);
int test_obj(void);
@@ -49,6 +48,8 @@ int test_vector(void);
int test_map(void);
int test_socket(void);
int test_regexp(void);
+int test_module(void);
+int test_hash_functions(void);
int
test_macros(void)
@@ -263,227 +264,6 @@ test_strings(void)
return 0;
}
-#define MAXPAIR 80
-#define MAXLEN 80
-int
-test_hash_functions(void)
-{
- spif_uint8_t i;
-
- for (i = 0; i < 6; i++) {
- spifhash_func_t hash_func;
- spif_uint32_t key_length, input_byte, trials, successes = 0, hash, ref_hash;
- spif_uint8_t buff[MAXLEN + 20], *pbuff;
- spif_uint8_t align1[] = "This has got the amazing aroma of bovine fecal matter...";
- spif_uint8_t align2[] = "xThis has got the amazing aroma of bovine fecal matter...";
- spif_uint8_t align3[] = "xxThis has got the amazing aroma of bovine fecal matter...";
- spif_uint8_t align4[] = "xxxThis has got the amazing aroma of bovine fecal matter...";
- spif_uint32_t j;
-
- if (i == 0) {
- TEST_NOTICE("*** Testing Jenkins hash:");
- hash_func = spifhash_jenkins;
- } else if (i == 1) {
- TEST_NOTICE("*** Testing Jenkins32 hash:");
- hash_func = spifhash_jenkins32;
- } else if (i == 2) {
-#if WORDS_BIGENDIAN
- continue;
-#else
- TEST_NOTICE("*** Testing JenkinsLE hash:");
- hash_func = spifhash_jenkinsLE;
-#endif
- } else if (i == 3) {
- TEST_NOTICE("*** Testing rotating hash:");
- hash_func = spifhash_rotating;
- } else if (i == 4) {
- TEST_NOTICE("*** Testing one-at-a-time hash:");
- hash_func = spifhash_one_at_a_time;
- } else if (i == 5) {
- TEST_NOTICE("*** Testing FNV hash:");
- hash_func = spifhash_fnv;
- }
-
- TEST_BEGIN("effect of every input bit on every output bit");
- for (key_length = 0; key_length < MAXLEN; key_length++) {
- /* For each key length up to 70 bytes... */
-
- if ((hash_func == spifhash_jenkins32)
- && (key_length % 4)) {
- successes++;
- continue;
- }
- trials = 0;
- for (input_byte = 0; input_byte < key_length; input_byte++) {
- /* ...for each input byte... */
- spif_uint32_t input_bit;
-
- for (input_bit = 0; input_bit < 8; input_bit++) {
- /* ...for each input bit... */
- spif_uint32_t seed;
-
- for (seed = 1; seed < 8; seed++) {
- /* ...use several possible seeds... */
- spif_uint32_t e, f, g, h, x, y;
- spif_uint32_t bit_pair;
-
- /* Initialize to ~0 (0xffffffff). */
- e = f = g = h = x = y = ~(SPIF_CAST(uint32) 0);
-
- /* ...to make sure every output bit is affected by every input bit. */
- for (bit_pair = 0; bit_pair < MAXPAIR; bit_pair += 2) {
- spif_uint8_t buff1[MAXLEN + 1], buff2[MAXLEN + 2];
- spif_uint8_t *pbuff1 = &buff1[0], *pbuff2 = &buff2[1];
- spif_uint32_t hash1, hash2;
-
- for (j = 0; j < key_length + 1; j++) {
- /* Initialize keys to all zeros. */
- pbuff1[j] = pbuff2[j] = (spif_uint8_t) 0;
- }
-
- /* Then make them differ by exactly one bit, the input_bit.
- bit_pair will always end in 0, so bit_pair + 1 will always
- end in 1. It's then shifted by input_bit to test the
- current bit to test all 8 of the lowest bits in sequence. */
- pbuff1[input_byte] ^= (bit_pair << input_bit);
- pbuff1[input_byte] ^= (bit_pair >> (8 - input_bit));
- pbuff2[input_byte] ^= ((bit_pair + 1) << input_bit);
- pbuff2[input_byte] ^= ((bit_pair + 1) >> (8 - input_bit));
-
- /* Hash them. */
- if (hash_func == spifhash_jenkins32) {
- hash1 = hash_func(pbuff1, key_length / 4, seed);
- hash2 = hash_func(pbuff2, key_length / 4, seed);
- } else {
- hash1 = hash_func(pbuff1, key_length, seed);
- hash2 = hash_func(pbuff2, key_length, seed);
- }
-
- /* Make sure every bit is 1 or 0 at least once. */
- e &= (hash1 ^ hash2); f &= ~(hash1 ^ hash2);
- g &= hash1; h &= ~hash1;
- x &= hash2; y &= ~hash2;
- if (!(e | f | g | h | x | y)) {
- /* They're all 0. That means they've all changed at least once. */
- break;
- }
- }
- if (bit_pair > trials) {
- trials = bit_pair;
- }
- if (bit_pair == MAXPAIR) {
-#if UNUSED_BLOCK
- printf("Some bit didn't change: ");
- printf("%.8lx %.8lx %.8lx %.8lx %.8lx %.8lx ",
- SPIF_CAST_C(unsigned long) e,
- SPIF_CAST_C(unsigned long) f,
- SPIF_CAST_C(unsigned long) g,
- SPIF_CAST_C(unsigned long) h,
- SPIF_CAST_C(unsigned long) x,
- SPIF_CAST_C(unsigned long) y);
- printf("input_byte %lu input_bit %lu seed %lu key length %lu\n",
- SPIF_CAST_C(unsigned long) input_byte,
- SPIF_CAST_C(unsigned long) input_bit,
- SPIF_CAST_C(unsigned long) seed,
- SPIF_CAST_C(unsigned long) key_length);
-#endif
- }
- if (trials == MAXPAIR) {
- /* Easy way to break out of a crapload of for loops. */
- goto done;
- }
- }
- }
- }
- done:
- if (trials < MAXPAIR) {
- successes++;
-#if UNUSED_BLOCK
- printf("Mix success: %2lu-byte key required %2lu trials (%lu so far).\n",
- SPIF_CAST_C(unsigned long) input_byte,
- SPIF_CAST_C(unsigned long) trials / 2,
- SPIF_CAST_C(unsigned long) successes);
-#endif
- }
- }
- printf("%.2f%% mix success rate in %d key lengths...",
- (100.0 * successes / key_length), key_length);
- TEST_FAIL_IF(successes == 0);
- TEST_PASS();
-
- /* Make sure nothing but the key is hashed, regardless of alignment. */
- TEST_BEGIN("endian cleanliness");
- key_length = CONST_STRLEN(align1);
- if (hash_func == spifhash_jenkins32) {
- if (key_length % 4) {
- TEST_FAIL_IF(key_length);
- } else {
- key_length /= 4;
- }
- }
- ref_hash = hash_func(align1, key_length, 0);
- hash = hash_func(align2 + 1, key_length, 0);
- /*printf("Reference hash 0x%08x, hash 0x%08x for length %lu\n", ref_hash, hash, key_length);*/
- TEST_FAIL_IF(hash != ref_hash);
- hash = hash_func(align3 + 2, key_length, 0);
- TEST_FAIL_IF(hash != ref_hash);
- hash = hash_func(align4 + 3, key_length, 0);
- TEST_FAIL_IF(hash != ref_hash);
-
- for (j = 0, pbuff = buff + 1; j < 8; j++, pbuff++) {
- for (key_length = 0; key_length < MAXLEN; key_length++) {
- if ((hash_func == spifhash_jenkins32)
- && (key_length % 4)) {
- continue;
- }
- MEMSET(buff, 0, sizeof(buff));
-
- if (hash_func == spifhash_jenkins32) {
- ref_hash = hash_func(pbuff, key_length / 4, 1);
- } else {
- ref_hash = hash_func(pbuff, key_length, 1);
- }
- *(pbuff + key_length) = ~(SPIF_CAST(uint8) 0);
- *(pbuff - 1) = ~(SPIF_CAST(uint8) 0);
- if (hash_func == spifhash_jenkins32) {
- hash = hash_func(pbuff, key_length / 4, 1);
- } else {
- hash = hash_func(pbuff, key_length, 1);
- }
- /*printf("Reference hash 0x%08x, hash 0x%08x for length %lu\n", ref_hash, hash, key_length);*/
- TEST_FAIL_IF(hash != ref_hash);
- }
- }
- TEST_PASS();
-
- /* We cannot test the rotating hash or the FNV hash here. The
- rotating hash repeats after 4 zero-length keys. The FNV
- hash generates constant hash values for zero-length keys. */
- if ((hash_func != spifhash_rotating)
- && (hash_func != spifhash_fnv)) {
- spif_uint32_t null_hashes[8];
- spif_uint8_t one_byte;
-
- TEST_BEGIN("hashes of empty strings");
- one_byte = ~0;
- for (j = 0, hash = 0; j < 8; j++) {
- spif_uint32_t k;
-
- hash = hash_func(&one_byte, SPIF_CAST(uint32) 0, hash);
- null_hashes[j] = hash;
- /*printf("Empty string hash %lu is 0x%08x\n", j, hash);*/
- for (k = j - 1; k < 8; k--) {
- TEST_FAIL_IF(null_hashes[j] == null_hashes[k]);
- }
- }
- TEST_PASS();
- }
- }
-
- TEST_PASSED("hash functions");
- return 0;
-}
-
int
test_snprintf(void)
{
@@ -2715,6 +2495,269 @@ test_regexp(void)
}
int
+test_module(void)
+{
+ spif_module_t test_mod;
+ double (*dynamic_tan)(double);
+
+ TEST_BEGIN("spif_module_new() function");
+ test_mod = spif_module_new();
+ TEST_FAIL_IF(SPIF_MODULE_ISNULL(test_mod));
+ TEST_PASS();
+
+ TEST_BEGIN("spif_module_t properties");
+ spif_module_set_name(test_mod, spif_str_new_from_ptr("math library"));
+ spif_module_set_path(test_mod, spif_str_new_from_ptr("libm.so"));
+ TEST_FAIL_IF(!SPIF_CMP_IS_EQUAL(spif_str_cmp_with_ptr(test_mod->name, "math library")));
+ TEST_FAIL_IF(!SPIF_CMP_IS_EQUAL(spif_str_cmp_with_ptr(test_mod->path, "libm.so")));
+ TEST_PASS();
+
+ libast_set_silent(1);
+ TEST_BEGIN("spif_module_load() function");
+ TEST_FAIL_IF(!spif_module_load(test_mod));
+ TEST_PASS();
+
+ TEST_BEGIN("spif_module_getsym() function");
+ TEST_FAIL_IF(SPIF_PTR_ISNULL(spif_module_getsym(test_mod, "sqrt")));
+ TEST_FAIL_IF(!SPIF_PTR_ISNULL(spif_module_getsym(test_mod, "lkjweoiclkjsdfoihwerbglkjsdf")));
+ dynamic_tan = spif_module_getsym(test_mod, "tan");
+ TEST_FAIL_IF((*dynamic_tan)(2.0) - tan(2.0) > 0.00001);
+ TEST_PASS();
+
+ TEST_BEGIN("spif_module_call() function");
+ TEST_PASS();
+
+ TEST_BEGIN("spif_module_unload() function");
+ TEST_FAIL_IF(!spif_module_unload(test_mod));
+ TEST_PASS();
+ libast_set_silent(0);
+
+ TEST_PASSED("spif_module_t");
+ return 0;
+}
+
+#define MAXPAIR 80
+#define MAXLEN 80
+int
+test_hash_functions(void)
+{
+ spif_uint8_t i;
+
+ for (i = 0; i < 6; i++) {
+ spifhash_func_t hash_func;
+ spif_uint32_t key_length, input_byte, trials, successes = 0, hash, ref_hash;
+ spif_uint8_t buff[MAXLEN + 20], *pbuff;
+ spif_uint8_t align1[] = "This has got the amazing aroma of bovine fecal matter...";
+ spif_uint8_t align2[] = "xThis has got the amazing aroma of bovine fecal matter...";
+ spif_uint8_t align3[] = "xxThis has got the amazing aroma of bovine fecal matter...";
+ spif_uint8_t align4[] = "xxxThis has got the amazing aroma of bovine fecal matter...";
+ spif_uint32_t j;
+
+ if (i == 0) {
+ TEST_NOTICE("*** Testing Jenkins hash:");
+ hash_func = spifhash_jenkins;
+ } else if (i == 1) {
+ TEST_NOTICE("*** Testing Jenkins32 hash:");
+ hash_func = spifhash_jenkins32;
+ } else if (i == 2) {
+#if WORDS_BIGENDIAN
+ continue;
+#else
+ TEST_NOTICE("*** Testing JenkinsLE hash:");
+ hash_func = spifhash_jenkinsLE;
+#endif
+ } else if (i == 3) {
+ TEST_NOTICE("*** Testing rotating hash:");
+ hash_func = spifhash_rotating;
+ } else if (i == 4) {
+ TEST_NOTICE("*** Testing one-at-a-time hash:");
+ hash_func = spifhash_one_at_a_time;
+ } else if (i == 5) {
+ TEST_NOTICE("*** Testing FNV hash:");
+ hash_func = spifhash_fnv;
+ }
+
+ TEST_BEGIN("effect of every input bit on every output bit");
+ for (key_length = 0; key_length < MAXLEN; key_length++) {
+ /* For each key length up to 70 bytes... */
+
+ if ((hash_func == spifhash_jenkins32)
+ && (key_length % 4)) {
+ successes++;
+ continue;
+ }
+ trials = 0;
+ for (input_byte = 0; input_byte < key_length; input_byte++) {
+ /* ...for each input byte... */
+ spif_uint32_t input_bit;
+
+ for (input_bit = 0; input_bit < 8; input_bit++) {
+ /* ...for each input bit... */
+ spif_uint32_t seed;
+
+ for (seed = 1; seed < 8; seed++) {
+ /* ...use several possible seeds... */
+ spif_uint32_t e, f, g, h, x, y;
+ spif_uint32_t bit_pair;
+
+ /* Initialize to ~0 (0xffffffff). */
+ e = f = g = h = x = y = ~(SPIF_CAST(uint32) 0);
+
+ /* ...to make sure every output bit is affected by every input bit. */
+ for (bit_pair = 0; bit_pair < MAXPAIR; bit_pair += 2) {
+ spif_uint8_t buff1[MAXLEN + 1], buff2[MAXLEN + 2];
+ spif_uint8_t *pbuff1 = &buff1[0], *pbuff2 = &buff2[1];
+ spif_uint32_t hash1, hash2;
+
+ for (j = 0; j < key_length + 1; j++) {
+ /* Initialize keys to all zeros. */
+ pbuff1[j] = pbuff2[j] = (spif_uint8_t) 0;
+ }
+
+ /* Then make them differ by exactly one bit, the input_bit.
+ bit_pair will always end in 0, so bit_pair + 1 will always
+ end in 1. It's then shifted by input_bit to test the
+ current bit to test all 8 of the lowest bits in sequence. */
+ pbuff1[input_byte] ^= (bit_pair << input_bit);
+ pbuff1[input_byte] ^= (bit_pair >> (8 - input_bit));
+ pbuff2[input_byte] ^= ((bit_pair + 1) << input_bit);
+ pbuff2[input_byte] ^= ((bit_pair + 1) >> (8 - input_bit));
+
+ /* Hash them. */
+ if (hash_func == spifhash_jenkins32) {
+ hash1 = hash_func(pbuff1, key_length / 4, seed);
+ hash2 = hash_func(pbuff2, key_length / 4, seed);
+ } else {
+ hash1 = hash_func(pbuff1, key_length, seed);
+ hash2 = hash_func(pbuff2, key_length, seed);
+ }
+
+ /* Make sure every bit is 1 or 0 at least once. */
+ e &= (hash1 ^ hash2); f &= ~(hash1 ^ hash2);
+ g &= hash1; h &= ~hash1;
+ x &= hash2; y &= ~hash2;
+ if (!(e | f | g | h | x | y)) {
+ /* They're all 0. That means they've all changed at least once. */
+ break;
+ }
+ }
+ if (bit_pair > trials) {
+ trials = bit_pair;
+ }
+ if (bit_pair == MAXPAIR) {
+#if UNUSED_BLOCK
+ printf("Some bit didn't change: ");
+ printf("%.8lx %.8lx %.8lx %.8lx %.8lx %.8lx ",
+ SPIF_CAST_C(unsigned long) e,
+ SPIF_CAST_C(unsigned long) f,
+ SPIF_CAST_C(unsigned long) g,
+ SPIF_CAST_C(unsigned long) h,
+ SPIF_CAST_C(unsigned long) x,
+ SPIF_CAST_C(unsigned long) y);
+ printf("input_byte %lu input_bit %lu seed %lu key length %lu\n",
+ SPIF_CAST_C(unsigned long) input_byte,
+ SPIF_CAST_C(unsigned long) input_bit,
+ SPIF_CAST_C(unsigned long) seed,
+ SPIF_CAST_C(unsigned long) key_length);
+#endif
+ }
+ if (trials == MAXPAIR) {
+ /* Easy way to break out of a crapload of for loops. */
+ goto done;
+ }
+ }
+ }
+ }
+ done:
+ if (trials < MAXPAIR) {
+ successes++;
+#if UNUSED_BLOCK
+ printf("Mix success: %2lu-byte key required %2lu trials (%lu so far).\n",
+ SPIF_CAST_C(unsigned long) input_byte,
+ SPIF_CAST_C(unsigned long) trials / 2,
+ SPIF_CAST_C(unsigned long) successes);
+#endif
+ }
+ }
+ printf("%.2f%% mix success rate in %d key lengths...",
+ (100.0 * successes / key_length), key_length);
+ TEST_FAIL_IF(successes == 0);
+ TEST_PASS();
+
+ /* Make sure nothing but the key is hashed, regardless of alignment. */
+ TEST_BEGIN("endian cleanliness");
+ key_length = CONST_STRLEN(align1);
+ if (hash_func == spifhash_jenkins32) {
+ if (key_length % 4) {
+ TEST_FAIL_IF(key_length);
+ } else {
+ key_length /= 4;
+ }
+ }
+ ref_hash = hash_func(align1, key_length, 0);
+ hash = hash_func(align2 + 1, key_length, 0);
+ /*printf("Reference hash 0x%08x, hash 0x%08x for length %lu\n", ref_hash, hash, key_length);*/
+ TEST_FAIL_IF(hash != ref_hash);
+ hash = hash_func(align3 + 2, key_length, 0);
+ TEST_FAIL_IF(hash != ref_hash);
+ hash = hash_func(align4 + 3, key_length, 0);
+ TEST_FAIL_IF(hash != ref_hash);
+
+ for (j = 0, pbuff = buff + 1; j < 8; j++, pbuff++) {
+ for (key_length = 0; key_length < MAXLEN; key_length++) {
+ if ((hash_func == spifhash_jenkins32)
+ && (key_length % 4)) {
+ continue;
+ }
+ MEMSET(buff, 0, sizeof(buff));
+
+ if (hash_func == spifhash_jenkins32) {
+ ref_hash = hash_func(pbuff, key_length / 4, 1);
+ } else {
+ ref_hash = hash_func(pbuff, key_length, 1);
+ }
+ *(pbuff + key_length) = ~(SPIF_CAST(uint8) 0);
+ *(pbuff - 1) = ~(SPIF_CAST(uint8) 0);
+ if (hash_func == spifhash_jenkins32) {
+ hash = hash_func(pbuff, key_length / 4, 1);
+ } else {
+ hash = hash_func(pbuff, key_length, 1);
+ }
+ /*printf("Reference hash 0x%08x, hash 0x%08x for length %lu\n", ref_hash, hash, key_length);*/
+ TEST_FAIL_IF(hash != ref_hash);
+ }
+ }
+ TEST_PASS();
+
+ /* We cannot test the rotating hash or the FNV hash here. The
+ rotating hash repeats after 4 zero-length keys. The FNV
+ hash generates constant hash values for zero-length keys. */
+ if ((hash_func != spifhash_rotating)
+ && (hash_func != spifhash_fnv)) {
+ spif_uint32_t null_hashes[8];
+ spif_uint8_t one_byte;
+
+ TEST_BEGIN("hashes of empty strings");
+ one_byte = ~0;
+ for (j = 0, hash = 0; j < 8; j++) {
+ spif_uint32_t k;
+
+ hash = hash_func(&one_byte, SPIF_CAST(uint32) 0, hash);
+ null_hashes[j] = hash;
+ /*printf("Empty string hash %lu is 0x%08x\n", j, hash);*/
+ for (k = j - 1; k < 8; k--) {
+ TEST_FAIL_IF(null_hashes[j] == null_hashes[k]);
+ }
+ }
+ TEST_PASS();
+ }
+ }
+
+ TEST_PASSED("hash functions");
+ return 0;
+}
+
+int
main(int argc, char *argv[])
{
int ret = 0;
@@ -2772,6 +2815,9 @@ main(int argc, char *argv[])
if ((ret = test_regexp()) != 0) {
return ret;
}
+ if ((ret = test_module()) != 0) {
+ return ret;
+ }
if ((ret = test_hash_functions()) != 0) {
return ret;
}