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)
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.
787 787
788Began work on UTF-8/Unicode strings. 788Began work on UTF-8/Unicode strings.
789---------------------------------------------------------------------- 789----------------------------------------------------------------------
790Thu Jul 13 14:02:08 2006 Michael Jennings (mej)
791
792Added thread, mutex, and condition interfaces along with their
793corresponding pthreads-based implementations. Not quite done yet, and
794not tested.
795
796Added dynamically-loadable module object class along with
797corresponding unit tests. Appears to work fine.
798----------------------------------------------------------------------
diff --git a/autogen.sh b/autogen.sh
index f453e03..afe9439 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -55,9 +55,9 @@ done
55export LIBTOOLIZE ACLOCAL AUTOCONF AUTOHEADER AUTOMAKE 55export LIBTOOLIZE ACLOCAL AUTOCONF AUTOHEADER AUTOMAKE
56 56
57# Check for existing libast.m4 we can use. Use the local one if not. 57# Check for existing libast.m4 we can use. Use the local one if not.
58if test ! -f "`$ACLOCAL --print-ac-dir`/libast.m4"; then 58#if test ! -f "`$ACLOCAL --print-ac-dir`/libast.m4"; then
59 ACLOCAL_FLAGS="-I . $ACLOCAL_FLAGS" 59 ACLOCAL_FLAGS="-I . $ACLOCAL_FLAGS"
60fi 60#fi
61 61
62# Run the stuff. 62# Run the stuff.
63(set -x && $LIBTOOLIZE -c -f) || abort libtool 63(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()
96AST_MMX_SUPPORT() 96AST_MMX_SUPPORT()
97AST_ARG_REGEXP(REGEXP) 97AST_ARG_REGEXP(REGEXP)
98AST_ARG_BACKQUOTE_EXEC(ALLOW_BACKQUOTE_EXEC) 98AST_ARG_BACKQUOTE_EXEC(ALLOW_BACKQUOTE_EXEC)
99AST_PTHREADS()
99 100
100AST_FLAGS() 101AST_FLAGS()
101AC_SUBST(CC) 102AC_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();
107# endif 107# endif
108#endif 108#endif
109 109
110/* Type and object headers that must go first. */
110#include <libast/types.h> 111#include <libast/types.h>
111#include <libast/obj.h> 112#include <libast/obj.h>
112 113
114/* Basic objects */
113#include <libast/mbuff.h> 115#include <libast/mbuff.h>
116#include <libast/module.h>
114#include <libast/objpair.h> 117#include <libast/objpair.h>
115#include <libast/regexp.h> 118#include <libast/regexp.h>
116#include <libast/socket.h> 119#include <libast/socket.h>
@@ -119,15 +122,23 @@ extern int re_exec();
119#include <libast/url.h> 122#include <libast/url.h>
120#include <libast/ustr.h> 123#include <libast/ustr.h>
121 124
125/* Interface classes */
126#include <libast/condition_if.h>
122#include <libast/iterator_if.h> 127#include <libast/iterator_if.h>
123#include <libast/list_if.h> 128#include <libast/list_if.h>
124#include <libast/map_if.h> 129#include <libast/map_if.h>
130#include <libast/mutex_if.h>
131#include <libast/thread_if.h>
125#include <libast/vector_if.h> 132#include <libast/vector_if.h>
126 133
134/* List/vector/map implementations */
127#include <libast/array.h> 135#include <libast/array.h>
128#include <libast/linked_list.h> 136#include <libast/linked_list.h>
129#include <libast/dlinked_list.h> 137#include <libast/dlinked_list.h>
130 138
139/* Thread/condition/mutex implementations */
140#include <libast/pthreads.h>
141
131#include <libast/avl_tree.h> 142#include <libast/avl_tree.h>
132 143
133/******************************* GENERIC GOOP *********************************/ 144/******************************* GENERIC GOOP *********************************/
@@ -2690,6 +2701,7 @@ typedef spif_uint32_t (*spifhash_func_t)(spif_uint8_t *, spif_uint32_t, spif_uin
2690/* msgs.c */ 2701/* msgs.c */
2691extern void libast_set_program_name(const char *); 2702extern void libast_set_program_name(const char *);
2692extern void libast_set_program_version(const char *); 2703extern void libast_set_program_version(const char *);
2704extern spif_bool_t libast_set_silent(spif_bool_t);
2693extern int libast_dprintf(const char *, ...); 2705extern int libast_dprintf(const char *, ...);
2694extern void libast_print_error(const char *fmt, ...); 2706extern void libast_print_error(const char *fmt, ...);
2695extern void libast_print_warning(const char *fmt, ...); 2707extern 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 @@
1# $Id: Makefile.am,v 1.6 2001/09/22 16:25:29 mej Exp $ 1# $Id: Makefile.am,v 1.6 2001/09/22 16:25:29 mej Exp $
2 2
3EXTRA_HEADERS = array.h avl_tree.h dlinked_list.h iterator_if.h \ 3EXTRA_HEADERS = array.h avl_tree.h dlinked_list.h iterator_if.h \
4linked_list.h list_if.h map_if.h mbuff.h obj.h objpair.h regexp.h \ 4linked_list.h list_if.h map_if.h mbuff.h module.h obj.h objpair.h \
5socket.h str.h sysdefs.h tok.h types.h url.h ustr.h vector_if.h 5regexp.h socket.h str.h sysdefs.h tok.h types.h url.h ustr.h \
6vector_if.h
6 7
7install-exec-hook: 8install-exec-hook:
8 $(mkinstalldirs) $(DESTDIR)$(includedir)/$(PACKAGE) 9 $(mkinstalldirs) $(DESTDIR)$(includedir)/$(PACKAGE)
@@ -22,4 +23,5 @@ types.h: types.h.in
22 23
23sysdefs.h: sysdefs.h.in 24sysdefs.h: sysdefs.h.in
24 (cd $(top_srcdir) && ./config.status) 25 (cd $(top_srcdir) && ./config.status)
26
25MAINTAINERCLEANFILES = Makefile.in 27MAINTAINERCLEANFILES = 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 @@
1/*
2 * Copyright (C) 1997-2004, Michael Jennings
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to
6 * deal in the Software without restriction, including without limitation the
7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 * sell copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies of the Software, its documentation and marketing & publicity
13 * materials, and acknowledgment shall be given in the documentation, materials
14 * and software packages that this Software was used.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24#ifndef _LIBAST_CONDITION_IF_H_
25#define _LIBAST_CONDITION_IF_H_
26
27/*
28 * interface goop
29 */
30
31/* Standard typecast macros.... */
32#define SPIF_CONDITION(o) (SPIF_CAST(condition) (o))
33#define SPIF_CONDITION_CLASS(o) (SPIF_CAST(conditionclass) SPIF_OBJ_CLASS(o))
34
35/* Name of class variable associated with condition interface */
36#define SPIF_CONDITIONCLASS_VAR(type) spif_ ## type ## _conditionclass
37
38/* Check if a condition is NULL */
39#define SPIF_CONDITION_ISNULL(o) (SPIF_CONDITION(o) == SPIF_NULL_TYPE(condition))
40
41/* Check if an object is a condition */
42#define SPIF_OBJ_IS_CONDITION(o) SPIF_OBJ_IS_TYPE(o, condition)
43
44/* Call a method on an instance of an implementation class */
45#define SPIF_CONDITION_CALL_METHOD(o, meth) SPIF_CONDITION_CLASS(o)->meth
46
47/* Calls to the basic functions. */
48#define SPIF_CONDITION_NEW(type) SPIF_CONDITION((SPIF_CLASS(SPIF_CONDITIONCLASS_VAR(type)))->noo())
49#define SPIF_CONDITION_INIT(o) SPIF_OBJ_INIT(o)
50#define SPIF_CONDITION_DONE(o) SPIF_OBJ_DONE(o)
51#define SPIF_CONDITION_DEL(o) SPIF_OBJ_DEL(o)
52#define SPIF_CONDITION_SHOW(o, b, i) SPIF_OBJ_SHOW(o, b, i)
53#define SPIF_CONDITION_COMP(o1, o2) SPIF_OBJ_COMP(o1, o2)
54#define SPIF_CONDITION_DUP(o) SPIF_OBJ_DUP(o)
55#define SPIF_CONDITION_TYPE(o) SPIF_OBJ_TYPE(o)
56
57#define SPIF_CONDITION_BROADCAST(o) SPIF_CAST(bool) ((SPIF_CONDITION_CALL_METHOD((o), broadcast))(o))
58#define SPIF_CONDITION_SIGNAL(o) SPIF_CAST(bool) ((SPIF_CONDITION_CALL_METHOD((o), signal))(o))
59#define SPIF_CONDITION_WAIT(o) SPIF_CAST(bool) ((SPIF_CONDITION_CALL_METHOD((o), wait))(o))
60#define SPIF_CONDITION_WAIT_TIMED(o, t) SPIF_CAST(bool) ((SPIF_CONDITION_CALL_METHOD((o), wait_timed))((o), (t)))
61
62typedef spif_obj_t spif_condition_t;
63
64SPIF_DECL_OBJ(conditionclass) {
65 SPIF_DECL_PARENT_TYPE(class);
66
67 spif_func_t broadcast;
68 spif_func_t signal;
69 spif_func_t wait;
70 spif_func_t wait_timed;
71};
72
73#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 @@
56 56
57#define SPIF_LIST_APPEND(o, item) SPIF_CAST(bool) ((SPIF_LIST_CALL_METHOD((o), append))(o, item)) 57#define SPIF_LIST_APPEND(o, item) SPIF_CAST(bool) ((SPIF_LIST_CALL_METHOD((o), append))(o, item))
58#define SPIF_LIST_CONTAINS(o, item) SPIF_CAST(bool) ((SPIF_LIST_CALL_METHOD((o), contains))(o, item)) 58#define SPIF_LIST_CONTAINS(o, item) SPIF_CAST(bool) ((SPIF_LIST_CALL_METHOD((o), contains))(o, item))
59#define SPIF_LIST_COUNT(o) SPIF_CAST_C(size_t) ((SPIF_LIST_CALL_METHOD((o), count))(o)) 59#define SPIF_LIST_COUNT(o) SPIF_CAST(listidx) ((SPIF_LIST_CALL_METHOD((o), count))(o))
60#define SPIF_LIST_FIND(o, item) SPIF_CAST(obj) ((SPIF_LIST_CALL_METHOD((o), find))(o, item)) 60#define SPIF_LIST_FIND(o, item) SPIF_CAST(obj) ((SPIF_LIST_CALL_METHOD((o), find))(o, item))
61#define SPIF_LIST_GET(o, index) SPIF_CAST(obj) ((SPIF_LIST_CALL_METHOD((o), get))(o, index)) 61#define SPIF_LIST_GET(o, index) SPIF_CAST(obj) ((SPIF_LIST_CALL_METHOD((o), get))(o, index))
62#define SPIF_LIST_INDEX(o, item) SPIF_CAST_C(size_t) ((SPIF_LIST_CALL_METHOD((o), index))(o, item)) 62#define SPIF_LIST_INDEX(o, item) SPIF_CAST(listidx) ((SPIF_LIST_CALL_METHOD((o), index))(o, item))
63#define SPIF_LIST_INSERT(o, item) SPIF_CAST(bool) ((SPIF_LIST_CALL_METHOD((o), insert))(o, item)) 63#define SPIF_LIST_INSERT(o, item) SPIF_CAST(bool) ((SPIF_LIST_CALL_METHOD((o), insert))(o, item))
64#define SPIF_LIST_INSERT_AT(o, item, index) SPIF_CAST(bool) ((SPIF_LIST_CALL_METHOD((o), insert_at))(o, item, index)) 64#define SPIF_LIST_INSERT_AT(o, item, index) SPIF_CAST(bool) ((SPIF_LIST_CALL_METHOD((o), insert_at))(o, item, index))
65#define SPIF_LIST_ITERATOR(o) SPIF_CAST(iterator) ((SPIF_LIST_CALL_METHOD((o), iterator))(o)) 65#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 @@
1/*
2 * Copyright (C) 1997-2004, Michael Jennings
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to
6 * deal in the Software without restriction, including without limitation the
7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 * sell copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies of the Software, its documentation and marketing & publicity
13 * materials, and acknowledgment shall be given in the documentation, materials
14 * and software packages that this Software was used.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24#ifndef _LIBAST_MODULE_H_
25#define _LIBAST_MODULE_H_
26
27#define SPIF_MODULE(obj) (SPIF_CAST(module) (obj))
28#define SPIF_MODULE_CLASS(o) (SPIF_CAST(moduleclass) SPIF_OBJ_CLASS(o))
29#define SPIF_OBJ_IS_MODULE(o) (SPIF_OBJ_IS_TYPE(o, module))
30#define SPIF_MODULE_ISNULL(s) SPIF_OBJ_ISNULL(SPIF_OBJ(s))
31#define SPIF_MODULECLASS_VAR(type) spif_ ## type ## _moduleclass
32#define SPIF_MODULE_CALL_METHOD(o, meth) SPIF_MODULE_CLASS(o)->meth
33
34#define SPIF_MODULE_NEW(type) SPIF_MODULE((SPIF_CLASS(SPIF_CLASS_VAR(type)))->noo())
35#define SPIF_MODULE_INIT(obj) SPIF_OBJ_INIT(obj)
36#define SPIF_MODULE_DONE(obj) SPIF_OBJ_DONE(obj)
37#define SPIF_MODULE_DEL(obj) SPIF_OBJ_DEL(obj)
38#define SPIF_MODULE_SHOW(obj, b, i) SPIF_OBJ_SHOW(obj, b, i)
39#define SPIF_MODULE_COMP(o1, o2) SPIF_OBJ_COMP(o1, o2)
40#define SPIF_MODULE_DUP(obj) SPIF_OBJ_DUP(obj)
41#define SPIF_MODULE_TYPE(obj) SPIF_OBJ_TYPE(obj)
42
43typedef spif_ptr_t (spif_getsym_func_t)(spif_charptr_t);
44
45SPIF_DECL_OBJ(module) {
46 SPIF_DECL_PARENT_TYPE(obj);
47 SPIF_DECL_PROPERTY(str, name);
48 SPIF_DECL_PROPERTY(str, path);
49 SPIF_DECL_PROPERTY(ptr, module_handle);
50 SPIF_DECL_PROPERTY(ptr, main_handle);
51};
52
53SPIF_DECL_OBJ(moduleclass) {
54 SPIF_DECL_PARENT_TYPE(class);
55
56 spif_func_t call;
57 spif_func_t getsym;
58 spif_func_t load;
59 spif_func_t run;
60 spif_func_t unload;
61};
62
63extern spif_class_t SPIF_CLASS_VAR(module);
64extern spif_moduleclass_t SPIF_MODULECLASS_VAR(module);
65extern spif_module_t spif_module_new(void);
66extern spif_bool_t spif_module_del(spif_module_t);
67extern spif_bool_t spif_module_init(spif_module_t);
68extern spif_bool_t spif_module_done(spif_module_t);
69extern spif_str_t spif_module_show(spif_module_t, spif_charptr_t, spif_str_t, size_t);
70extern spif_cmp_t spif_module_comp(spif_module_t, spif_module_t);
71extern spif_module_t spif_module_dup(spif_module_t);
72extern spif_classname_t spif_module_type(spif_module_t);
73extern spif_ptr_t spif_module_call(spif_module_t self, spif_charptr_t fname, spif_ptr_t data);
74extern spif_ptr_t spif_module_getsym(spif_module_t self, spif_charptr_t sym);
75extern spif_bool_t spif_module_load(spif_module_t self);
76extern spif_bool_t spif_module_run(spif_module_t self);
77extern spif_bool_t spif_module_unload(spif_module_t self);
78SPIF_DECL_PROPERTY_FUNC(module, str, name);
79SPIF_DECL_PROPERTY_FUNC(module, str, path);
80SPIF_DECL_PROPERTY_FUNC(module, ptr, module_handle);
81SPIF_DECL_PROPERTY_FUNC(module, ptr, main_handle);
82
83#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 @@
1/*
2 * Copyright (C) 1997-2004, Michael Jennings
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to
6 * deal in the Software without restriction, including without limitation the
7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 * sell copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies of the Software, its documentation and marketing & publicity
13 * materials, and acknowledgment shall be given in the documentation, materials
14 * and software packages that this Software was used.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24#ifndef _LIBAST_MUTEX_IF_H_
25#define _LIBAST_MUTEX_IF_H_
26
27/*
28 * interface goop
29 */
30
31/* Standard typecast macros.... */
32#define SPIF_MUTEX(o) (SPIF_CAST(mutex) (o))
33#define SPIF_MUTEX_CLASS(o) (SPIF_CAST(mutexclass) SPIF_OBJ_CLASS(o))
34
35/* Name of class variable associated with mutex interface */
36#define SPIF_MUTEXCLASS_VAR(type) spif_ ## type ## _mutexclass
37
38/* Check if a mutex is NULL */
39#define SPIF_MUTEX_ISNULL(o) (SPIF_MUTEX(o) == SPIF_NULL_TYPE(mutex))
40
41/* Check if an object is a mutex */
42#define SPIF_OBJ_IS_MUTEX(o) SPIF_OBJ_IS_TYPE(o, mutex)
43
44/* Call a method on an instance of an implementation class */
45#define SPIF_MUTEX_CALL_METHOD(o, meth) SPIF_MUTEX_CLASS(o)->meth
46
47/* Calls to the basic functions. */
48#define SPIF_MUTEX_NEW(type) SPIF_MUTEX((SPIF_CLASS(SPIF_MUTEXCLASS_VAR(type)))->noo())
49#define SPIF_MUTEX_INIT(o) SPIF_OBJ_INIT(o)
50#define SPIF_MUTEX_DONE(o) SPIF_OBJ_DONE(o)
51#define SPIF_MUTEX_DEL(o) SPIF_OBJ_DEL(o)
52#define SPIF_MUTEX_SHOW(o, b, i) SPIF_OBJ_SHOW(o, b, i)
53#define SPIF_MUTEX_COMP(o1, o2) SPIF_OBJ_COMP(o1, o2)
54#define SPIF_MUTEX_DUP(o) SPIF_OBJ_DUP(o)
55#define SPIF_MUTEX_TYPE(o) SPIF_OBJ_TYPE(o)
56
57#define SPIF_MUTEX_LOCK() SPIF_CAST(bool) ((SPIF_MUTEX_CALL_METHOD((o), lock))(o))
58#define SPIF_MUTEX_LOCK_NOWAIT() SPIF_CAST(bool) ((SPIF_MUTEX_CALL_METHOD((o), lock_nowait))(o))
59#define SPIF_MUTEX_UNLOCK() SPIF_CAST(bool) ((SPIF_MUTEX_CALL_METHOD((o), unlock))(o))
60
61typedef spif_obj_t spif_mutex_t;
62
63SPIF_DECL_OBJ(mutexclass) {
64 SPIF_DECL_PARENT_TYPE(class);
65
66 spif_func_t lock;
67 spif_func_t lock_nowait;
68 spif_func_t unlock;
69};
70
71#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 @@
1/*
2 * Copyright (C) 1997-2004, Michael Jennings
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to
6 * deal in the Software without restriction, including without limitation the
7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 * sell copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies of the Software, its documentation and marketing & publicity
13 * materials, and acknowledgment shall be given in the documentation, materials
14 * and software packages that this Software was used.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24#ifndef _LIBAST_PTHREADS_H_
25#define _LIBAST_PTHREADS_H_
26
27#define SPIF_PTHREADS(obj) (SPIF_CAST(pthreads) (obj))
28#define SPIF_OBJ_IS_PTHREADS(o) (SPIF_OBJ_IS_TYPE(o, pthreads))
29#define SPIF_PTHREADS_ISNULL(s) SPIF_OBJ_ISNULL(SPIF_OBJ(s))
30
31SPIF_DECL_OBJ(pthreads) {
32 SPIF_DECL_PARENT_TYPE(obj);
33 SPIF_DECL_PROPERTY_C(pthread_t, handle);
34 SPIF_DECL_PROPERTY_C(pthread_t, creator);
35 SPIF_DECL_PROPERTY_C(pthread_attr_t, attr);
36 SPIF_DECL_PROPERTY(thread_func, main_func);
37 SPIF_DECL_PROPERTY(thread_data, data);
38 SPIF_DECL_PROPERTY(list, tls_keys);
39};
40
41#define SPIF_PTHREADS_MUTEX(obj) (SPIF_CAST(pthreads_mutex) (obj))
42#define SPIF_OBJ_IS_PTHREADS_MUTEX(o) (SPIF_OBJ_IS_TYPE(o, pthreads_mutex))
43#define SPIF_PTHREADS_MUTEX_ISNULL(s) SPIF_OBJ_ISNULL(SPIF_OBJ(s))
44
45SPIF_DECL_OBJ(pthreads_mutex) {
46 SPIF_DECL_PARENT_TYPE(obj);
47 SPIF_DECL_PROPERTY(thread, creator);
48 SPIF_DECL_PROPERTY_C(pthread_mutex_t, mutex);
49};
50
51#define SPIF_PTHREADS_CONDITION(obj) (SPIF_CAST(pthreads_condition) (obj))
52#define SPIF_OBJ_IS_PTHREADS_CONDITION(o) (SPIF_OBJ_IS_TYPE(o, pthreads_condition))
53#define SPIF_PTHREADS_CONDITION_ISNULL(s) SPIF_OBJ_ISNULL(SPIF_OBJ(s))
54
55SPIF_DECL_OBJ(pthreads_condition) {
56 SPIF_DECL_PARENT_TYPE(pthreads_mutex);
57 SPIF_DECL_PROPERTY_C(pthread_cond_t, cond);
58};
59
60extern SPIF_TYPE(class) SPIF_CLASS_VAR(pthreads);
61extern SPIF_TYPE(threadclass) SPIF_THREADCLASS_VAR(pthreads);
62extern spif_pthreads_t spif_pthreads_new(void);
63extern spif_pthreads_t spif_pthreads_new_with_func(spif_thread_func_t, spif_thread_data_t);
64extern spif_bool_t spif_pthreads_init(spif_pthreads_t);
65extern spif_bool_t spif_pthreads_init_with_func(spif_pthreads_t, spif_thread_func_t, spif_thread_data_t);
66extern spif_bool_t spif_pthreads_done(spif_pthreads_t);
67extern spif_bool_t spif_pthreads_del(spif_pthreads_t);
68extern spif_str_t spif_pthreads_show(spif_pthreads_t, spif_charptr_t, spif_str_t, size_t);
69extern spif_cmp_t spif_pthreads_comp(spif_pthreads_t, spif_pthreads_t);
70extern spif_pthreads_t spif_pthreads_dup(spif_pthreads_t);
71extern spif_classname_t spif_pthreads_type(spif_pthreads_t);
72extern spif_bool_t spif_pthreads_detach(spif_pthreads_t self);
73extern spif_condition_t spif_pthreads_get_condition(spif_pthreads_t self);
74extern spif_mutex_t spif_pthreads_get_mutex(spif_pthreads_t self);
75extern spif_bool_t spif_pthreads_kill(spif_pthreads_t self, int sig);
76extern spif_bool_t spif_pthreads_run(spif_pthreads_t self);
77extern spif_tls_handle_t spif_pthreads_tls_calloc(spif_pthreads_t self, size_t count, size_t size);
78extern spif_bool_t spif_pthreads_tls_free(spif_pthreads_t self, spif_tls_handle_t handle);
79extern spif_ptr_t spif_pthreads_tls_get(spif_pthreads_t self, spif_tls_handle_t handle);
80extern spif_tls_handle_t spif_pthreads_tls_malloc(spif_pthreads_t self, spif_memidx_t size);
81extern spif_bool_t spif_pthreads_tls_realloc(spif_pthreads_t self, spif_tls_handle_t handle, spif_memidx_t size);
82extern spif_bool_t spif_pthreads_wait(spif_pthreads_t self, spif_condition_t cond);
83extern spif_bool_t spif_pthreads_wait_for(spif_pthreads_t self, spif_pthreads_t other);
84SPIF_DECL_PROPERTY_FUNC_C(pthreads, pthread_t, handle);
85SPIF_DECL_PROPERTY_FUNC_C(pthreads, pthread_t, creator);
86SPIF_DECL_PROPERTY_FUNC_C(pthreads, pthread_attr_t, attr);
87SPIF_DECL_PROPERTY_FUNC(pthreads, thread_func, main_func);
88SPIF_DECL_PROPERTY_FUNC(pthreads, thread_data, data);
89SPIF_DECL_PROPERTY_FUNC(pthreads, list, tls_keys);
90
91extern SPIF_TYPE(mutexclass) SPIF_MUTEXCLASS_VAR(pthreads_mutex);
92extern spif_pthreads_mutex_t spif_pthreads_mutex_new(void);
93extern spif_bool_t spif_pthreads_mutex_init(spif_pthreads_mutex_t);
94extern spif_bool_t spif_pthreads_mutex_done(spif_pthreads_mutex_t);
95extern spif_bool_t spif_pthreads_mutex_del(spif_pthreads_mutex_t);
96extern spif_str_t spif_pthreads_mutex_show(spif_pthreads_mutex_t, spif_charptr_t, spif_str_t, size_t);
97extern spif_cmp_t spif_pthreads_mutex_comp(spif_pthreads_mutex_t, spif_pthreads_mutex_t);
98extern spif_pthreads_mutex_t spif_pthreads_mutex_dup(spif_pthreads_mutex_t);
99extern spif_classname_t spif_pthreads_mutex_type(spif_pthreads_mutex_t);
100extern spif_bool_t spif_pthreads_mutex_lock(spif_pthreads_mutex_t);
101extern spif_bool_t spif_pthreads_mutex_lock_nowait(spif_pthreads_mutex_t);
102extern spif_bool_t spif_pthreads_mutex_unlock(spif_pthreads_mutex_t);
103SPIF_DECL_PROPERTY_FUNC(pthreads_mutex, thread, creator);
104SPIF_DECL_PROPERTY_FUNC_C(pthreads_mutex, pthread_mutex_t, mutex);
105
106extern SPIF_TYPE(conditionclass) SPIF_CONDITIONCLASS_VAR(pthreads_condition);
107extern spif_pthreads_condition_t spif_pthreads_condition_new(void);
108extern spif_bool_t spif_pthreads_condition_init(spif_pthreads_condition_t);
109extern spif_bool_t spif_pthreads_condition_done(spif_pthreads_condition_t);
110extern spif_bool_t spif_pthreads_condition_del(spif_pthreads_condition_t);
111extern spif_str_t spif_pthreads_condition_show(spif_pthreads_condition_t, spif_charptr_t, spif_str_t, size_t);
112extern spif_cmp_t spif_pthreads_condition_comp(spif_pthreads_condition_t, spif_pthreads_condition_t);
113extern spif_pthreads_condition_t spif_pthreads_condition_dup(spif_pthreads_condition_t);
114extern spif_classname_t spif_pthreads_condition_type(spif_pthreads_condition_t);
115extern spif_bool_t spif_pthreads_condition_broadcast(spif_pthreads_condition_t);
116extern spif_bool_t spif_pthreads_condition_signal(spif_pthreads_condition_t);
117extern spif_bool_t spif_pthreads_condition_wait(spif_pthreads_condition_t);
118extern spif_bool_t spif_pthreads_condition_wait_timed(spif_pthreads_condition_t, spif_int32_t);
119SPIF_DECL_PROPERTY_FUNC_C(pthreads_condition, pthread_cond_t, cond);
120
121#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 @@
1/*
2 * Copyright (C) 1997-2004, Michael Jennings
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to
6 * deal in the Software without restriction, including without limitation the
7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 * sell copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies of the Software, its documentation and marketing & publicity
13 * materials, and acknowledgment shall be given in the documentation, materials
14 * and software packages that this Software was used.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24#ifndef _LIBAST_THREAD_IF_H_
25#define _LIBAST_THREAD_IF_H_
26
27/*
28 * interface goop
29 */
30
31/* Standard typecast macros.... */
32#define SPIF_THREAD(o) (SPIF_CAST(thread) (o))
33#define SPIF_THREAD_CLASS(o) (SPIF_CAST(threadclass) SPIF_OBJ_CLASS(o))
34
35/* Name of class variable associated with thread interface */
36#define SPIF_THREADCLASS_VAR(type) spif_ ## type ## _threadclass
37
38/* Check if a thread is NULL */
39#define SPIF_THREAD_ISNULL(o) (SPIF_THREAD(o) == SPIF_NULL_TYPE(thread))
40
41/* Check if an object is a thread */
42#define SPIF_OBJ_IS_THREAD(o) SPIF_OBJ_IS_TYPE(o, thread)
43
44/* Call a method on an instance of an implementation class */
45#define SPIF_THREAD_CALL_METHOD(o, meth) SPIF_THREAD_CLASS(o)->meth
46
47/* Calls to the basic functions. */
48#define SPIF_THREAD_NEW(type) SPIF_THREAD((SPIF_CLASS(SPIF_THREADCLASS_VAR(type)))->noo())
49#define SPIF_THREAD_INIT(o) SPIF_OBJ_INIT(o)
50#define SPIF_THREAD_DONE(o) SPIF_OBJ_DONE(o)
51#define SPIF_THREAD_DEL(o) SPIF_OBJ_DEL(o)
52#define SPIF_THREAD_SHOW(o, b, i) SPIF_OBJ_SHOW(o, b, i)
53#define SPIF_THREAD_COMP(o1, o2) SPIF_OBJ_COMP(o1, o2)
54#define SPIF_THREAD_DUP(o) SPIF_OBJ_DUP(o)
55#define SPIF_THREAD_TYPE(o) SPIF_OBJ_TYPE(o)
56
57#define SPIF_THREAD_NEW_WITH_FUNC(type, f, d) SPIF_THREAD((SPIF_CLASS(SPIF_THREADCLASS_VAR(type)))->new_with_func((f), (d)))
58#define SPIF_THREAD_INIT_WITH_FUNC(o, f, d) SPIF_CAST(bool) ((SPIF_THREAD_CALL_METHOD((o), init_with_func))((o), (f), (d)))
59#define SPIF_THREAD_DETACH(o) SPIF_CAST(bool) ((SPIF_THREAD_CALL_METHOD((o), detach))(o))
60#define SPIF_THREAD_GET_CONDITION(o) SPIF_CAST(condition) ((SPIF_THREAD_CALL_METHOD((o), get_condition))())
61#define SPIF_THREAD_GET_MUTEX(o) SPIF_CAST(mutex) ((SPIF_THREAD_CALL_METHOD((o), get_mutex))())
62#define SPIF_THREAD_KILL(o, s) SPIF_CAST(bool) ((SPIF_THREAD_CALL_METHOD((o), kill))((o), (s)))
63#define SPIF_THREAD_RUN(o) SPIF_CAST(bool) ((SPIF_THREAD_CALL_METHOD((o), run))(o))
64#define SPIF_THREAD_TLS_CALLOC(o, c, s) SPIF_CAST(tls_handle) ((SPIF_THREAD_CALL_METHOD((o), tls_calloc))((o), (c), (s)))
65#define SPIF_THREAD_TLS_FREE(o, i) SPIF_CAST(bool) ((SPIF_THREAD_CALL_METHOD((o), tls_free))((o), (i)))
66#define SPIF_THREAD_TLS_GET(o, i) SPIF_CAST(ptr) ((SPIF_THREAD_CALL_METHOD((o), tls_get))((o), (i)))
67#define SPIF_THREAD_TLS_MALLOC(o, s) SPIF_CAST(tls_handle) ((SPIF_THREAD_CALL_METHOD((o), tls_malloc))((o), (s)))
68#define SPIF_THREAD_TLS_REALLOC(o, i, s) SPIF_CAST(bool) ((SPIF_THREAD_CALL_METHOD((o), tls_realloc))((o), (i), (s)))
69#define SPIF_THREAD_WAIT(o, c) SPIF_CAST(bool) ((SPIF_THREAD_CALL_METHOD((o), wait))((o), (c)))
70#define SPIF_THREAD_WAIT_FOR(o, t) SPIF_CAST(bool) ((SPIF_THREAD_CALL_METHOD((o), wait_for))((o), (t)))
71
72typedef spif_obj_t spif_thread_t;
73typedef spif_ptr_t spif_thread_data_t;
74typedef spif_thread_data_t (*spif_thread_func_t)(spif_thread_data_t);
75typedef spif_listidx_t spif_tls_handle_t;
76
77SPIF_DECL_OBJ(threadclass) {
78 SPIF_DECL_PARENT_TYPE(class);
79
80 spif_func_t new_with_func;
81 spif_func_t init_with_func;
82 spif_func_t detach;
83 spif_func_t get_condition;
84 spif_func_t get_mutex;
85 spif_func_t kill;
86 spif_func_t run;
87 spif_func_t tls_calloc;
88 spif_func_t tls_free;
89 spif_func_t tls_get;
90 spif_func_t tls_malloc;
91 spif_func_t tls_realloc;
92 spif_func_t wait;
93 spif_func_t wait_for;
94};
95
96#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
182dnl# 182dnl#
183AC_DEFUN([AST_IMLIB2_SUPPORT], [ 183AC_DEFUN([AST_IMLIB2_SUPPORT], [
184 AC_ARG_WITH(imlib, 184 AC_ARG_WITH(imlib,
185 [ --with-imlib[=DIR] compile with Imlib2 support (default)], 185 [ --with-imlib[=DIR] compile with Imlib2 support (default)],
186 [ 186 [
187 if test "$withval" != "no"; then 187 if test "$withval" != "no"; then
188 if test "$withval" != "yes"; then 188 if test "$withval" != "yes"; then
@@ -347,7 +347,7 @@ dnl# - arg 1 is the name of the env var to use
347dnl# 347dnl#
348AC_DEFUN([AST_ARG_DEBUG], [ 348AC_DEFUN([AST_ARG_DEBUG], [
349 AC_MSG_CHECKING(for debugging level) 349 AC_MSG_CHECKING(for debugging level)
350 AC_ARG_WITH(debugging, [ --with-debugging[=num] compile in debugging support. num >= 0], [ 350 AC_ARG_WITH(debugging, [ --with-debugging[=num] compile in debugging support. num >= 0], [
351 if test "$withval" = "yes"; then 351 if test "$withval" = "yes"; then
352 withval=4 352 withval=4
353 fi 353 fi
@@ -368,7 +368,7 @@ AC_DEFUN([AST_ARG_DEBUG], [
368]) 368])
369AC_DEFUN([AST_ARG_REGEXP], [ 369AC_DEFUN([AST_ARG_REGEXP], [
370 AC_ARG_WITH(regexp, 370 AC_ARG_WITH(regexp,
371 [ --with-regexp[=TYPE] specify the type of regular expression support (bsd, posix, pcre)], 371 [ --with-regexp[=TYPE] specify the type of regular expression support (bsd, posix, pcre)],
372 [$1=$withval], [$1=yes]) 372 [$1=$withval], [$1=yes])
373 AST_REGEXP_SUPPORT($1) 373 AST_REGEXP_SUPPORT($1)
374 AC_MSG_CHECKING(for regular expression support) 374 AC_MSG_CHECKING(for regular expression support)
@@ -377,7 +377,7 @@ AC_DEFUN([AST_ARG_REGEXP], [
377AC_DEFUN([AST_ARG_BACKQUOTE_EXEC], [ 377AC_DEFUN([AST_ARG_BACKQUOTE_EXEC], [
378 AC_MSG_CHECKING(if backquote execution support should be enabled) 378 AC_MSG_CHECKING(if backquote execution support should be enabled)
379 AC_ARG_WITH(backquote-exec, 379 AC_ARG_WITH(backquote-exec,
380 [ --without-backquote-exec disables the execution of commands from inside config files], 380 [ --without-backquote-exec disables the execution of commands from inside config files],
381 [ 381 [
382 if test "$withval" = "no"; then 382 if test "$withval" = "no"; then
383 AC_MSG_RESULT(no) 383 AC_MSG_RESULT(no)
@@ -688,3 +688,195 @@ exit(1);
688 AC_MSG_RESULT([unknown, assuming none]) 688 AC_MSG_RESULT([unknown, assuming none])
689 fi 689 fi
690]) 690])
691
692dnl# Taken from http://autoconf-archive.cryp.to/acx_pthread.html
693AC_DEFUN([AST_PTHREADS], [
694AC_REQUIRE([AC_CANONICAL_HOST])
695AC_LANG_SAVE
696AC_LANG_C
697ast_pthreads_ok=no
698
699# We used to check for pthread.h first, but this fails if pthread.h
700# requires special compiler flags (e.g. on True64 or Sequent).
701# It gets checked for in the link test anyway.
702
703# First of all, check if the user has set any of the PTHREAD_LIBS,
704# etcetera environment variables, and if threads linking works using
705# them:
706if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
707 save_CFLAGS="$CFLAGS"
708 CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
709 save_LIBS="$LIBS"
710 LIBS="$PTHREAD_LIBS $LIBS"
711 AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
712 AC_TRY_LINK_FUNC(pthread_join, ast_pthreads_ok=yes)
713 AC_MSG_RESULT($ast_pthreads_ok)
714 if test x"$ast_pthreads_ok" = xno; then
715 PTHREAD_LIBS=""
716 PTHREAD_CFLAGS=""
717 fi
718 LIBS="$save_LIBS"
719 CFLAGS="$save_CFLAGS"
720fi
721
722# We must check for the threads library under a number of different
723# names; the ordering is very important because some systems
724# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
725# libraries is broken (non-POSIX).
726
727# Create a list of thread flags to try. Items starting with a "-" are
728# C compiler flags, and other items are library names, except for "none"
729# which indicates that we try without any flags at all, and "pthread-config"
730# which is a program returning the flags for the Pth emulation library.
731
732ast_pthreads_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
733
734# The ordering *is* (sometimes) important. Some notes on the
735# individual items follow:
736
737# pthreads: AIX (must check this before -lpthread)
738# none: in case threads are in libc; should be tried before -Kthread and
739# other compiler flags to prevent continual compiler warnings
740# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
741# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
742# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
743# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
744# -pthreads: Solaris/gcc
745# -mthreads: Mingw32/gcc, Lynx/gcc
746# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
747# doesn't hurt to check since this sometimes defines pthreads too;
748# also defines -D_REENTRANT)
749# ... -mt is also the pthreads flag for HP/aCC
750# pthread: Linux, etcetera
751# --thread-safe: KAI C++
752# pthread-config: use pthread-config program (for GNU Pth library)
753
754case "${host_cpu}-${host_os}" in
755 *solaris*)
756
757 # On Solaris (at least, for some versions), libc contains stubbed
758 # (non-functional) versions of the pthreads routines, so link-based
759 # tests will erroneously succeed. (We need to link with -pthreads/-mt/
760 # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
761 # a function called by this macro, so we could check for that, but
762 # who knows whether they'll stub that too in a future libc.) So,
763 # we'll just look for -pthreads and -lpthread first:
764
765 ast_pthreads_flags="-pthreads pthread -mt -pthread $ast_pthreads_flags"
766 ;;
767esac
768
769if test x"$ast_pthreads_ok" = xno; then
770for flag in $ast_pthreads_flags; do
771
772 case $flag in
773 none)
774 AC_MSG_CHECKING([whether pthreads work without any flags])
775 ;;
776
777 -*)
778 AC_MSG_CHECKING([whether pthreads work with $flag])
779 PTHREAD_CFLAGS="$flag"
780 ;;
781
782 pthread-config)
783 AC_CHECK_PROG(ast_pthreads_config, pthread-config, yes, no)
784 if test x"$ast_pthreads_config" = xno; then continue; fi
785 PTHREAD_CFLAGS="`pthread-config --cflags`"
786 PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
787 ;;
788
789 *)
790 AC_MSG_CHECKING([for the pthreads library -l$flag])
791 PTHREAD_LIBS="-l$flag"
792 ;;
793 esac
794
795 save_LIBS="$LIBS"
796 save_CFLAGS="$CFLAGS"
797 LIBS="$PTHREAD_LIBS $LIBS"
798 CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
799
800 # Check for various functions. We must include pthread.h,
801 # since some functions may be macros. (On the Sequent, we
802 # need a special flag -Kthread to make this header compile.)
803 # We check for pthread_join because it is in -lpthread on IRIX
804 # while pthread_create is in libc. We check for pthread_attr_init
805 # due to DEC craziness with -lpthreads. We check for
806 # pthread_cleanup_push because it is one of the few pthread
807 # functions on Solaris that doesn't have a non-functional libc stub.
808 # We try pthread_create on general principles.
809 AC_TRY_LINK([#include <pthread.h>],
810 [pthread_t th; pthread_join(th, 0);
811 pthread_attr_init(0); pthread_cleanup_push(0, 0);
812 pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
813 [ast_pthreads_ok=yes])
814
815 LIBS="$save_LIBS"
816 CFLAGS="$save_CFLAGS"
817
818 AC_MSG_RESULT($ast_pthreads_ok)
819 if test "x$ast_pthreads_ok" = xyes; then
820 break;
821 fi
822
823 PTHREAD_LIBS=""
824 PTHREAD_CFLAGS=""
825done
826fi
827
828# Various other checks:
829if test "x$ast_pthreads_ok" = xyes; then
830 save_LIBS="$LIBS"
831 LIBS="$PTHREAD_LIBS $LIBS"
832 save_CFLAGS="$CFLAGS"
833 CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
834
835 # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
836 AC_MSG_CHECKING([for joinable pthread attribute])
837 attr_name=unknown
838 for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
839 AC_TRY_LINK([#include <pthread.h>], [int attr=$attr; return attr;],
840 [attr_name=$attr; break])
841 done
842 AC_MSG_RESULT($attr_name)
843 if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
844 AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
845 [Define to necessary symbol if this constant
846 uses a non-standard name on your system.])
847 fi
848
849 AC_MSG_CHECKING([if more special flags are required for pthreads])
850 flag=no
851 case "${host_cpu}-${host_os}" in
852 *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";;
853 *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";;
854 esac
855 AC_MSG_RESULT(${flag})
856 if test "x$flag" != xno; then
857 PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
858 fi
859
860 LIBS="$save_LIBS"
861 CFLAGS="$save_CFLAGS"
862
863 # More AIX lossage: must compile with cc_r
864 AC_CHECK_PROG(PTHREAD_CC, cc_r, cc_r, ${CC})
865else
866 PTHREAD_CC="$CC"
867fi
868
869AC_SUBST(PTHREAD_LIBS)
870AC_SUBST(PTHREAD_CFLAGS)
871AC_SUBST(PTHREAD_CC)
872
873# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
874if test x"$ast_pthreads_ok" = xyes; then
875 ifelse([$1],,AC_DEFINE(HAVE_PTHREADS,1,[Define if you have POSIX threads libraries and header files.]),[$1])
876 :
877else
878 ast_pthreads_ok=no
879 $2
880fi
881AC_LANG_RESTORE
882])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 @@
3lib_LTLIBRARIES = libast.la 3lib_LTLIBRARIES = libast.la
4 4
5INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/include/$(PACKAGE) 5INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/include/$(PACKAGE)
6AM_CFLAGS = $(PTHREAD_CFLAGS)
7AM_LDFLAGS = $(PTHREAD_LIBS)
6 8
7libast_la_SOURCES = \ 9libast_la_SOURCES = array.c builtin_hashes.c conf.c debug.c \
8 array.c builtin_hashes.c conf.c debug.c dlinked_list.c file.c \ 10dlinked_list.c file.c linked_list.c mbuff.c mem.c module.c msgs.c \
9 linked_list.c mbuff.c mem.c msgs.c obj.c objpair.c options.c \ 11obj.c objpair.c options.c pthreads.c regexp.c socket.c str.c strings.c \
10 regexp.c socket.c str.c strings.c snprintf.c tok.c url.c ustr.c 12snprintf.c tok.c url.c ustr.c
11 13
12libast_la_LDFLAGS = -version-info 2:1:0 14libast_la_LDFLAGS = -version-info 2:2:0
13MAINTAINERCLEANFILES = Makefile.in 15MAINTAINERCLEANFILES = 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)
728 } 728 }
729 729
730 left = self->len - i - 1; 730 left = self->len - i - 1;
731 printf("%d %d %d\n", i, left, self->len);
732 tmp = self->items[i]; 731 tmp = self->items[i];
733 memmove(self->items + i, self->items + i + 1, sizeof(spif_obj_t) * left); 732 memmove(self->items + i, self->items + i + 1, sizeof(spif_obj_t) * left);
734 self->len--; 733 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 @@
1/*
2 * Copyright (C) 1997-2004, Michael Jennings
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to
6 * deal in the Software without restriction, including without limitation the
7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 * sell copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies of the Software, its documentation and marketing & publicity
13 * materials, and acknowledgment shall be given in the documentation, materials
14 * and software packages that this Software was used.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24static const char __attribute__((unused)) cvs_ident[] = "$Id$";
25
26#ifdef HAVE_CONFIG_H
27# include <config.h>
28#endif
29
30#include <libast_internal.h>
31#include <dlfcn.h>
32
33/* *INDENT-OFF* */
34static SPIF_CONST_TYPE(moduleclass) s_class = {
35 {
36 SPIF_DECL_CLASSNAME(module),
37 (spif_func_t) spif_module_new,
38 (spif_func_t) spif_module_init,
39 (spif_func_t) spif_module_done,
40 (spif_func_t) spif_module_del,
41 (spif_func_t) spif_module_show,
42 (spif_func_t) spif_module_comp,
43 (spif_func_t) spif_module_dup,
44 (spif_func_t) spif_module_type
45 },
46 (spif_func_t) spif_module_call,
47 (spif_func_t) spif_module_getsym,
48 (spif_func_t) spif_module_load,
49 (spif_func_t) spif_module_run,
50 (spif_func_t) spif_module_unload,
51};
52SPIF_TYPE(class) SPIF_CLASS_VAR(module) = SPIF_CAST(class) &s_class;
53SPIF_TYPE(moduleclass) SPIF_MODULECLASS_VAR(module) = &s_class;
54/* *INDENT-ON* */
55
56static const size_t buff_inc = 4096;
57
58spif_module_t
59spif_module_new(void)
60{
61 spif_module_t self;
62
63 self = SPIF_ALLOC(module);
64 if (!spif_module_init(self)) {
65 SPIF_DEALLOC(self);
66 self = SPIF_NULL_TYPE(module);
67 }
68 return self;
69}
70
71spif_bool_t
72spif_module_init(spif_module_t self)
73{
74 ASSERT_RVAL(!SPIF_MODULE_ISNULL(self), FALSE);
75 /* ***NOT NEEDED*** spif_obj_init(SPIF_OBJ(self)); */
76 spif_obj_set_class(SPIF_OBJ(self), SPIF_CLASS(SPIF_MODULECLASS_VAR(module)));
77 self->name = SPIF_NULL_TYPE(str);
78 self->path = SPIF_NULL_TYPE(str);
79 self->module_handle = SPIF_NULL_TYPE(ptr);
80 self->main_handle = dlopen(NULL, RTLD_LAZY);
81 return TRUE;
82}
83
84spif_bool_t
85spif_module_done(spif_module_t self)
86{
87 spif_bool_t ret = TRUE;
88
89 ASSERT_RVAL(!SPIF_MODULE_ISNULL(self), FALSE);
90 if (self->module_handle) {
91 ret = spif_module_unload(self);
92 self->module_handle = SPIF_NULL_TYPE(ptr);
93 }
94 if (!SPIF_STR_ISNULL(self->name)) {
95 spif_str_del(self->name);
96 self->name = SPIF_NULL_TYPE(str);
97 }
98 if (!SPIF_STR_ISNULL(self->path)) {
99 spif_str_del(self->path);
100 self->path = SPIF_NULL_TYPE(str);
101 }
102 return ret;
103}
104
105spif_bool_t
106spif_module_del(spif_module_t self)
107{
108 ASSERT_RVAL(!SPIF_MODULE_ISNULL(self), FALSE);
109 spif_module_done(self);
110 dlclose(self->main_handle);
111 SPIF_DEALLOC(self);
112 return TRUE;
113}
114
115spif_str_t
116spif_module_show(spif_module_t self, spif_charptr_t name, spif_str_t buff, size_t indent)
117{
118 spif_char_t tmp[4096];
119
120 if (SPIF_MODULE_ISNULL(self)) {
121 SPIF_OBJ_SHOW_NULL(module, name, buff, indent, tmp);
122 return buff;
123 }
124
125 memset(tmp, ' ', indent);
126 snprintf(SPIF_CHARPTR_C(tmp) + indent, sizeof(tmp) - indent,
127 "(spif_module_t) %s: %10p { \"",
128 name, SPIF_CAST(ptr) self);
129 if (SPIF_STR_ISNULL(buff)) {
130 buff = spif_str_new_from_ptr(tmp);
131 } else {
132 spif_str_append_from_ptr(buff, tmp);
133 }
134
135 indent += 2;
136 if (indent < sizeof(tmp)) {
137 memset(tmp, ' ', indent);
138 }
139 buff = spif_str_show(self->name, SPIF_CHARPTR("name"), buff, indent);
140 buff = spif_str_show(self->path, SPIF_CHARPTR("path"), buff, indent);
141 snprintf(SPIF_CHARPTR_C(tmp) + indent, sizeof(tmp) - indent, "(spif_ptr_t) module_handle: 0x%p\n", self->module_handle);
142 spif_str_append_from_ptr(buff, tmp);
143
144 snprintf(SPIF_CHARPTR_C(tmp) + indent, sizeof(tmp) - indent, "(spif_ptr_t) main_handle: 0x%p\n", self->main_handle);
145 spif_str_append_from_ptr(buff, tmp);
146
147 snprintf(SPIF_CHARPTR_C(tmp), sizeof(tmp), "}\n");
148 spif_str_append_from_ptr(buff, tmp);
149 return buff;
150}
151
152spif_cmp_t
153spif_module_comp(spif_module_t self, spif_module_t other)
154{
155 spif_cmp_t ret;
156
157 SPIF_OBJ_COMP_CHECK_NULL(self, other);
158 SPIF_OBJ_COMP_CHECK_NULL(self->name, other->name);
159 if (!SPIF_CMP_IS_EQUAL(ret = spif_str_comp(self->name, other->name))) {
160 return ret;
161 }
162 SPIF_OBJ_COMP_CHECK_NULL(self->path, other->path);
163 if (!SPIF_CMP_IS_EQUAL(ret = spif_str_comp(self->path, other->path))) {
164 return ret;
165 }
166 return SPIF_CMP_FROM_INT((int) self->module_handle - (int) other->module_handle);
167}
168
169spif_module_t
170spif_module_dup(spif_module_t self)
171{
172 spif_module_t tmp;
173
174 ASSERT_RVAL(!SPIF_MODULE_ISNULL(self), SPIF_NULL_TYPE(module));
175 tmp = SPIF_ALLOC(module);
176 memcpy(tmp, self, SPIF_SIZEOF_TYPE(module));
177 tmp->name = spif_str_dup(self->name);
178 tmp->path = spif_str_dup(self->path);
179 return tmp;
180}
181
182spif_classname_t
183spif_module_type(spif_module_t self)
184{
185 ASSERT_RVAL(!SPIF_MODULE_ISNULL(self), SPIF_CAST(classname) SPIF_NULLSTR_TYPE(classname));
186 return SPIF_OBJ_CLASSNAME(self);
187}
188
189spif_ptr_t
190spif_module_call(spif_module_t self, spif_charptr_t fname, spif_ptr_t data)
191{
192 spif_func_t fp;
193 spif_charptr_t err;
194
195 fp = SPIF_CAST(func) spif_module_getsym(self, fname);
196 if (SPIF_PTR_ISNULL(err)) {
197 /* No error. Proceed. */
198 return (fp)(data);
199 } else {
200 libast_print_warning("Unable to call function %s() from module \"%s\" -- %s\n", fname, SPIF_STR_STR(self->name), err);
201 }
202 return SPIF_NULL_TYPE(ptr);
203}
204
205spif_ptr_t
206spif_module_getsym(spif_module_t self, spif_charptr_t sym)
207{
208 spif_ptr_t psym;
209 spif_charptr_t err;
210
211 ASSERT_RVAL(!SPIF_MODULE_ISNULL(self), SPIF_NULL_TYPE(ptr));
212 ASSERT_RVAL(!SPIF_PTR_ISNULL(sym), SPIF_NULL_TYPE(ptr));
213 REQUIRE_RVAL(!SPIF_PTR_ISNULL(self->main_handle), SPIF_NULL_TYPE(ptr));
214 dlerror();
215 psym = SPIF_CAST(ptr) dlsym(self->module_handle, (const char *) sym);
216 err = SPIF_CAST(charptr) dlerror();
217 if (SPIF_PTR_ISNULL(err)) {
218 /* No error. Proceed. */
219 return psym;
220 } else {
221 psym = SPIF_CAST(ptr) dlsym(self->main_handle, (const char *) sym);
222 err = SPIF_CAST(charptr) dlerror();
223 if (SPIF_PTR_ISNULL(err)) {
224 /* No error. Proceed. */
225 return psym;
226 } else {
227#ifdef RTLD_DEFAULT
228 psym = SPIF_CAST(ptr) dlsym(RTLD_DEFAULT, (const char *) sym);
229 err = SPIF_CAST(charptr) dlerror();
230 if (SPIF_PTR_ISNULL(err)) {
231 /* No error. Proceed. */
232 return psym;
233 } else
234#endif
235 libast_print_warning("Unable to resolve symbol \"%s\" from module \"%s\" -- %s\n", sym,
236 SPIF_STR_STR(self->name), err);
237 }
238 }
239 return SPIF_NULL_TYPE(ptr);
240}
241
242spif_bool_t
243spif_module_load(spif_module_t self)
244{
245 spif_func_t fp;
246
247 ASSERT_RVAL(!SPIF_MODULE_ISNULL(self), FALSE);
248 REQUIRE_RVAL(!SPIF_STR_ISNULL(self->path), FALSE);
249
250 if (SPIF_STR_ISNULL(self->name)) {
251 spif_stridx_t idx;
252
253 idx = spif_str_rindex(self->path, '/');
254 if (idx == spif_str_get_len(self->path)) {
255 self->name = spif_str_dup(self->path);
256 } else {
257 self->name = spif_str_substr(self->path, idx, 0);
258 }
259 }
260
261 self->module_handle = dlopen(SPIF_STR_STR(self->path), RTLD_LAZY | RTLD_GLOBAL);
262 if (SPIF_PTR_ISNULL(self->module_handle)) {
263 libast_print_error("Unable to dlopen() \"%s\" -- %s\n", SPIF_STR_STR(self->path), dlerror());
264 return FALSE;
265 }
266 fp = spif_module_getsym(self, "init");
267 if (fp) {
268 return (((fp)(self)) ? (TRUE) : (FALSE));
269 } else {
270 return TRUE;
271 }
272}
273
274spif_bool_t
275spif_module_run(spif_module_t self)
276{
277 return ((spif_module_call(self, "run", NULL)) ? (TRUE) : (FALSE));
278}
279
280spif_bool_t
281spif_module_unload(spif_module_t self)
282{
283 spif_func_t fp;
284
285 ASSERT_RVAL(!SPIF_MODULE_ISNULL(self), FALSE);
286 REQUIRE_RVAL(!SPIF_PTR_ISNULL(self->module_handle), FALSE);
287
288 fp = spif_module_getsym(self, "done");
289 if (fp) {
290 if (!(fp)()) {
291 return FALSE;
292 }
293 }
294
295 dlerror();
296 if (dlclose(self->module_handle)) {
297 libast_print_warning("Unable to dlclose() \"%s\" -- %s\n", SPIF_STR_STR(self->path), dlerror());
298 return FALSE;
299 }
300 self->module_handle = SPIF_NULL_TYPE(ptr);
301 return TRUE;
302}
303
304SPIF_DEFINE_PROPERTY_FUNC(module, str, name);
305SPIF_DEFINE_PROPERTY_FUNC(module, str, path);
306SPIF_DEFINE_PROPERTY_FUNC(module, ptr, module_handle);
307SPIF_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;
61spif_charptr_t libast_program_version = SPIF_CAST(charptr) VERSION; 61spif_charptr_t libast_program_version = SPIF_CAST(charptr) VERSION;
62 62
63/** 63/**
64 * Silence mode
65 *
66 * This variable determines whether or not error, warning, and
67 * debugging messages may be printed.
68 */
69static spif_bool_t silent = FALSE;
70
71/**
64 * Sets the program name. 72 * Sets the program name.
65 * 73 *
66 * This function is provided for safe and sane setting of the 74 * This function is provided for safe and sane setting of the
@@ -119,6 +127,22 @@ libast_set_program_version(const char *progversion)
119} 127}
120 128
121/** 129/**
130 * Sets silent mode.
131 *
132 * This function turns on/off error, warning, and debugging output.
133 *
134 * @param flag Boolean value to set silent flag
135 * @return The new value
136 *
137 * @see silent
138 */
139spif_bool_t
140libast_set_silent(spif_bool_t flag)
141{
142 return (silent = flag);
143}
144
145/**
122 * Prints debugging output. 146 * Prints debugging output.
123 * 147 *
124 * This function is the guts behing the D_*() and DPRINTF() families of 148 * This function is the guts behing the D_*() and DPRINTF() families of
@@ -140,6 +164,7 @@ libast_dprintf(const char *format, ...)
140 int n; 164 int n;
141 165
142 ASSERT_RVAL(!SPIF_PTR_ISNULL(format), SPIF_CAST_C(int) -1); 166 ASSERT_RVAL(!SPIF_PTR_ISNULL(format), SPIF_CAST_C(int) -1);
167 REQUIRE_RVAL(!silent, 0);
143 REQUIRE_RVAL(libast_program_name != NULL, 0); 168 REQUIRE_RVAL(libast_program_name != NULL, 0);
144 va_start(args, format); 169 va_start(args, format);
145 n = vfprintf(LIBAST_DEBUG_FD, format, args); 170 n = vfprintf(LIBAST_DEBUG_FD, format, args);
@@ -168,6 +193,7 @@ libast_print_error(const char *fmt, ...)
168 va_list arg_ptr; 193 va_list arg_ptr;
169 194
170 ASSERT(!SPIF_PTR_ISNULL(fmt)); 195 ASSERT(!SPIF_PTR_ISNULL(fmt));
196 REQUIRE(!silent);
171 REQUIRE(libast_program_name != NULL); 197 REQUIRE(libast_program_name != NULL);
172 va_start(arg_ptr, fmt); 198 va_start(arg_ptr, fmt);
173 fprintf(stderr, "%s: Error: ", libast_program_name); 199 fprintf(stderr, "%s: Error: ", libast_program_name);
@@ -195,6 +221,7 @@ libast_print_warning(const char *fmt, ...)
195 va_list arg_ptr; 221 va_list arg_ptr;
196 222
197 ASSERT(!SPIF_PTR_ISNULL(fmt)); 223 ASSERT(!SPIF_PTR_ISNULL(fmt));
224 REQUIRE(!silent);
198 REQUIRE(libast_program_name != NULL); 225 REQUIRE(libast_program_name != NULL);
199 va_start(arg_ptr, fmt); 226 va_start(arg_ptr, fmt);
200 fprintf(stderr, "%s: Warning: ", libast_program_name); 227 fprintf(stderr, "%s: Warning: ", libast_program_name);
@@ -222,7 +249,7 @@ libast_fatal_error(const char *fmt, ...)
222 va_list arg_ptr; 249 va_list arg_ptr;
223 250
224 ASSERT(!SPIF_PTR_ISNULL(fmt)); 251 ASSERT(!SPIF_PTR_ISNULL(fmt));
225 if (libast_program_name != NULL) { 252 if ((!silent) && (libast_program_name != NULL)) {
226 va_start(arg_ptr, fmt); 253 va_start(arg_ptr, fmt);
227 fprintf(stderr, "%s: FATAL: ", libast_program_name); 254 fprintf(stderr, "%s: FATAL: ", libast_program_name);
228 vfprintf(stderr, fmt, arg_ptr); 255 vfprintf(stderr, fmt, arg_ptr);
@@ -230,3 +257,4 @@ libast_fatal_error(const char *fmt, ...)
230 } 257 }
231 exit(-1); 258 exit(-1);
232} 259}
260
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 @@
1/*
2 * Copyright (C) 1997-2004, Michael Jennings
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to
6 * deal in the Software without restriction, including without limitation the
7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 * sell copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies of the Software, its documentation and marketing & publicity
13 * materials, and acknowledgment shall be given in the documentation, materials
14 * and software packages that this Software was used.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24static const char __attribute__((unused)) cvs_ident[] = "$Id$";
25
26#ifdef HAVE_CONFIG_H
27# include <config.h>
28#endif
29
30#include <libast_internal.h>
31#include <pthread.h>
32
33/* *INDENT-OFF* */
34static SPIF_CONST_TYPE(threadclass) pt_class = {
35 {
36 SPIF_DECL_CLASSNAME(pthreads),
37 (spif_func_t) spif_pthreads_new,
38 (spif_func_t) spif_pthreads_init,
39 (spif_func_t) spif_pthreads_done,
40 (spif_func_t) spif_pthreads_del,
41 (spif_func_t) spif_pthreads_show,
42 (spif_func_t) spif_pthreads_comp,
43 (spif_func_t) spif_pthreads_dup,
44 (spif_func_t) spif_pthreads_type
45 },
46 (spif_func_t) spif_pthreads_new_with_func,
47 (spif_func_t) spif_pthreads_init_with_func,
48 (spif_func_t) spif_pthreads_detach,
49 (spif_func_t) spif_pthreads_get_condition,
50 (spif_func_t) spif_pthreads_get_mutex,
51 (spif_func_t) spif_pthreads_kill,
52 (spif_func_t) spif_pthreads_run,
53 (spif_func_t) spif_pthreads_tls_calloc,
54 (spif_func_t) spif_pthreads_tls_free,
55 (spif_func_t) spif_pthreads_tls_get,
56 (spif_func_t) spif_pthreads_tls_malloc,
57 (spif_func_t) spif_pthreads_tls_realloc,
58 (spif_func_t) spif_pthreads_wait,
59 (spif_func_t) spif_pthreads_wait_for
60};
61SPIF_TYPE(class) SPIF_CLASS_VAR(pthreads) = SPIF_CAST(class) &pt_class;
62SPIF_TYPE(threadclass) SPIF_THREADCLASS_VAR(pthreads) = &pt_class;
63
64static SPIF_CONST_TYPE(mutexclass) ptm_class = {
65 {
66 SPIF_DECL_CLASSNAME(pthreads_mutex),
67 (spif_func_t) spif_pthreads_mutex_new,
68 (spif_func_t) spif_pthreads_mutex_init,
69 (spif_func_t) spif_pthreads_mutex_done,
70 (spif_func_t) spif_pthreads_mutex_del,
71 (spif_func_t) spif_pthreads_mutex_show,
72 (spif_func_t) spif_pthreads_mutex_comp,
73 (spif_func_t) spif_pthreads_mutex_dup,
74 (spif_func_t) spif_pthreads_mutex_type
75 },
76 (spif_func_t) spif_pthreads_mutex_lock,
77 (spif_func_t) spif_pthreads_mutex_lock_nowait,
78 (spif_func_t) spif_pthreads_mutex_unlock
79};
80SPIF_TYPE(class) SPIF_CLASS_VAR(pthreads_mutex) = SPIF_CAST(class) &ptm_class;
81SPIF_TYPE(mutexclass) SPIF_MUTEXCLASS_VAR(pthreads_mutex) = &ptm_class;
82
83static SPIF_CONST_TYPE(conditionclass) ptc_class = {
84 {
85 SPIF_DECL_CLASSNAME(pthreads_condition),
86 (spif_func_t) spif_pthreads_condition_new,
87 (spif_func_t) spif_pthreads_condition_init,
88 (spif_func_t) spif_pthreads_condition_done,
89 (spif_func_t) spif_pthreads_condition_del,
90 (spif_func_t) spif_pthreads_condition_show,
91 (spif_func_t) spif_pthreads_condition_comp,
92 (spif_func_t) spif_pthreads_condition_dup,
93 (spif_func_t) spif_pthreads_condition_type
94 },
95 (spif_func_t) spif_pthreads_condition_broadcast,
96 (spif_func_t) spif_pthreads_condition_signal,
97 (spif_func_t) spif_pthreads_condition_wait,
98 (spif_func_t) spif_pthreads_condition_wait_timed
99};
100SPIF_TYPE(class) SPIF_CLASS_VAR(pthreads_condition) = SPIF_CAST(class) &ptc_class;
101SPIF_TYPE(conditionclass) SPIF_CONDITIONCLASS_VAR(pthreads_condition) = &ptc_class;
102/* *INDENT-ON* */
103
104static void spif_pthreads_tls_destructor(void *ptr);
105
106spif_pthreads_t
107spif_pthreads_new(void)
108{
109 spif_pthreads_t self;
110
111 self = SPIF_ALLOC(pthreads);
112 if (!spif_pthreads_init(self)) {
113 SPIF_DEALLOC(self);
114 self = SPIF_NULL_TYPE(pthreads);
115 }
116 return self;
117}
118
119spif_pthreads_t
120spif_pthreads_new_with_func(spif_thread_func_t func, spif_thread_data_t data)
121{
122 spif_pthreads_t self;
123
124 self = SPIF_ALLOC(pthreads);
125 if (!spif_pthreads_init_with_func(self, func, data)) {
126 SPIF_DEALLOC(self);
127 self = SPIF_NULL_TYPE(pthreads);
128 }
129 return self;
130}
131
132spif_bool_t
133spif_pthreads_init(spif_pthreads_t self)
134{
135 ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), FALSE);
136 /* ***NOT NEEDED*** spif_obj_init(SPIF_OBJ(self)); */
137 spif_obj_set_class(SPIF_OBJ(self), SPIF_CLASS(SPIF_THREADCLASS_VAR(pthreads)));
138 self->handle = (pthread_t) 0;
139 self->creator = (pthread_t) 0;
140 pthread_attr_init(&self->attr);
141 self->main_func = SPIF_NULL_TYPE(thread_func);
142 self->data = SPIF_NULL_TYPE(thread_data);
143 self->tls_keys = SPIF_NULL_TYPE(list);
144 return TRUE;
145}
146
147spif_bool_t
148spif_pthreads_init_with_func(spif_pthreads_t self, spif_thread_func_t func, spif_thread_data_t data)
149{
150 ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), FALSE);
151 /* ***NOT NEEDED*** spif_obj_init(SPIF_OBJ(self)); */
152 spif_obj_set_class(SPIF_OBJ(self), SPIF_CLASS(SPIF_THREADCLASS_VAR(pthreads)));
153 self->handle = (pthread_t) 0;
154 self->creator = (pthread_t) 0;
155 pthread_attr_init(&self->attr);
156 self->main_func = func;
157 self->data = data;
158 self->tls_keys = SPIF_NULL_TYPE(list);
159 return TRUE;
160}
161
162spif_bool_t
163spif_pthreads_done(spif_pthreads_t self)
164{
165 spif_bool_t ret = TRUE;
166
167 ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), FALSE);
168 if (self->handle) {
169 spif_pthreads_kill(self, SIGTERM);
170 self->handle = (pthread_t) 0;
171 }
172 self->creator = pthread_self();
173 pthread_attr_destroy(&self->attr);
174 pthread_attr_init(&self->attr);
175 self->main_func = SPIF_NULL_TYPE(thread_func);
176 if (self->tls_keys) {
177 SPIF_LIST_DEL(self->tls_keys);
178 self->tls_keys = SPIF_NULL_TYPE(list);
179 }
180 return ret;
181}
182
183spif_bool_t
184spif_pthreads_del(spif_pthreads_t self)
185{
186 ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), FALSE);
187 spif_pthreads_done(self);
188 SPIF_DEALLOC(self);
189 return TRUE;
190}
191
192spif_str_t
193spif_pthreads_show(spif_pthreads_t self, spif_charptr_t name, spif_str_t buff, size_t indent)
194{
195 spif_char_t tmp[4096];
196
197 if (SPIF_PTHREADS_ISNULL(self)) {
198 SPIF_OBJ_SHOW_NULL(pthreads, name, buff, indent, tmp);
199 return buff;
200 }
201
202 memset(tmp, ' ', indent);
203 snprintf(SPIF_CHARPTR_C(tmp) + indent, sizeof(tmp) - indent,
204 "(spif_pthreads_t) %s: %10p { \"",
205 name, SPIF_CAST(ptr) self);
206 if (SPIF_STR_ISNULL(buff)) {
207 buff = spif_str_new_from_ptr(tmp);
208 } else {
209 spif_str_append_from_ptr(buff, tmp);
210 }
211
212 indent += 2;
213 if (indent < sizeof(tmp)) {
214 memset(tmp, ' ', indent);
215 }
216 snprintf(SPIF_CHARPTR_C(tmp) + indent, sizeof(tmp) - indent, "(pthread_t) handle: %ld\n", (long) self->handle);
217 spif_str_append_from_ptr(buff, tmp);
218
219 snprintf(SPIF_CHARPTR_C(tmp) + indent, sizeof(tmp) - indent, "(pthread_t) creator: %ld\n", (long) self->creator);
220 spif_str_append_from_ptr(buff, tmp);
221
222 snprintf(SPIF_CHARPTR_C(tmp) + indent, sizeof(tmp) - indent, "(pthread_attr_t) attr: %10p {...}\n", &self->attr);
223 spif_str_append_from_ptr(buff, tmp);
224
225 snprintf(SPIF_CHARPTR_C(tmp) + indent, sizeof(tmp) - indent, "(spif_thread_func_t) main_func: %10p\n", self->main_func);
226 spif_str_append_from_ptr(buff, tmp);
227
228 snprintf(SPIF_CHARPTR_C(tmp) + indent, sizeof(tmp) - indent, "(spif_thread_data_t) data: %10p\n", self->data);
229 spif_str_append_from_ptr(buff, tmp);
230
231 if (SPIF_LIST_ISNULL(self->tls_keys)) {
232 SPIF_OBJ_SHOW_NULL(list, "tls_keys", buff, indent, tmp);
233 } else {
234 buff = SPIF_LIST_SHOW(self->tls_keys, buff, indent);
235 }
236
237 snprintf(SPIF_CHARPTR_C(tmp), sizeof(tmp), "}\n");
238 spif_str_append_from_ptr(buff, tmp);
239 return buff;
240}
241
242spif_cmp_t
243spif_pthreads_comp(spif_pthreads_t self, spif_pthreads_t other)
244{
245 SPIF_OBJ_COMP_CHECK_NULL(self, other);
246 if (pthread_equal(self->handle, other->handle)) {
247 return SPIF_CMP_EQUAL;
248 }
249 return SPIF_OBJ_COMP(self, other);
250}
251
252spif_pthreads_t
253spif_pthreads_dup(spif_pthreads_t self)
254{
255 spif_pthreads_t tmp;
256
257 ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), SPIF_NULL_TYPE(pthreads));
258 tmp = SPIF_ALLOC(pthreads);
259 memcpy(tmp, self, SPIF_SIZEOF_TYPE(pthreads));
260 tmp->tls_keys = SPIF_LIST_DUP(self->tls_keys);
261 return tmp;
262}
263
264spif_classname_t
265spif_pthreads_type(spif_pthreads_t self)
266{
267 ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), SPIF_CAST(classname) SPIF_NULLSTR_TYPE(classname));
268 return SPIF_OBJ_CLASSNAME(self);
269}
270
271spif_bool_t
272spif_pthreads_detach(spif_pthreads_t self)
273{
274 int ret;
275
276 ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), FALSE);
277 REQUIRE_RVAL(self->handle, FALSE);
278
279 ret = pthread_detach(self->handle);
280 if (!ret) {
281 return TRUE;
282 } else if ((errno == EINVAL) || (ret == EINVAL)) {
283 return TRUE;
284 } else {
285 return FALSE;
286 }
287}
288
289spif_condition_t
290spif_pthreads_get_condition(spif_pthreads_t self)
291{
292 spif_pthreads_condition_t cond;
293
294 ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), SPIF_NULL_TYPE(condition));
295 cond = spif_pthreads_condition_new();
296 spif_pthreads_mutex_set_creator(SPIF_PTHREADS_MUTEX(cond), SPIF_THREAD(self));
297 return SPIF_CAST(condition) cond;
298}
299
300spif_mutex_t
301spif_pthreads_get_mutex(spif_pthreads_t self)
302{
303 spif_pthreads_mutex_t mutex;
304
305 ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), SPIF_NULL_TYPE(mutex));
306 mutex = spif_pthreads_mutex_new();
307 spif_pthreads_mutex_set_creator(mutex, SPIF_THREAD(self));
308 return SPIF_CAST(mutex) mutex;
309}
310
311spif_bool_t
312spif_pthreads_kill(spif_pthreads_t self, int sig)
313{
314 ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), FALSE);
315 REQUIRE_RVAL(self->handle, FALSE);
316
317 return ((pthread_kill(self->handle, sig)) ? (FALSE) : (TRUE));
318}
319
320spif_bool_t
321spif_pthreads_run(spif_pthreads_t self)
322{
323 ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), FALSE);
324 REQUIRE_RVAL(self->main_func != SPIF_NULL_TYPE(thread_func), FALSE);
325 REQUIRE_RVAL(self->handle == (pthread_t) 0, FALSE);
326
327 if (!pthread_create(&self->handle, &self->attr, self->main_func, self)) {
328 return TRUE;
329 } else {
330 return FALSE;
331 }
332}
333
334spif_tls_handle_t
335spif_pthreads_tls_calloc(spif_pthreads_t self, size_t count, size_t size)
336{
337 spif_tls_handle_t handle;
338 spif_ptr_t data;
339
340 ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), SPIF_CAST(tls_handle) -1);
341 REQUIRE_RVAL(count, SPIF_CAST(tls_handle) -1);
342 REQUIRE_RVAL(size, SPIF_CAST(tls_handle) -1);
343
344 handle = spif_pthreads_tls_malloc(self, count * size);
345 data = spif_pthreads_tls_get(self, handle);
346 MEMSET(data, 0, count * size);
347 return handle;
348}
349
350spif_bool_t
351spif_pthreads_tls_free(spif_pthreads_t self, spif_tls_handle_t handle)
352{
353 spif_mbuff_t key;
354
355 ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), FALSE);
356 REQUIRE_RVAL(!SPIF_LIST_ISNULL(self->tls_keys), FALSE);
357
358 key = SPIF_CAST(mbuff) SPIF_LIST_REMOVE_AT(self->tls_keys, handle);
359 if (handle != SPIF_LIST_COUNT(self->tls_keys)) {
360 /* If this isn't the last item in our list, insert an empty placeholder
361 so that numeric indexes which have already been given out will remain valid. */
362 SPIF_LIST_INSERT_AT(self->tls_keys, SPIF_NULL_TYPE(obj), handle);
363 }
364 if (!SPIF_MBUFF_ISNULL(key)) {
365 spif_ptr_t ptr;
366
367 ptr = SPIF_CAST(ptr) pthread_getspecific(*((pthread_key_t *) SPIF_MBUFF_BUFF(key)));
368 if (ptr && !pthread_key_delete(*((pthread_key_t *) SPIF_MBUFF_BUFF(key)))) {
369 FREE(ptr);
370 return TRUE;
371 }
372 }
373 return FALSE;
374}
375
376spif_ptr_t
377spif_pthreads_tls_get(spif_pthreads_t self, spif_tls_handle_t handle)
378{
379 spif_mbuff_t key;
380
381 ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), SPIF_NULL_TYPE(ptr));
382 REQUIRE_RVAL(!SPIF_LIST_ISNULL(self->tls_keys), FALSE);
383
384 key = SPIF_CAST(mbuff) SPIF_LIST_GET(self->tls_keys, handle);
385 if (!SPIF_MBUFF_ISNULL(key)) {
386 return (SPIF_CAST(ptr) pthread_getspecific(*((pthread_key_t *) SPIF_MBUFF_BUFF(key))));
387 }
388 return SPIF_NULL_TYPE(ptr);
389}
390
391spif_tls_handle_t
392spif_pthreads_tls_malloc(spif_pthreads_t self, spif_memidx_t size)
393{
394 pthread_key_t key;
395 spif_ptr_t ptr;
396
397 ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), SPIF_CAST(tls_handle) -1);
398
399 if (SPIF_LIST_ISNULL(self->tls_keys)) {
400 self->tls_keys = SPIF_LIST_NEW(array);
401 }
402 ptr = MALLOC(size);
403
404 if (!pthread_key_create(&key, spif_pthreads_tls_destructor)) {
405 spif_mbuff_t tls_key;
406
407 /* Store the pointer. */
408 pthread_setspecific(key, ptr);
409
410 /* The key is actually copied into the mbuff buffer. */
411 tls_key = spif_mbuff_new_from_ptr(SPIF_CAST(byteptr) &key, sizeof(pthread_key_t));
412
413 /* Since the pointer returned by MALLOC() is only stored locally in
414 this function and as keyed in the TLS data store, it cannot be
415 retrieved by any other thread. Thus, thread-local storage. Yay! */
416 if (SPIF_LIST_APPEND(self->tls_keys, tls_key)) {
417 return (SPIF_LIST_COUNT(self->tls_keys) - 1);
418 }
419 }
420 return (SPIF_CAST(tls_handle) -1);
421}
422
423static void
424spif_pthreads_tls_destructor(void *ptr)
425{
426 FREE(ptr);
427}
428
429spif_bool_t
430spif_pthreads_tls_realloc(spif_pthreads_t self, spif_tls_handle_t handle, spif_memidx_t size)
431{
432 spif_mbuff_t key;
433
434 ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), FALSE);
435 REQUIRE_RVAL(!SPIF_LIST_ISNULL(self->tls_keys), FALSE);
436
437 key = SPIF_CAST(mbuff) SPIF_LIST_GET(self->tls_keys, handle);
438 if (!SPIF_MBUFF_ISNULL(key)) {
439 spif_ptr_t ptr;
440
441 ptr = SPIF_CAST(ptr) pthread_getspecific(*((pthread_key_t *) SPIF_MBUFF_BUFF(key)));
442 if (ptr) {
443 ptr = REALLOC(ptr, size);
444 if (ptr) {
445 pthread_setspecific(*((pthread_key_t *) SPIF_MBUFF_BUFF(key)), ptr);
446 return TRUE;
447 }
448 }
449 }
450 return FALSE;
451}
452
453spif_bool_t
454spif_pthreads_wait(spif_pthreads_t self, spif_condition_t cond)
455{
456 ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), FALSE);
457 ASSERT_RVAL(!SPIF_PTHREADS_CONDITION_ISNULL(SPIF_PTHREADS_CONDITION(cond)), FALSE);
458}
459
460spif_bool_t
461spif_pthreads_wait_for(spif_pthreads_t self, spif_pthreads_t other)
462{
463 ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(self), FALSE);
464 ASSERT_RVAL(!SPIF_PTHREADS_ISNULL(other), FALSE);
465}
466
467SPIF_DEFINE_PROPERTY_FUNC_C(pthreads, pthread_t, handle);
468SPIF_DEFINE_PROPERTY_FUNC_C(pthreads, pthread_t, creator);
469SPIF_DEFINE_PROPERTY_FUNC_C(pthreads, pthread_attr_t, attr);
470SPIF_DEFINE_PROPERTY_FUNC(pthreads, thread_func, main_func);
471SPIF_DEFINE_PROPERTY_FUNC(pthreads, thread_data, data);
472SPIF_DEFINE_PROPERTY_FUNC(pthreads, list, tls_keys);
473
474spif_pthreads_mutex_t
475spif_pthreads_mutex_new(void)
476{
477 spif_pthreads_mutex_t self;
478
479 self = SPIF_ALLOC(pthreads_mutex);
480 if (!spif_pthreads_mutex_init(self)) {
481 SPIF_DEALLOC(self);
482 self = SPIF_NULL_TYPE(pthreads_mutex);
483 }
484 return self;
485}
486
487spif_bool_t
488spif_pthreads_mutex_init(spif_pthreads_mutex_t self)
489{
490 ASSERT_RVAL(!SPIF_PTHREADS_MUTEX_ISNULL(self), FALSE);
491 /* ***NOT NEEDED*** spif_obj_init(SPIF_OBJ(self)); */
492 spif_obj_set_class(SPIF_OBJ(self), SPIF_CLASS(SPIF_MUTEXCLASS_VAR(pthreads_mutex)));
493 self->creator = SPIF_NULL_TYPE(thread);
494 pthread_mutex_init(&self->mutex, NULL);
495 return TRUE;
496}
497
498spif_bool_t
499spif_pthreads_mutex_done(spif_pthreads_mutex_t self)
500{
501 spif_bool_t ret = TRUE;
502
503 ASSERT_RVAL(!SPIF_PTHREADS_MUTEX_ISNULL(self), FALSE);
504 self->creator = SPIF_NULL_TYPE(thread);
505 if (!pthread_mutex_unlock(&self->mutex)) {
506 /* It was locked. Destroy it. */
507 pthread_mutex_destroy(&self->mutex);
508 }
509 pthread_mutex_init(&self->mutex, NULL);
510 return ret;
511}
512
513spif_bool_t
514spif_pthreads_mutex_del(spif_pthreads_mutex_t self)
515{
516 ASSERT_RVAL(!SPIF_PTHREADS_MUTEX_ISNULL(self), FALSE);
517 spif_pthreads_mutex_done(self);
518 SPIF_DEALLOC(self);
519 return TRUE;
520}
521
522spif_str_t
523spif_pthreads_mutex_show(spif_pthreads_mutex_t self, spif_charptr_t name, spif_str_t buff, size_t indent)
524{
525 spif_char_t tmp[4096];
526
527 if (SPIF_PTHREADS_MUTEX_ISNULL(self)) {
528 SPIF_OBJ_SHOW_NULL(pthreads_mutex, name, buff, indent, tmp);
529 return buff;
530 }
531
532 memset(tmp, ' ', indent);
533 snprintf(SPIF_CHARPTR_C(tmp) + indent, sizeof(tmp) - indent,
534 "(spif_pthreads_mutex_t) %s: %10p { \"",
535 name, SPIF_CAST(ptr) self);
536 if (SPIF_STR_ISNULL(buff)) {
537 buff = spif_str_new_from_ptr(tmp);
538 } else {
539 spif_str_append_from_ptr(buff, tmp);
540 }
541
542 indent += 2;
543 if (indent < sizeof(tmp)) {
544 memset(tmp, ' ', indent);
545 }
546 if (SPIF_THREAD_ISNULL(self->creator)) {
547 SPIF_OBJ_SHOW_NULL(thread, "creator", buff, indent, tmp);
548 } else {
549 buff = SPIF_THREAD_SHOW(self->creator, buff, indent);
550 }
551
552 snprintf(SPIF_CHARPTR_C(tmp) + indent, sizeof(tmp) - indent, "(pthread_mutex_t) mutex: %10p {...}\n", &self->mutex);
553 spif_str_append_from_ptr(buff, tmp);
554
555 snprintf(SPIF_CHARPTR_C(tmp), sizeof(tmp), "}\n");
556 spif_str_append_from_ptr(buff, tmp);
557 return buff;
558}
559
560spif_cmp_t
561spif_pthreads_mutex_comp(spif_pthreads_mutex_t self, spif_pthreads_mutex_t other)
562{
563 SPIF_OBJ_COMP_CHECK_NULL(self, other);
564 return SPIF_OBJ_COMP(self, other);
565}
566
567spif_pthreads_mutex_t
568spif_pthreads_mutex_dup(spif_pthreads_mutex_t self)
569{
570 spif_pthreads_mutex_t tmp;
571
572 ASSERT_RVAL(!SPIF_PTHREADS_MUTEX_ISNULL(self), SPIF_NULL_TYPE(pthreads_mutex));
573 tmp = SPIF_ALLOC(pthreads_mutex);
574 memcpy(tmp, self, SPIF_SIZEOF_TYPE(pthreads_mutex));
575 return tmp;
576}
577
578spif_classname_t
579spif_pthreads_mutex_type(spif_pthreads_mutex_t self)
580{
581 ASSERT_RVAL(!SPIF_PTHREADS_MUTEX_ISNULL(self), SPIF_CAST(classname) SPIF_NULLSTR_TYPE(classname));
582 return SPIF_OBJ_CLASSNAME(self);
583}
584
585spif_bool_t
586spif_pthreads_mutex_lock(spif_pthreads_mutex_t self)
587{
588
589}
590
591spif_bool_t
592spif_pthreads_mutex_lock_nowait(spif_pthreads_mutex_t self)
593{
594
595}
596
597spif_bool_t
598spif_pthreads_mutex_unlock(spif_pthreads_mutex_t self)
599{
600
601}
602
603SPIF_DEFINE_PROPERTY_FUNC(pthreads_mutex, thread, creator);
604SPIF_DEFINE_PROPERTY_FUNC_C(pthreads_mutex, pthread_mutex_t, mutex);
605
606spif_pthreads_condition_t
607spif_pthreads_condition_new(void)
608{
609 spif_pthreads_condition_t self;
610
611 self = SPIF_ALLOC(pthreads_condition);
612 if (!spif_pthreads_condition_init(self)) {
613 SPIF_DEALLOC(self);
614 self = SPIF_NULL_TYPE(pthreads_condition);
615 }
616 return self;
617}
618
619spif_bool_t
620spif_pthreads_condition_init(spif_pthreads_condition_t self)
621{
622 ASSERT_RVAL(!SPIF_PTHREADS_CONDITION_ISNULL(self), FALSE);
623 spif_pthreads_mutex_init(SPIF_PTHREADS_MUTEX(self));
624 spif_obj_set_class(SPIF_OBJ(self), SPIF_CLASS(SPIF_CONDITIONCLASS_VAR(pthreads_condition)));
625 pthread_cond_init(&self->cond, NULL);
626 return TRUE;
627}
628
629spif_bool_t
630spif_pthreads_condition_done(spif_pthreads_condition_t self)
631{
632 spif_bool_t ret = TRUE;
633
634 ASSERT_RVAL(!SPIF_PTHREADS_CONDITION_ISNULL(self), FALSE);
635 ret = spif_pthreads_mutex_done(SPIF_PTHREADS_MUTEX(self));
636 pthread_cond_destroy(&self->cond);
637 pthread_cond_init(&self->cond, NULL);
638 return ret;
639}
640
641spif_bool_t
642spif_pthreads_condition_del(spif_pthreads_condition_t self)
643{
644 ASSERT_RVAL(!SPIF_PTHREADS_CONDITION_ISNULL(self), FALSE);
645 spif_pthreads_condition_done(self);
646 SPIF_DEALLOC(self);
647 return TRUE;
648}
649
650spif_str_t
651spif_pthreads_condition_show(spif_pthreads_condition_t self, spif_charptr_t name, spif_str_t buff, size_t indent)
652{
653 spif_char_t tmp[4096];
654
655 if (SPIF_PTHREADS_CONDITION_ISNULL(self)) {
656 SPIF_OBJ_SHOW_NULL(pthreads_condition, name, buff, indent, tmp);
657 return buff;
658 }
659
660 memset(tmp, ' ', indent);
661 snprintf(SPIF_CHARPTR_C(tmp) + indent, sizeof(tmp) - indent,
662 "(spif_pthreads_condition_t) %s: %10p { \"",
663 name, SPIF_CAST(ptr) self);
664 if (SPIF_STR_ISNULL(buff)) {
665 buff = spif_str_new_from_ptr(tmp);
666 } else {
667 spif_str_append_from_ptr(buff, tmp);
668 }
669
670 indent += 2;
671 if (indent < sizeof(tmp)) {
672 memset(tmp, ' ', indent);
673 }
674 buff = spif_pthreads_mutex_show(SPIF_PTHREADS_MUTEX(self), "self", buff, indent);
675
676 snprintf(SPIF_CHARPTR_C(tmp) + indent, sizeof(tmp) - indent, "(pthread_cond_t) cond: %10p {...}\n", &self->cond);
677 spif_str_append_from_ptr(buff, tmp);
678
679 snprintf(SPIF_CHARPTR_C(tmp), sizeof(tmp), "}\n");
680 spif_str_append_from_ptr(buff, tmp);
681 return buff;
682}
683
684spif_cmp_t
685spif_pthreads_condition_comp(spif_pthreads_condition_t self, spif_pthreads_condition_t other)
686{
687 SPIF_OBJ_COMP_CHECK_NULL(self, other);
688 return SPIF_OBJ_COMP(self, other);
689}
690
691spif_pthreads_condition_t
692spif_pthreads_condition_dup(spif_pthreads_condition_t self)
693{
694 spif_pthreads_condition_t tmp;
695
696 ASSERT_RVAL(!SPIF_PTHREADS_CONDITION_ISNULL(self), SPIF_NULL_TYPE(pthreads_condition));
697 tmp = SPIF_ALLOC(pthreads_condition);
698 memcpy(tmp, self, SPIF_SIZEOF_TYPE(pthreads_condition));
699 return tmp;
700}
701
702spif_classname_t
703spif_pthreads_condition_type(spif_pthreads_condition_t self)
704{
705 ASSERT_RVAL(!SPIF_PTHREADS_CONDITION_ISNULL(self), SPIF_CAST(classname) SPIF_NULLSTR_TYPE(classname));
706 return SPIF_OBJ_CLASSNAME(self);
707}
708
709spif_bool_t
710spif_pthreads_condition_broadcast(spif_pthreads_condition_t self)
711{
712
713}
714
715spif_bool_t
716spif_pthreads_condition_signal(spif_pthreads_condition_t self)
717{
718
719}
720
721spif_bool_t
722spif_pthreads_condition_wait(spif_pthreads_condition_t self)
723{
724
725}
726
727spif_bool_t
728spif_pthreads_condition_wait_timed(spif_pthreads_condition_t self, spif_int32_t delay)
729{
730
731}
732
733SPIF_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;
35int test_macros(void); 35int test_macros(void);
36int test_mem(void); 36int test_mem(void);
37int test_strings(void); 37int test_strings(void);
38int test_hash_functions(void);
39int test_snprintf(void); 38int test_snprintf(void);
40int test_options(void); 39int test_options(void);
41int test_obj(void); 40int test_obj(void);
@@ -49,6 +48,8 @@ int test_vector(void);
49int test_map(void); 48int test_map(void);
50int test_socket(void); 49int test_socket(void);
51int test_regexp(void); 50int test_regexp(void);
51int test_module(void);
52int test_hash_functions(void);
52 53
53int 54int
54test_macros(void) 55test_macros(void)
@@ -263,227 +264,6 @@ test_strings(void)
263 return 0; 264 return 0;
264} 265}
265 266
266#define MAXPAIR 80
267#define MAXLEN 80
268int
269test_hash_functions(void)
270{
271 spif_uint8_t i;
272
273 for (i = 0; i < 6; i++) {
274 spifhash_func_t hash_func;
275 spif_uint32_t key_length, input_byte, trials, successes = 0, hash, ref_hash;
276 spif_uint8_t buff[MAXLEN + 20], *pbuff;
277 spif_uint8_t align1[] = "This has got the amazing aroma of bovine fecal matter...";
278 spif_uint8_t align2[] = "xThis has got the amazing aroma of bovine fecal matter...";
279 spif_uint8_t align3[] = "xxThis has got the amazing aroma of bovine fecal matter...";
280 spif_uint8_t align4[] = "xxxThis has got the amazing aroma of bovine fecal matter...";
281 spif_uint32_t j;
282
283 if (i == 0) {
284 TEST_NOTICE("*** Testing Jenkins hash:");
285 hash_func = spifhash_jenkins;
286 } else if (i == 1) {
287 TEST_NOTICE("*** Testing Jenkins32 hash:");
288 hash_func = spifhash_jenkins32;
289 } else if (i == 2) {
290#if WORDS_BIGENDIAN
291 continue;
292#else
293 TEST_NOTICE("*** Testing JenkinsLE hash:");
294 hash_func = spifhash_jenkinsLE;
295#endif
296 } else if (i == 3) {
297 TEST_NOTICE("*** Testing rotating hash:");
298 hash_func = spifhash_rotating;
299 } else if (i == 4) {
300 TEST_NOTICE("*** Testing one-at-a-time hash:");
301 hash_func = spifhash_one_at_a_time;
302 } else if (i == 5) {
303 TEST_NOTICE("*** Testing FNV hash:");
304 hash_func = spifhash_fnv;
305 }
306
307 TEST_BEGIN("effect of every input bit on every output bit");
308 for (key_length = 0; key_length < MAXLEN; key_length++) {
309 /* For each key length up to 70 bytes... */
310
311 if ((hash_func == spifhash_jenkins32)
312 && (key_length % 4)) {
313 successes++;
314 continue;
315 }
316 trials = 0;
317 for (input_byte = 0; input_byte < key_length; input_byte++) {
318 /* ...for each input byte... */
319 spif_uint32_t input_bit;
320
321 for (input_bit = 0; input_bit < 8; input_bit++) {
322 /* ...for each input bit... */
323 spif_uint32_t seed;
324
325 for (seed = 1; seed < 8; seed++) {
326 /* ...use several possible seeds... */
327 spif_uint32_t e, f, g, h, x, y;
328 spif_uint32_t bit_pair;
329
330 /* Initialize to ~0 (0xffffffff). */
331 e = f = g = h = x = y = ~(SPIF_CAST(uint32) 0);
332
333 /* ...to make sure every output bit is affected by every input bit. */
334 for (bit_pair = 0; bit_pair < MAXPAIR; bit_pair += 2) {
335 spif_uint8_t buff1[MAXLEN + 1], buff2[MAXLEN + 2];
336 spif_uint8_t *pbuff1 = &buff1[0], *pbuff2 = &buff2[1];
337 spif_uint32_t hash1, hash2;
338
339 for (j = 0; j < key_length + 1; j++) {
340 /* Initialize keys to all zeros. */
341 pbuff1[j] = pbuff2[j] = (spif_uint8_t) 0;
342 }
343
344 /* Then make them differ by exactly one bit, the input_bit.
345 bit_pair will always end in 0, so bit_pair + 1 will always
346 end in 1. It's then shifted by input_bit to test the
347 current bit to test all 8 of the lowest bits in sequence. */
348 pbuff1[input_byte] ^= (bit_pair << input_bit);
349 pbuff1[input_byte] ^= (bit_pair >> (8 - input_bit));
350 pbuff2[input_byte] ^= ((bit_pair + 1) << input_bit);
351 pbuff2[input_byte] ^= ((bit_pair + 1) >> (8 - input_bit));
352
353 /* Hash them. */
354 if (hash_func == spifhash_jenkins32) {
355 hash1 = hash_func(pbuff1, key_length / 4, seed);
356 hash2 = hash_func(pbuff2, key_length / 4, seed);
357 } else {
358 hash1 = hash_func(pbuff1, key_length, seed);
359 hash2 = hash_func(pbuff2, key_length, seed);
360 }
361
362 /* Make sure every bit is 1 or 0 at least once. */
363 e &= (hash1 ^ hash2); f &= ~(hash1 ^ hash2);
364 g &= hash1; h &= ~hash1;
365 x &= hash2; y &= ~hash2;
366 if (!(e | f | g | h | x | y)) {
367 /* They're all 0. That means they've all changed at least once. */
368 break;
369 }
370 }
371 if (bit_pair > trials) {
372 trials = bit_pair;
373 }
374 if (bit_pair == MAXPAIR) {
375#if UNUSED_BLOCK
376 printf("Some bit didn't change: ");
377 printf("%.8lx %.8lx %.8lx %.8lx %.8lx %.8lx ",
378 SPIF_CAST_C(unsigned long) e,
379 SPIF_CAST_C(unsigned long) f,
380 SPIF_CAST_C(unsigned long) g,
381 SPIF_CAST_C(unsigned long) h,
382 SPIF_CAST_C(unsigned long) x,
383 SPIF_CAST_C(unsigned long) y);
384 printf("input_byte %lu input_bit %lu seed %lu key length %lu\n",
385 SPIF_CAST_C(unsigned long) input_byte,
386 SPIF_CAST_C(unsigned long) input_bit,
387 SPIF_CAST_C(unsigned long) seed,
388 SPIF_CAST_C(unsigned long) key_length);
389#endif
390 }
391 if (trials == MAXPAIR) {
392 /* Easy way to break out of a crapload of for loops. */
393 goto done;
394 }
395 }
396 }
397 }
398 done:
399 if (trials < MAXPAIR) {
400 successes++;
401#if UNUSED_BLOCK
402 printf("Mix success: %2lu-byte key required %2lu trials (%lu so far).\n",
403 SPIF_CAST_C(unsigned long) input_byte,
404 SPIF_CAST_C(unsigned long) trials / 2,
405 SPIF_CAST_C(unsigned long) successes);
406#endif
407 }
408 }
409 printf("%.2f%% mix success rate in %d key lengths...",
410 (100.0 * successes / key_length), key_length);
411 TEST_FAIL_IF(successes == 0);
412 TEST_PASS();
413
414 /* Make sure nothing but the key is hashed, regardless of alignment. */
415 TEST_BEGIN("endian cleanliness");
416 key_length = CONST_STRLEN(align1);
417 if (hash_func == spifhash_jenkins32) {
418 if (key_length % 4) {
419 TEST_FAIL_IF(key_length);
420 } else {
421 key_length /= 4;
422 }
423 }
424 ref_hash = hash_func(align1, key_length, 0);
425 hash = hash_func(align2 + 1, key_length, 0);
426 /*printf("Reference hash 0x%08x, hash 0x%08x for length %lu\n", ref_hash, hash, key_length);*/
427 TEST_FAIL_IF(hash != ref_hash);
428 hash = hash_func(align3 + 2, key_length, 0);
429 TEST_FAIL_IF(hash != ref_hash);
430 hash = hash_func(align4 + 3, key_length, 0);
431 TEST_FAIL_IF(hash != ref_hash);
432
433 for (j = 0, pbuff = buff + 1; j < 8; j++, pbuff++) {
434 for (key_length = 0; key_length < MAXLEN; key_length++) {
435 if ((hash_func == spifhash_jenkins32)
436 && (key_length % 4)) {
437 continue;
438 }
439 MEMSET(buff, 0, sizeof(buff));
440
441 if (hash_func == spifhash_jenkins32) {
442 ref_hash = hash_func(pbuff, key_length / 4, 1);
443 } else {
444 ref_hash = hash_func(pbuff, key_length, 1);
445 }
446 *(pbuff + key_length) = ~(SPIF_CAST(uint8) 0);
447 *(pbuff - 1) = ~(SPIF_CAST(uint8) 0);
448 if (hash_func == spifhash_jenkins32) {
449 hash = hash_func(pbuff, key_length / 4, 1);
450 } else {
451 hash = hash_func(pbuff, key_length, 1);
452 }
453 /*printf("Reference hash 0x%08x, hash 0x%08x for length %lu\n", ref_hash, hash, key_length);*/
454 TEST_FAIL_IF(hash != ref_hash);
455 }
456 }
457 TEST_PASS();
458
459 /* We cannot test the rotating hash or the FNV hash here. The
460 rotating hash repeats after 4 zero-length keys. The FNV
461 hash generates constant hash values for zero-length keys. */
462 if ((hash_func != spifhash_rotating)
463 && (hash_func != spifhash_fnv)) {
464 spif_uint32_t null_hashes[8];
465 spif_uint8_t one_byte;
466
467 TEST_BEGIN("hashes of empty strings");
468 one_byte = ~0;
469 for (j = 0, hash = 0; j < 8; j++) {
470 spif_uint32_t k;
471
472 hash = hash_func(&one_byte, SPIF_CAST(uint32) 0, hash);
473 null_hashes[j] = hash;
474 /*printf("Empty string hash %lu is 0x%08x\n", j, hash);*/
475 for (k = j - 1; k < 8; k--) {
476 TEST_FAIL_IF(null_hashes[j] == null_hashes[k]);
477 }
478 }
479 TEST_PASS();
480 }
481 }
482
483 TEST_PASSED("hash functions");
484 return 0;
485}
486
487int 267int
488test_snprintf(void) 268test_snprintf(void)
489{ 269{
@@ -2715,6 +2495,269 @@ test_regexp(void)
2715} 2495}
2716 2496
2717int 2497int
2498test_module(void)
2499{
2500 spif_module_t test_mod;
2501 double (*dynamic_tan)(double);
2502
2503 TEST_BEGIN("spif_module_new() function");
2504 test_mod = spif_module_new();
2505 TEST_FAIL_IF(SPIF_MODULE_ISNULL(test_mod));
2506 TEST_PASS();
2507
2508 TEST_BEGIN("spif_module_t properties");
2509 spif_module_set_name(test_mod, spif_str_new_from_ptr("math library"));
2510 spif_module_set_path(test_mod, spif_str_new_from_ptr("libm.so"));
2511 TEST_FAIL_IF(!SPIF_CMP_IS_EQUAL(spif_str_cmp_with_ptr(test_mod->name, "math library")));
2512 TEST_FAIL_IF(!SPIF_CMP_IS_EQUAL(spif_str_cmp_with_ptr(test_mod->path, "libm.so")));
2513 TEST_PASS();
2514
2515 libast_set_silent(1);
2516 TEST_BEGIN("spif_module_load() function");
2517 TEST_FAIL_IF(!spif_module_load(test_mod));
2518 TEST_PASS();
2519
2520 TEST_BEGIN("spif_module_getsym() function");
2521 TEST_FAIL_IF(SPIF_PTR_ISNULL(spif_module_getsym(test_mod, "sqrt")));
2522 TEST_FAIL_IF(!SPIF_PTR_ISNULL(spif_module_getsym(test_mod, "lkjweoiclkjsdfoihwerbglkjsdf")));
2523 dynamic_tan = spif_module_getsym(test_mod, "tan");
2524 TEST_FAIL_IF((*dynamic_tan)(2.0) - tan(2.0) > 0.00001);
2525 TEST_PASS();
2526
2527 TEST_BEGIN("spif_module_call() function");
2528 TEST_PASS();
2529
2530 TEST_BEGIN("spif_module_unload() function");
2531 TEST_FAIL_IF(!spif_module_unload(test_mod));
2532 TEST_PASS();
2533 libast_set_silent(0);
2534
2535 TEST_PASSED("spif_module_t");
2536 return 0;
2537}
2538
2539#define MAXPAIR 80
2540#define MAXLEN 80
2541int
2542test_hash_functions(void)
2543{
2544 spif_uint8_t i;
2545
2546 for (i = 0; i < 6; i++) {
2547 spifhash_func_t hash_func;
2548 spif_uint32_t key_length, input_byte, trials, successes = 0, hash, ref_hash;
2549 spif_uint8_t buff[MAXLEN + 20], *pbuff;
2550 spif_uint8_t align1[] = "This has got the amazing aroma of bovine fecal matter...";
2551 spif_uint8_t align2[] = "xThis has got the amazing aroma of bovine fecal matter...";
2552 spif_uint8_t align3[] = "xxThis has got the amazing aroma of bovine fecal matter...";
2553 spif_uint8_t align4[] = "xxxThis has got the amazing aroma of bovine fecal matter...";
2554 spif_uint32_t j;
2555
2556 if (i == 0) {
2557 TEST_NOTICE("*** Testing Jenkins hash:");
2558 hash_func = spifhash_jenkins;
2559 } else if (i == 1) {
2560 TEST_NOTICE("*** Testing Jenkins32 hash:");
2561 hash_func = spifhash_jenkins32;
2562 } else if (i == 2) {
2563#if WORDS_BIGENDIAN
2564 continue;
2565#else
2566 TEST_NOTICE("*** Testing JenkinsLE hash:");
2567 hash_func = spifhash_jenkinsLE;
2568#endif
2569 } else if (i == 3) {
2570 TEST_NOTICE("*** Testing rotating hash:");
2571 hash_func = spifhash_rotating;
2572 } else if (i == 4) {
2573 TEST_NOTICE("*** Testing one-at-a-time hash:");
2574 hash_func = spifhash_one_at_a_time;
2575 } else if (i == 5) {
2576 TEST_NOTICE("*** Testing FNV hash:");
2577 hash_func = spifhash_fnv;
2578 }
2579
2580 TEST_BEGIN("effect of every input bit on every output bit");
2581 for (key_length = 0; key_length < MAXLEN; key_length++) {
2582 /* For each key length up to 70 bytes... */
2583
2584 if ((hash_func == spifhash_jenkins32)
2585 && (key_length % 4)) {
2586 successes++;
2587 continue;
2588 }
2589 trials = 0;
2590 for (input_byte = 0; input_byte < key_length; input_byte++) {
2591 /* ...for each input byte... */
2592 spif_uint32_t input_bit;
2593
2594 for (input_bit = 0; input_bit < 8; input_bit++) {
2595 /* ...for each input bit... */
2596 spif_uint32_t seed;
2597
2598 for (seed = 1; seed < 8; seed++) {
2599 /* ...use several possible seeds... */
2600 spif_uint32_t e, f, g, h, x, y;
2601 spif_uint32_t bit_pair;
2602
2603 /* Initialize to ~0 (0xffffffff). */
2604 e = f = g = h = x = y = ~(SPIF_CAST(uint32) 0);
2605
2606 /* ...to make sure every output bit is affected by every input bit. */
2607 for (bit_pair = 0; bit_pair < MAXPAIR; bit_pair += 2) {
2608 spif_uint8_t buff1[MAXLEN + 1], buff2[MAXLEN + 2];
2609 spif_uint8_t *pbuff1 = &buff1[0], *pbuff2 = &buff2[1];
2610 spif_uint32_t hash1, hash2;
2611
2612 for (j = 0; j < key_length + 1; j++) {
2613 /* Initialize keys to all zeros. */
2614 pbuff1[j] = pbuff2[j] = (spif_uint8_t) 0;
2615 }
2616
2617 /* Then make them differ by exactly one bit, the input_bit.
2618 bit_pair will always end in 0, so bit_pair + 1 will always
2619 end in 1. It's then shifted by input_bit to test the
2620 current bit to test all 8 of the lowest bits in sequence. */
2621 pbuff1[input_byte] ^= (bit_pair << input_bit);
2622 pbuff1[input_byte] ^= (bit_pair >> (8 - input_bit));
2623 pbuff2[input_byte] ^= ((bit_pair + 1) << input_bit);
2624 pbuff2[input_byte] ^= ((bit_pair + 1) >> (8 - input_bit));
2625
2626 /* Hash them. */
2627 if (hash_func == spifhash_jenkins32) {
2628 hash1 = hash_func(pbuff1, key_length / 4, seed);
2629 hash2 = hash_func(pbuff2, key_length / 4, seed);
2630 } else {
2631 hash1 = hash_func(pbuff1, key_length, seed);
2632 hash2 = hash_func(pbuff2, key_length, seed);
2633 }
2634
2635 /* Make sure every bit is 1 or 0 at least once. */
2636 e &= (hash1 ^ hash2); f &= ~(hash1 ^ hash2);
2637 g &= hash1; h &= ~hash1;
2638 x &= hash2; y &= ~hash2;
2639 if (!(e | f | g | h | x | y)) {
2640 /* They're all 0. That means they've all changed at least once. */
2641 break;
2642 }
2643 }
2644 if (bit_pair > trials) {
2645 trials = bit_pair;
2646 }
2647 if (bit_pair == MAXPAIR) {
2648#if UNUSED_BLOCK
2649 printf("Some bit didn't change: ");
2650 printf("%.8lx %.8lx %.8lx %.8lx %.8lx %.8lx ",
2651 SPIF_CAST_C(unsigned long) e,
2652 SPIF_CAST_C(unsigned long) f,
2653 SPIF_CAST_C(unsigned long) g,
2654 SPIF_CAST_C(unsigned long) h,
2655 SPIF_CAST_C(unsigned long) x,
2656 SPIF_CAST_C(unsigned long) y);
2657 printf("input_byte %lu input_bit %lu seed %lu key length %lu\n",
2658 SPIF_CAST_C(unsigned long) input_byte,
2659 SPIF_CAST_C(unsigned long) input_bit,
2660 SPIF_CAST_C(unsigned long) seed,
2661 SPIF_CAST_C(unsigned long) key_length);
2662#endif
2663 }
2664 if (trials == MAXPAIR) {
2665 /* Easy way to break out of a crapload of for loops. */
2666 goto done;
2667 }
2668 }
2669 }
2670 }
2671 done:
2672 if (trials < MAXPAIR) {
2673 successes++;
2674#if UNUSED_BLOCK
2675 printf("Mix success: %2lu-byte key required %2lu trials (%lu so far).\n",
2676 SPIF_CAST_C(unsigned long) input_byte,
2677 SPIF_CAST_C(unsigned long) trials / 2,
2678 SPIF_CAST_C(unsigned long) successes);
2679#endif
2680 }
2681 }
2682 printf("%.2f%% mix success rate in %d key lengths...",
2683 (100.0 * successes / key_length), key_length);
2684 TEST_FAIL_IF(successes == 0);
2685 TEST_PASS();
2686
2687 /* Make sure nothing but the key is hashed, regardless of alignment. */
2688 TEST_BEGIN("endian cleanliness");
2689 key_length = CONST_STRLEN(align1);
2690 if (hash_func == spifhash_jenkins32) {
2691 if (key_length % 4) {
2692 TEST_FAIL_IF(key_length);
2693 } else {
2694 key_length /= 4;
2695 }
2696 }
2697 ref_hash = hash_func(align1, key_length, 0);
2698 hash = hash_func(align2 + 1, key_length, 0);
2699 /*printf("Reference hash 0x%08x, hash 0x%08x for length %lu\n", ref_hash, hash, key_length);*/
2700 TEST_FAIL_IF(hash != ref_hash);
2701 hash = hash_func(align3 + 2, key_length, 0);
2702 TEST_FAIL_IF(hash != ref_hash);
2703 hash = hash_func(align4 + 3, key_length, 0);
2704 TEST_FAIL_IF(hash != ref_hash);
2705
2706 for (j = 0, pbuff = buff + 1; j < 8; j++, pbuff++) {
2707 for (key_length = 0; key_length < MAXLEN; key_length++) {
2708 if ((hash_func == spifhash_jenkins32)
2709 && (key_length % 4)) {
2710 continue;
2711 }
2712 MEMSET(buff, 0, sizeof(buff));
2713
2714 if (hash_func == spifhash_jenkins32) {
2715 ref_hash = hash_func(pbuff, key_length / 4, 1);
2716 } else {
2717 ref_hash = hash_func(pbuff, key_length, 1);
2718 }
2719 *(pbuff + key_length) = ~(SPIF_CAST(uint8) 0);
2720 *(pbuff - 1) = ~(SPIF_CAST(uint8) 0);
2721 if (hash_func == spifhash_jenkins32) {
2722 hash = hash_func(pbuff, key_length / 4, 1);
2723 } else {
2724 hash = hash_func(pbuff, key_length, 1);
2725 }
2726 /*printf("Reference hash 0x%08x, hash 0x%08x for length %lu\n", ref_hash, hash, key_length);*/
2727 TEST_FAIL_IF(hash != ref_hash);
2728 }
2729 }
2730 TEST_PASS();
2731
2732 /* We cannot test the rotating hash or the FNV hash here. The
2733 rotating hash repeats after 4 zero-length keys. The FNV
2734 hash generates constant hash values for zero-length keys. */
2735 if ((hash_func != spifhash_rotating)
2736 && (hash_func != spifhash_fnv)) {
2737 spif_uint32_t null_hashes[8];
2738 spif_uint8_t one_byte;
2739
2740 TEST_BEGIN("hashes of empty strings");
2741 one_byte = ~0;
2742 for (j = 0, hash = 0; j < 8; j++) {
2743 spif_uint32_t k;
2744
2745 hash = hash_func(&one_byte, SPIF_CAST(uint32) 0, hash);
2746 null_hashes[j] = hash;
2747 /*printf("Empty string hash %lu is 0x%08x\n", j, hash);*/
2748 for (k = j - 1; k < 8; k--) {
2749 TEST_FAIL_IF(null_hashes[j] == null_hashes[k]);
2750 }
2751 }
2752 TEST_PASS();
2753 }
2754 }
2755
2756 TEST_PASSED("hash functions");
2757 return 0;
2758}
2759
2760int
2718main(int argc, char *argv[]) 2761main(int argc, char *argv[])
2719{ 2762{
2720 int ret = 0; 2763 int ret = 0;
@@ -2772,6 +2815,9 @@ main(int argc, char *argv[])
2772 if ((ret = test_regexp()) != 0) { 2815 if ((ret = test_regexp()) != 0) {
2773 return ret; 2816 return ret;
2774 } 2817 }
2818 if ((ret = test_module()) != 0) {
2819 return ret;
2820 }
2775 if ((ret = test_hash_functions()) != 0) { 2821 if ((ret = test_hash_functions()) != 0) {
2776 return ret; 2822 return ret;
2777 } 2823 }