summaryrefslogtreecommitdiff
path: root/pjlib/src
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2005-11-13 19:40:44 +0000
committerBenny Prijono <bennylp@teluu.com>2005-11-13 19:40:44 +0000
commita08b589d09d5197f9a76d549a189e4686bd2ca8c (patch)
tree549904e7680dfab96b3ce579b1843c5d58107100 /pjlib/src
parent8df70c6d5fef443506618bf31b686d53fef3f259 (diff)
Applying license to pjproject
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@49 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjlib/src')
-rw-r--r--pjlib/src/pj/addr_resolv_linux_kernel.c41
-rw-r--r--pjlib/src/pj/addr_resolv_sock.c91
-rw-r--r--pjlib/src/pj/array.c128
-rw-r--r--pjlib/src/pj/compat/sigjmp.c67
-rw-r--r--pjlib/src/pj/compat/string.c77
-rw-r--r--pjlib/src/pj/config.c85
-rw-r--r--pjlib/src/pj/equeue_winnt.c27
-rw-r--r--pjlib/src/pj/errno.c215
-rw-r--r--pjlib/src/pj/except.c291
-rw-r--r--pjlib/src/pj/extra-exports.c85
-rw-r--r--pjlib/src/pj/fifobuf.c375
-rw-r--r--pjlib/src/pj/file_access_unistd.c213
-rw-r--r--pjlib/src/pj/file_access_win32.c21
-rw-r--r--pjlib/src/pj/file_io_ansi.c285
-rw-r--r--pjlib/src/pj/file_io_win32.c309
-rw-r--r--pjlib/src/pj/guid.c41
-rw-r--r--pjlib/src/pj/guid_simple.c125
-rw-r--r--pjlib/src/pj/guid_win32.c125
-rw-r--r--pjlib/src/pj/hash.c508
-rw-r--r--pjlib/src/pj/ioqueue_common_abs.c1635
-rw-r--r--pjlib/src/pj/ioqueue_common_abs.h237
-rw-r--r--pjlib/src/pj/ioqueue_dummy.c377
-rw-r--r--pjlib/src/pj/ioqueue_epoll.c937
-rw-r--r--pjlib/src/pj/ioqueue_linux_kernel.c313
-rw-r--r--pjlib/src/pj/ioqueue_select.c1049
-rw-r--r--pjlib/src/pj/ioqueue_winnt.c1807
-rw-r--r--pjlib/src/pj/list.c39
-rw-r--r--pjlib/src/pj/lock.c377
-rw-r--r--pjlib/src/pj/log.c437
-rw-r--r--pjlib/src/pj/log_writer_printk.c45
-rw-r--r--pjlib/src/pj/log_writer_stdout.c129
-rw-r--r--pjlib/src/pj/os_core_linux_kernel.c1369
-rw-r--r--pjlib/src/pj/os_core_unix.c2411
-rw-r--r--pjlib/src/pj/os_core_win32.c2357
-rw-r--r--pjlib/src/pj/os_error_linux_kernel.c151
-rw-r--r--pjlib/src/pj/os_error_unix.c129
-rw-r--r--pjlib/src/pj/os_error_win32.c319
-rw-r--r--pjlib/src/pj/os_time_ansi.c133
-rw-r--r--pjlib/src/pj/os_time_linux_kernel.c141
-rw-r--r--pjlib/src/pj/os_timestamp_common.c259
-rw-r--r--pjlib/src/pj/os_timestamp_linux.c269
-rw-r--r--pjlib/src/pj/os_timestamp_linux_kernel.c147
-rw-r--r--pjlib/src/pj/os_timestamp_win32.c77
-rw-r--r--pjlib/src/pj/pool.c533
-rw-r--r--pjlib/src/pj/pool_caching.c431
-rw-r--r--pjlib/src/pj/pool_dbg_win32.c463
-rw-r--r--pjlib/src/pj/pool_policy_kmalloc.c107
-rw-r--r--pjlib/src/pj/pool_policy_malloc.c113
-rw-r--r--pjlib/src/pj/rand.c57
-rw-r--r--pjlib/src/pj/rbtree.c843
-rw-r--r--pjlib/src/pj/sock_bsd.c1141
-rw-r--r--pjlib/src/pj/sock_linux_kernel.c1489
-rw-r--r--pjlib/src/pj/sock_select.c205
-rw-r--r--pjlib/src/pj/string.c251
-rw-r--r--pjlib/src/pj/symbols.c681
-rw-r--r--pjlib/src/pj/timer.c975
-rw-r--r--pjlib/src/pj/types.c83
-rw-r--r--pjlib/src/pjlib++-test/main.cpp21
-rw-r--r--pjlib/src/pjlib-samples/except.c158
-rw-r--r--pjlib/src/pjlib-samples/list.c130
-rw-r--r--pjlib/src/pjlib-samples/log.c72
-rw-r--r--pjlib/src/pjlib-test/atomic.c187
-rw-r--r--pjlib/src/pjlib-test/echo_clt.c525
-rw-r--r--pjlib/src/pjlib-test/errno.c312
-rw-r--r--pjlib/src/pjlib-test/exception.c343
-rw-r--r--pjlib/src/pjlib-test/fifobuf.c221
-rw-r--r--pjlib/src/pjlib-test/file.c21
-rw-r--r--pjlib/src/pjlib-test/ioq_perf.c993
-rw-r--r--pjlib/src/pjlib-test/ioq_tcp.c1069
-rw-r--r--pjlib/src/pjlib-test/ioq_udp.c1315
-rw-r--r--pjlib/src/pjlib-test/list.c439
-rw-r--r--pjlib/src/pjlib-test/main.c173
-rw-r--r--pjlib/src/pjlib-test/main_mod.c67
-rw-r--r--pjlib/src/pjlib-test/mutex.c337
-rw-r--r--pjlib/src/pjlib-test/os.c27
-rw-r--r--pjlib/src/pjlib-test/pool.c333
-rw-r--r--pjlib/src/pjlib-test/pool_perf.c269
-rw-r--r--pjlib/src/pjlib-test/rand.c95
-rw-r--r--pjlib/src/pjlib-test/rbtree.c323
-rw-r--r--pjlib/src/pjlib-test/select.c423
-rw-r--r--pjlib/src/pjlib-test/sleep.c389
-rw-r--r--pjlib/src/pjlib-test/sock.c901
-rw-r--r--pjlib/src/pjlib-test/sock_perf.c355
-rw-r--r--pjlib/src/pjlib-test/string.c337
-rw-r--r--pjlib/src/pjlib-test/test.c387
-rw-r--r--pjlib/src/pjlib-test/test.h211
-rw-r--r--pjlib/src/pjlib-test/thread.c567
-rw-r--r--pjlib/src/pjlib-test/timer.c361
-rw-r--r--pjlib/src/pjlib-test/timestamp.c275
-rw-r--r--pjlib/src/pjlib-test/udp_echo_srv_ioqueue.c21
-rw-r--r--pjlib/src/pjlib-test/udp_echo_srv_sync.c315
-rw-r--r--pjlib/src/pjlib-test/util.c251
92 files changed, 19886 insertions, 17962 deletions
diff --git a/pjlib/src/pj/addr_resolv_linux_kernel.c b/pjlib/src/pj/addr_resolv_linux_kernel.c
index 996c6316..4d587acb 100644
--- a/pjlib/src/pj/addr_resolv_linux_kernel.c
+++ b/pjlib/src/pj/addr_resolv_linux_kernel.c
@@ -1,10 +1,31 @@
-/* $Id$
- *
- */
-#include <pj/addr_resolv.h>
-
-PJ_DEF(pj_status_t) pj_gethostbyname(const pj_str_t *hostname, pj_hostent *phe)
-{
- return -1;
-}
-
+/* $Id$
+ *
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/addr_resolv.h>
+
+PJ_DEF(pj_status_t) pj_gethostbyname(const pj_str_t *hostname, pj_hostent *phe)
+{
+ return -1;
+}
+
diff --git a/pjlib/src/pj/addr_resolv_sock.c b/pjlib/src/pj/addr_resolv_sock.c
index ee49db2d..5e2676da 100644
--- a/pjlib/src/pj/addr_resolv_sock.c
+++ b/pjlib/src/pj/addr_resolv_sock.c
@@ -1,35 +1,56 @@
-/* $Id$
- */
-#include <pj/addr_resolv.h>
-#include <pj/assert.h>
-#include <pj/string.h>
-#include <pj/compat/socket.h>
-#include <pj/errno.h>
-
-
-PJ_DEF(pj_status_t) pj_gethostbyname(const pj_str_t *hostname, pj_hostent *phe)
-{
- struct hostent *he;
- char copy[PJ_MAX_HOSTNAME];
-
- pj_assert(hostname && hostname ->slen < PJ_MAX_HOSTNAME);
-
- if (hostname->slen >= PJ_MAX_HOSTNAME)
- return PJ_ENAMETOOLONG;
-
- pj_memcpy(copy, hostname->ptr, hostname->slen);
- copy[ hostname->slen ] = '\0';
-
- he = gethostbyname(copy);
- if (!he)
- return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
-
- phe->h_name = he->h_name;
- phe->h_aliases = he->h_aliases;
- phe->h_addrtype = he->h_addrtype;
- phe->h_length = he->h_length;
- phe->h_addr_list = he->h_addr_list;
-
- return PJ_SUCCESS;
-}
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/addr_resolv.h>
+#include <pj/assert.h>
+#include <pj/string.h>
+#include <pj/compat/socket.h>
+#include <pj/errno.h>
+
+
+PJ_DEF(pj_status_t) pj_gethostbyname(const pj_str_t *hostname, pj_hostent *phe)
+{
+ struct hostent *he;
+ char copy[PJ_MAX_HOSTNAME];
+
+ pj_assert(hostname && hostname ->slen < PJ_MAX_HOSTNAME);
+
+ if (hostname->slen >= PJ_MAX_HOSTNAME)
+ return PJ_ENAMETOOLONG;
+
+ pj_memcpy(copy, hostname->ptr, hostname->slen);
+ copy[ hostname->slen ] = '\0';
+
+ he = gethostbyname(copy);
+ if (!he)
+ return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
+
+ phe->h_name = he->h_name;
+ phe->h_aliases = he->h_aliases;
+ phe->h_addrtype = he->h_addrtype;
+ phe->h_length = he->h_length;
+ phe->h_addr_list = he->h_addr_list;
+
+ return PJ_SUCCESS;
+}
+
diff --git a/pjlib/src/pj/array.c b/pjlib/src/pj/array.c
index 563b7bf9..76fea95b 100644
--- a/pjlib/src/pj/array.c
+++ b/pjlib/src/pj/array.c
@@ -1,54 +1,74 @@
-/* $Id$
- */
-#include <pj/array.h>
-#include <pj/string.h>
-#include <pj/assert.h>
-#include <pj/errno.h>
-
-PJ_DEF(void) pj_array_insert( void *array,
- unsigned elem_size,
- unsigned count,
- unsigned pos,
- const void *value)
-{
- if (count && pos < count-1) {
- pj_memmove( (char*)array + (pos+1)*elem_size,
- (char*)array + pos*elem_size,
- (count-pos)*elem_size);
- }
- pj_memmove((char*)array + pos*elem_size, value, elem_size);
-}
-
-PJ_DEF(void) pj_array_erase( void *array,
- unsigned elem_size,
- unsigned count,
- unsigned pos)
-{
- pj_assert(count != 0);
- if (pos < count-1) {
- pj_memmove( (char*)array + pos*elem_size,
- (char*)array + (pos+1)*elem_size,
- (count-pos-1)*elem_size);
- }
-}
-
-PJ_DEF(pj_status_t) pj_array_find( const void *array,
- unsigned elem_size,
- unsigned count,
- pj_status_t (*matching)(const void *value),
- void **result)
-{
- unsigned i;
- const char *char_array = array;
- for (i=0; i<count; ++i) {
- if ( (*matching)(char_array) == PJ_SUCCESS) {
- if (result) {
- *result = (void*)char_array;
- }
- return PJ_SUCCESS;
- }
- char_array += elem_size;
- }
- return PJ_ENOTFOUND;
-}
-
+/* $Id$ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/array.h>
+#include <pj/string.h>
+#include <pj/assert.h>
+#include <pj/errno.h>
+
+PJ_DEF(void) pj_array_insert( void *array,
+ unsigned elem_size,
+ unsigned count,
+ unsigned pos,
+ const void *value)
+{
+ if (count && pos < count-1) {
+ pj_memmove( (char*)array + (pos+1)*elem_size,
+ (char*)array + pos*elem_size,
+ (count-pos)*elem_size);
+ }
+ pj_memmove((char*)array + pos*elem_size, value, elem_size);
+}
+
+PJ_DEF(void) pj_array_erase( void *array,
+ unsigned elem_size,
+ unsigned count,
+ unsigned pos)
+{
+ pj_assert(count != 0);
+ if (pos < count-1) {
+ pj_memmove( (char*)array + pos*elem_size,
+ (char*)array + (pos+1)*elem_size,
+ (count-pos-1)*elem_size);
+ }
+}
+
+PJ_DEF(pj_status_t) pj_array_find( const void *array,
+ unsigned elem_size,
+ unsigned count,
+ pj_status_t (*matching)(const void *value),
+ void **result)
+{
+ unsigned i;
+ const char *char_array = array;
+ for (i=0; i<count; ++i) {
+ if ( (*matching)(char_array) == PJ_SUCCESS) {
+ if (result) {
+ *result = (void*)char_array;
+ }
+ return PJ_SUCCESS;
+ }
+ char_array += elem_size;
+ }
+ return PJ_ENOTFOUND;
+}
+
diff --git a/pjlib/src/pj/compat/sigjmp.c b/pjlib/src/pj/compat/sigjmp.c
index d3fb0d70..ccdec59d 100644
--- a/pjlib/src/pj/compat/sigjmp.c
+++ b/pjlib/src/pj/compat/sigjmp.c
@@ -1,24 +1,43 @@
-/* $Id$
- *
- */
-#include <pj/config.h>
-#include <pj/compat/setjmp.h>
-
-int __sigjmp_save(sigjmp_buf env, int savemask)
-{
- return 0;
-}
-
-extern int __sigsetjmp(pj_jmp_buf env, int savemask);
-extern void __longjmp(pj_jmp_buf env, int val) __attribute__((noreturn));
-
-PJ_DEF(int) pj_setjmp(pj_jmp_buf env)
-{
- return __sigsetjmp(env, 0);
-}
-
-PJ_DEF(void) pj_longjmp(pj_jmp_buf env, int val)
-{
- __longjmp(env, val);
-}
-
+/* $Id$ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/config.h>
+#include <pj/compat/setjmp.h>
+
+int __sigjmp_save(sigjmp_buf env, int savemask)
+{
+ return 0;
+}
+
+extern int __sigsetjmp(pj_jmp_buf env, int savemask);
+extern void __longjmp(pj_jmp_buf env, int val) __attribute__((noreturn));
+
+PJ_DEF(int) pj_setjmp(pj_jmp_buf env)
+{
+ return __sigsetjmp(env, 0);
+}
+
+PJ_DEF(void) pj_longjmp(pj_jmp_buf env, int val)
+{
+ __longjmp(env, val);
+}
+
diff --git a/pjlib/src/pj/compat/string.c b/pjlib/src/pj/compat/string.c
index 766857e1..a1cab0b8 100644
--- a/pjlib/src/pj/compat/string.c
+++ b/pjlib/src/pj/compat/string.c
@@ -1,29 +1,48 @@
-/* $Id$
- *
- */
-#include <pj/types.h>
-#include <pj/compat/string.h>
-#include <pj/ctype.h>
-
-PJ_DEF(int) strcasecmp(const char *s1, const char *s2)
-{
- while ((*s1==*s2) || (pj_tolower(*s1)==pj_tolower(*s2))) {
- if (!*s1++)
- return 0;
- ++s2;
- }
- return (pj_tolower(*s1) < pj_tolower(*s2)) ? -1 : 1;
-}
-
-PJ_DEF(int) strncasecmp(const char *s1, const char *s2, int len)
-{
- if (!len) return 0;
-
- while ((*s1==*s2) || (pj_tolower(*s1)==pj_tolower(*s2))) {
- if (!*s1++ || --len <= 0)
- return 0;
- ++s2;
- }
- return (pj_tolower(*s1) < pj_tolower(*s2)) ? -1 : 1;
-}
-
+/* $Id$ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/types.h>
+#include <pj/compat/string.h>
+#include <pj/ctype.h>
+
+PJ_DEF(int) strcasecmp(const char *s1, const char *s2)
+{
+ while ((*s1==*s2) || (pj_tolower(*s1)==pj_tolower(*s2))) {
+ if (!*s1++)
+ return 0;
+ ++s2;
+ }
+ return (pj_tolower(*s1) < pj_tolower(*s2)) ? -1 : 1;
+}
+
+PJ_DEF(int) strncasecmp(const char *s1, const char *s2, int len)
+{
+ if (!len) return 0;
+
+ while ((*s1==*s2) || (pj_tolower(*s1)==pj_tolower(*s2))) {
+ if (!*s1++ || --len <= 0)
+ return 0;
+ ++s2;
+ }
+ return (pj_tolower(*s1) < pj_tolower(*s2)) ? -1 : 1;
+}
+
diff --git a/pjlib/src/pj/config.c b/pjlib/src/pj/config.c
index 7923088d..329fd984 100644
--- a/pjlib/src/pj/config.c
+++ b/pjlib/src/pj/config.c
@@ -1,32 +1,53 @@
-/* $Id$
- */
-#include <pj/config.h>
-#include <pj/log.h>
-#include <pj/ioqueue.h>
-
-static const char *id = "config.c";
-const char *PJ_VERSION = "0.3.0-pre4";
-
-PJ_DEF(void) pj_dump_config(void)
-{
- PJ_LOG(3, (id, "PJLIB (c)2005 Benny Prijono"));
- PJ_LOG(3, (id, "Dumping configurations:"));
- PJ_LOG(3, (id, " PJ_VERSION : %s", PJ_VERSION));
- PJ_LOG(3, (id, " PJ_DEBUG : %d", PJ_DEBUG));
- PJ_LOG(3, (id, " PJ_FUNCTIONS_ARE_INLINED : %d", PJ_FUNCTIONS_ARE_INLINED));
- PJ_LOG(3, (id, " PJ_POOL_DEBUG : %d", PJ_POOL_DEBUG));
- PJ_LOG(3, (id, " PJ_HAS_THREADS : %d", PJ_HAS_THREADS));
- PJ_LOG(3, (id, " PJ_LOG_MAX_LEVEL : %d", PJ_LOG_MAX_LEVEL));
- PJ_LOG(3, (id, " PJ_LOG_MAX_SIZE : %d", PJ_LOG_MAX_SIZE));
- PJ_LOG(3, (id, " PJ_LOG_USE_STACK_BUFFER : %d", PJ_LOG_USE_STACK_BUFFER));
- PJ_LOG(3, (id, " PJ_HAS_TCP : %d", PJ_HAS_TCP));
- PJ_LOG(3, (id, " PJ_MAX_HOSTNAME : %d", PJ_MAX_HOSTNAME));
- PJ_LOG(3, (id, " PJ_HAS_SEMAPHORE : %d", PJ_HAS_SEMAPHORE));
- PJ_LOG(3, (id, " PJ_HAS_EVENT_OBJ : %d", PJ_HAS_EVENT_OBJ));
- PJ_LOG(3, (id, " PJ_HAS_HIGH_RES_TIMER : %d", PJ_HAS_HIGH_RES_TIMER));
- PJ_LOG(3, (id, " PJ_(endianness) : %s",
- (PJ_IS_BIG_ENDIAN?"big-endian":"little-endian")));
- PJ_LOG(3, (id, " ioqueue type : %s", pj_ioqueue_name()));
- PJ_LOG(3, (id, " PJ_IOQUEUE_MAX_HANDLES : %d", PJ_IOQUEUE_MAX_HANDLES));
-}
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/config.h>
+#include <pj/log.h>
+#include <pj/ioqueue.h>
+
+static const char *id = "config.c";
+const char *PJ_VERSION = "0.3.0-pre4";
+
+PJ_DEF(void) pj_dump_config(void)
+{
+ PJ_LOG(3, (id, "PJLIB (c)2005 Benny Prijono"));
+ PJ_LOG(3, (id, "Dumping configurations:"));
+ PJ_LOG(3, (id, " PJ_VERSION : %s", PJ_VERSION));
+ PJ_LOG(3, (id, " PJ_DEBUG : %d", PJ_DEBUG));
+ PJ_LOG(3, (id, " PJ_FUNCTIONS_ARE_INLINED : %d", PJ_FUNCTIONS_ARE_INLINED));
+ PJ_LOG(3, (id, " PJ_POOL_DEBUG : %d", PJ_POOL_DEBUG));
+ PJ_LOG(3, (id, " PJ_HAS_THREADS : %d", PJ_HAS_THREADS));
+ PJ_LOG(3, (id, " PJ_LOG_MAX_LEVEL : %d", PJ_LOG_MAX_LEVEL));
+ PJ_LOG(3, (id, " PJ_LOG_MAX_SIZE : %d", PJ_LOG_MAX_SIZE));
+ PJ_LOG(3, (id, " PJ_LOG_USE_STACK_BUFFER : %d", PJ_LOG_USE_STACK_BUFFER));
+ PJ_LOG(3, (id, " PJ_HAS_TCP : %d", PJ_HAS_TCP));
+ PJ_LOG(3, (id, " PJ_MAX_HOSTNAME : %d", PJ_MAX_HOSTNAME));
+ PJ_LOG(3, (id, " PJ_HAS_SEMAPHORE : %d", PJ_HAS_SEMAPHORE));
+ PJ_LOG(3, (id, " PJ_HAS_EVENT_OBJ : %d", PJ_HAS_EVENT_OBJ));
+ PJ_LOG(3, (id, " PJ_HAS_HIGH_RES_TIMER : %d", PJ_HAS_HIGH_RES_TIMER));
+ PJ_LOG(3, (id, " PJ_(endianness) : %s",
+ (PJ_IS_BIG_ENDIAN?"big-endian":"little-endian")));
+ PJ_LOG(3, (id, " ioqueue type : %s", pj_ioqueue_name()));
+ PJ_LOG(3, (id, " PJ_IOQUEUE_MAX_HANDLES : %d", PJ_IOQUEUE_MAX_HANDLES));
+}
+
diff --git a/pjlib/src/pj/equeue_winnt.c b/pjlib/src/pj/equeue_winnt.c
index 8357dce9..1565b9a7 100644
--- a/pjlib/src/pj/equeue_winnt.c
+++ b/pjlib/src/pj/equeue_winnt.c
@@ -1,3 +1,24 @@
-/* $Id$
- */
-#include <pj/equeue.h>
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/equeue.h>
diff --git a/pjlib/src/pj/errno.c b/pjlib/src/pj/errno.c
index 5a986514..6d05576a 100644
--- a/pjlib/src/pj/errno.c
+++ b/pjlib/src/pj/errno.c
@@ -1,99 +1,120 @@
-/* $Id$
- */
-#include <pj/errno.h>
-#include <pj/string.h>
-#include <pj/compat/sprintf.h>
-
-/* Prototype for platform specific error message, which will be defined
- * in separate file.
- */
-extern int platform_strerror( pj_os_err_type code,
- char *buf, pj_size_t bufsize );
-
-/* PJLIB's own error codes/messages */
-static const struct
-{
- int code;
- const char *msg;
-} err_str[] =
-{
- { PJ_EUNKNOWN, "Unknown Error" },
- { PJ_EPENDING, "Pending operation" },
- { PJ_ETOOMANYCONN, "Too many connecting sockets" },
- { PJ_EINVAL, "Invalid value or argument" },
- { PJ_ENAMETOOLONG, "Name too long" },
- { PJ_ENOTFOUND, "Not found" },
- { PJ_ENOMEM, "Not enough memory" },
- { PJ_EBUG, "BUG DETECTED!" },
- { PJ_ETIMEDOUT, "Operation timed out" },
- { PJ_ETOOMANY, "Too many objects of the specified type"},
- { PJ_EBUSY, "Object is busy"},
- { PJ_ENOTSUP, "Option/operation is not supported"},
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/errno.h>
+#include <pj/string.h>
+#include <pj/compat/sprintf.h>
+
+/* Prototype for platform specific error message, which will be defined
+ * in separate file.
+ */
+extern int platform_strerror( pj_os_err_type code,
+ char *buf, pj_size_t bufsize );
+
+/* PJLIB's own error codes/messages */
+static const struct
+{
+ int code;
+ const char *msg;
+} err_str[] =
+{
+ { PJ_EUNKNOWN, "Unknown Error" },
+ { PJ_EPENDING, "Pending operation" },
+ { PJ_ETOOMANYCONN, "Too many connecting sockets" },
+ { PJ_EINVAL, "Invalid value or argument" },
+ { PJ_ENAMETOOLONG, "Name too long" },
+ { PJ_ENOTFOUND, "Not found" },
+ { PJ_ENOMEM, "Not enough memory" },
+ { PJ_EBUG, "BUG DETECTED!" },
+ { PJ_ETIMEDOUT, "Operation timed out" },
+ { PJ_ETOOMANY, "Too many objects of the specified type"},
+ { PJ_EBUSY, "Object is busy"},
+ { PJ_ENOTSUP, "Option/operation is not supported"},
{ PJ_EINVALIDOP, "Invalid operation"},
{ PJ_ECANCELLED, "Operation cancelled"},
- { PJ_EEXISTS, "Object already exists" }
-};
-
-/*
- * pjlib_error()
- *
- * Retrieve message string for PJLIB's own error code.
- */
-static int pjlib_error(pj_status_t code, char *buf, pj_size_t size)
-{
- unsigned i;
-
- for (i=0; i<sizeof(err_str)/sizeof(err_str[0]); ++i) {
- if (err_str[i].code == code) {
- pj_size_t len = strlen(err_str[i].msg);
- if (len >= size) len = size-1;
- pj_memcpy(buf, err_str[i].msg, len);
- buf[len] = '\0';
- return len;
- }
- }
-
- *buf++ = '?';
- *buf++ = '?';
- *buf++ = '?';
- *buf++ = '\0';
- return 3;
-}
-
-/*
- * pj_strerror()
- */
-PJ_DEF(pj_str_t) pj_strerror( pj_status_t statcode,
- char *buf, pj_size_t bufsize )
-{
- int len = -1;
- pj_str_t errstr;
-
- if (statcode < PJ_ERRNO_START + PJ_ERRNO_SPACE_SIZE) {
- len = pj_snprintf( buf, bufsize, "Unknown error %d", statcode);
-
- } else if (statcode < PJ_ERRNO_START_STATUS + PJ_ERRNO_SPACE_SIZE) {
- len = pjlib_error(statcode, buf, bufsize);
-
- } else if (statcode < PJ_ERRNO_START_SYS + PJ_ERRNO_SPACE_SIZE) {
- len = platform_strerror(PJ_STATUS_TO_OS(statcode), buf, bufsize);
-
- } else if (statcode < PJ_ERRNO_START_USER + PJ_ERRNO_SPACE_SIZE) {
- len = pj_snprintf( buf, bufsize, "User error %d", statcode);
-
- } else {
- len = pj_snprintf( buf, bufsize, "Invalid error %d", statcode);
-
- }
-
- if (len < 1) {
- *buf = '\0';
- len = 0;
- }
-
- errstr.ptr = buf;
- errstr.slen = len;
-
- return errstr;
-}
-
+ { PJ_EEXISTS, "Object already exists" }
+};
+
+/*
+ * pjlib_error()
+ *
+ * Retrieve message string for PJLIB's own error code.
+ */
+static int pjlib_error(pj_status_t code, char *buf, pj_size_t size)
+{
+ unsigned i;
+
+ for (i=0; i<sizeof(err_str)/sizeof(err_str[0]); ++i) {
+ if (err_str[i].code == code) {
+ pj_size_t len = strlen(err_str[i].msg);
+ if (len >= size) len = size-1;
+ pj_memcpy(buf, err_str[i].msg, len);
+ buf[len] = '\0';
+ return len;
+ }
+ }
+
+ *buf++ = '?';
+ *buf++ = '?';
+ *buf++ = '?';
+ *buf++ = '\0';
+ return 3;
+}
+
+/*
+ * pj_strerror()
+ */
+PJ_DEF(pj_str_t) pj_strerror( pj_status_t statcode,
+ char *buf, pj_size_t bufsize )
+{
+ int len = -1;
+ pj_str_t errstr;
+
+ if (statcode < PJ_ERRNO_START + PJ_ERRNO_SPACE_SIZE) {
+ len = pj_snprintf( buf, bufsize, "Unknown error %d", statcode);
+
+ } else if (statcode < PJ_ERRNO_START_STATUS + PJ_ERRNO_SPACE_SIZE) {
+ len = pjlib_error(statcode, buf, bufsize);
+
+ } else if (statcode < PJ_ERRNO_START_SYS + PJ_ERRNO_SPACE_SIZE) {
+ len = platform_strerror(PJ_STATUS_TO_OS(statcode), buf, bufsize);
+
+ } else if (statcode < PJ_ERRNO_START_USER + PJ_ERRNO_SPACE_SIZE) {
+ len = pj_snprintf( buf, bufsize, "User error %d", statcode);
+
+ } else {
+ len = pj_snprintf( buf, bufsize, "Invalid error %d", statcode);
+
+ }
+
+ if (len < 1) {
+ *buf = '\0';
+ len = 0;
+ }
+
+ errstr.ptr = buf;
+ errstr.slen = len;
+
+ return errstr;
+}
+
diff --git a/pjlib/src/pj/except.c b/pjlib/src/pj/except.c
index 84fb93c2..024a4177 100644
--- a/pjlib/src/pj/except.c
+++ b/pjlib/src/pj/except.c
@@ -1,135 +1,156 @@
-/* $Id$
- */
-#include <pj/except.h>
-#include <pj/os.h>
-#include <pj/assert.h>
-#include <pj/log.h>
-#include <pj/errno.h>
-
-static long thread_local_id = -1;
-
-#if defined(PJ_HAS_EXCEPTION_NAMES) && PJ_HAS_EXCEPTION_NAMES != 0
- static const char *exception_id_names[PJ_MAX_EXCEPTION_ID];
-#else
- /*
- * Start from 1 (not 0)!!!
- * Exception 0 is reserved for normal path of setjmp()!!!
- */
- static int last_exception_id = 1;
-#endif /* PJ_HAS_EXCEPTION_NAMES */
-
-
-PJ_DEF(void) pj_throw_exception_(int exception_id)
-{
- struct pj_exception_state_t *handler;
-
- handler = pj_thread_local_get(thread_local_id);
- if (handler == NULL) {
- PJ_LOG(1,("except.c", "!!!FATAL: unhandled exception %d!\n", exception_id));
- pj_assert(handler != NULL);
- /* This will crash the system! */
- }
- pj_longjmp(handler->state, exception_id);
-}
-
-PJ_DEF(void) pj_push_exception_handler_(struct pj_exception_state_t *rec)
-{
- struct pj_exception_state_t *parent_handler = NULL;
-
- if (thread_local_id == -1) {
- pj_thread_local_alloc(&thread_local_id);
- pj_assert(thread_local_id != -1);
- }
- parent_handler = pj_thread_local_get(thread_local_id);
- rec->prev = parent_handler;
- pj_thread_local_set(thread_local_id, rec);
-}
-
-PJ_DEF(void) pj_pop_exception_handler_(void)
-{
- struct pj_exception_state_t *handler;
-
- handler = pj_thread_local_get(thread_local_id);
- pj_assert(handler != NULL);
- pj_thread_local_set(thread_local_id, handler->prev);
-}
-
-#if defined(PJ_HAS_EXCEPTION_NAMES) && PJ_HAS_EXCEPTION_NAMES != 0
-PJ_DEF(pj_status_t) pj_exception_id_alloc( const char *name,
- pj_exception_id_t *id)
-{
- unsigned i;
-
- pj_enter_critical_section();
-
- /*
- * Start from 1 (not 0)!!!
- * Exception 0 is reserved for normal path of setjmp()!!!
- */
- for (i=1; i<PJ_MAX_EXCEPTION_ID; ++i) {
- if (exception_id_names[i] == NULL) {
- exception_id_names[i] = name;
- *id = i;
- pj_leave_critical_section();
- return PJ_SUCCESS;
- }
- }
-
- pj_leave_critical_section();
- return PJ_ETOOMANY;
-}
-
-PJ_DEF(pj_status_t) pj_exception_id_free( pj_exception_id_t id )
-{
- /*
- * Start from 1 (not 0)!!!
- * Exception 0 is reserved for normal path of setjmp()!!!
- */
- PJ_ASSERT_RETURN(id>0 && id<PJ_MAX_EXCEPTION_ID, PJ_EINVAL);
-
- pj_enter_critical_section();
- exception_id_names[id] = NULL;
- pj_leave_critical_section();
-
- return PJ_SUCCESS;
-
-}
-
-PJ_DEF(const char*) pj_exception_id_name(pj_exception_id_t id)
-{
- /*
- * Start from 1 (not 0)!!!
- * Exception 0 is reserved for normal path of setjmp()!!!
- */
- PJ_ASSERT_RETURN(id>0 && id<PJ_MAX_EXCEPTION_ID, "<Invalid ID>");
-
- if (exception_id_names[id] == NULL)
- return "<Unallocated ID>";
-
- return exception_id_names[id];
-}
-
-#else /* PJ_HAS_EXCEPTION_NAMES */
-PJ_DEF(pj_status_t) pj_exception_id_alloc( const char *name,
- pj_exception_id_t *id)
-{
- PJ_ASSERT_RETURN(last_exception_id < PJ_MAX_EXCEPTION_ID-1, PJ_ETOOMANY);
-
- *id = last_exception_id++
- return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_exception_id_free( pj_exception_id_t id )
-{
- return PJ_SUCCESS;
-}
-
-PJ_DEF(const char*) pj_exception_id_name(pj_exception_id_t id)
-{
- return "";
-}
-
-#endif /* PJ_HAS_EXCEPTION_NAMES */
-
-
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/except.h>
+#include <pj/os.h>
+#include <pj/assert.h>
+#include <pj/log.h>
+#include <pj/errno.h>
+
+static long thread_local_id = -1;
+
+#if defined(PJ_HAS_EXCEPTION_NAMES) && PJ_HAS_EXCEPTION_NAMES != 0
+ static const char *exception_id_names[PJ_MAX_EXCEPTION_ID];
+#else
+ /*
+ * Start from 1 (not 0)!!!
+ * Exception 0 is reserved for normal path of setjmp()!!!
+ */
+ static int last_exception_id = 1;
+#endif /* PJ_HAS_EXCEPTION_NAMES */
+
+
+PJ_DEF(void) pj_throw_exception_(int exception_id)
+{
+ struct pj_exception_state_t *handler;
+
+ handler = pj_thread_local_get(thread_local_id);
+ if (handler == NULL) {
+ PJ_LOG(1,("except.c", "!!!FATAL: unhandled exception %d!\n", exception_id));
+ pj_assert(handler != NULL);
+ /* This will crash the system! */
+ }
+ pj_longjmp(handler->state, exception_id);
+}
+
+PJ_DEF(void) pj_push_exception_handler_(struct pj_exception_state_t *rec)
+{
+ struct pj_exception_state_t *parent_handler = NULL;
+
+ if (thread_local_id == -1) {
+ pj_thread_local_alloc(&thread_local_id);
+ pj_assert(thread_local_id != -1);
+ }
+ parent_handler = pj_thread_local_get(thread_local_id);
+ rec->prev = parent_handler;
+ pj_thread_local_set(thread_local_id, rec);
+}
+
+PJ_DEF(void) pj_pop_exception_handler_(void)
+{
+ struct pj_exception_state_t *handler;
+
+ handler = pj_thread_local_get(thread_local_id);
+ pj_assert(handler != NULL);
+ pj_thread_local_set(thread_local_id, handler->prev);
+}
+
+#if defined(PJ_HAS_EXCEPTION_NAMES) && PJ_HAS_EXCEPTION_NAMES != 0
+PJ_DEF(pj_status_t) pj_exception_id_alloc( const char *name,
+ pj_exception_id_t *id)
+{
+ unsigned i;
+
+ pj_enter_critical_section();
+
+ /*
+ * Start from 1 (not 0)!!!
+ * Exception 0 is reserved for normal path of setjmp()!!!
+ */
+ for (i=1; i<PJ_MAX_EXCEPTION_ID; ++i) {
+ if (exception_id_names[i] == NULL) {
+ exception_id_names[i] = name;
+ *id = i;
+ pj_leave_critical_section();
+ return PJ_SUCCESS;
+ }
+ }
+
+ pj_leave_critical_section();
+ return PJ_ETOOMANY;
+}
+
+PJ_DEF(pj_status_t) pj_exception_id_free( pj_exception_id_t id )
+{
+ /*
+ * Start from 1 (not 0)!!!
+ * Exception 0 is reserved for normal path of setjmp()!!!
+ */
+ PJ_ASSERT_RETURN(id>0 && id<PJ_MAX_EXCEPTION_ID, PJ_EINVAL);
+
+ pj_enter_critical_section();
+ exception_id_names[id] = NULL;
+ pj_leave_critical_section();
+
+ return PJ_SUCCESS;
+
+}
+
+PJ_DEF(const char*) pj_exception_id_name(pj_exception_id_t id)
+{
+ /*
+ * Start from 1 (not 0)!!!
+ * Exception 0 is reserved for normal path of setjmp()!!!
+ */
+ PJ_ASSERT_RETURN(id>0 && id<PJ_MAX_EXCEPTION_ID, "<Invalid ID>");
+
+ if (exception_id_names[id] == NULL)
+ return "<Unallocated ID>";
+
+ return exception_id_names[id];
+}
+
+#else /* PJ_HAS_EXCEPTION_NAMES */
+PJ_DEF(pj_status_t) pj_exception_id_alloc( const char *name,
+ pj_exception_id_t *id)
+{
+ PJ_ASSERT_RETURN(last_exception_id < PJ_MAX_EXCEPTION_ID-1, PJ_ETOOMANY);
+
+ *id = last_exception_id++
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_exception_id_free( pj_exception_id_t id )
+{
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(const char*) pj_exception_id_name(pj_exception_id_t id)
+{
+ return "";
+}
+
+#endif /* PJ_HAS_EXCEPTION_NAMES */
+
+
+
diff --git a/pjlib/src/pj/extra-exports.c b/pjlib/src/pj/extra-exports.c
index 29e1921d..af7276cb 100644
--- a/pjlib/src/pj/extra-exports.c
+++ b/pjlib/src/pj/extra-exports.c
@@ -1,32 +1,53 @@
-/* $Id$
- *
- */
-/*
- * This file contains code to export extra symbols from Linux kernel.
- * It should be copied to Linux kernel source tree and added to
- * Linux kernel combilation.
- *
- * This file is part of PJLIB project.
- */
-#include <linux/module.h>
-#include <linux/syscalls.h>
-
-EXPORT_SYMBOL(sys_select);
-
-EXPORT_SYMBOL(sys_epoll_create);
-EXPORT_SYMBOL(sys_epoll_ctl);
-EXPORT_SYMBOL(sys_epoll_wait);
-
-EXPORT_SYMBOL(sys_socket);
-EXPORT_SYMBOL(sys_bind);
-EXPORT_SYMBOL(sys_getpeername);
-EXPORT_SYMBOL(sys_getsockname);
-EXPORT_SYMBOL(sys_sendto);
-EXPORT_SYMBOL(sys_recvfrom);
-EXPORT_SYMBOL(sys_getsockopt);
-EXPORT_SYMBOL(sys_setsockopt);
-EXPORT_SYMBOL(sys_listen);
-EXPORT_SYMBOL(sys_shutdown);
-EXPORT_SYMBOL(sys_connect);
-EXPORT_SYMBOL(sys_accept);
-
+/* $Id$
+ *
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*
+ * This file contains code to export extra symbols from Linux kernel.
+ * It should be copied to Linux kernel source tree and added to
+ * Linux kernel combilation.
+ *
+ * This file is part of PJLIB project.
+ */
+#include <linux/module.h>
+#include <linux/syscalls.h>
+
+EXPORT_SYMBOL(sys_select);
+
+EXPORT_SYMBOL(sys_epoll_create);
+EXPORT_SYMBOL(sys_epoll_ctl);
+EXPORT_SYMBOL(sys_epoll_wait);
+
+EXPORT_SYMBOL(sys_socket);
+EXPORT_SYMBOL(sys_bind);
+EXPORT_SYMBOL(sys_getpeername);
+EXPORT_SYMBOL(sys_getsockname);
+EXPORT_SYMBOL(sys_sendto);
+EXPORT_SYMBOL(sys_recvfrom);
+EXPORT_SYMBOL(sys_getsockopt);
+EXPORT_SYMBOL(sys_setsockopt);
+EXPORT_SYMBOL(sys_listen);
+EXPORT_SYMBOL(sys_shutdown);
+EXPORT_SYMBOL(sys_connect);
+EXPORT_SYMBOL(sys_accept);
+
diff --git a/pjlib/src/pj/fifobuf.c b/pjlib/src/pj/fifobuf.c
index 0368ef32..2902363a 100644
--- a/pjlib/src/pj/fifobuf.c
+++ b/pjlib/src/pj/fifobuf.c
@@ -1,177 +1,198 @@
-/* $Id$
- */
-#include <pj/fifobuf.h>
-#include <pj/log.h>
-#include <pj/assert.h>
-#include <pj/os.h>
-
-#define THIS_FILE "fifobuf"
-
-#define SZ sizeof(unsigned)
-
-PJ_DEF(void)
-pj_fifobuf_init (pj_fifobuf_t *fifobuf, void *buffer, unsigned size)
-{
- PJ_CHECK_STACK();
-
- PJ_LOG(6, (THIS_FILE,
- "fifobuf_init fifobuf=%p buffer=%p, size=%d",
- fifobuf, buffer, size));
-
- fifobuf->first = buffer;
- fifobuf->last = fifobuf->first + size;
- fifobuf->ubegin = fifobuf->uend = fifobuf->first;
- fifobuf->full = 0;
-}
-
-PJ_DEF(unsigned)
-pj_fifobuf_max_size (pj_fifobuf_t *fifobuf)
-{
- unsigned s1, s2;
-
- PJ_CHECK_STACK();
-
- if (fifobuf->uend >= fifobuf->ubegin) {
- s1 = fifobuf->last - fifobuf->uend;
- s2 = fifobuf->ubegin - fifobuf->first;
- } else {
- s1 = s2 = fifobuf->ubegin - fifobuf->uend;
- }
-
- return s1<s2 ? s2 : s1;
-}
-
-PJ_DEF(void*)
-pj_fifobuf_alloc (pj_fifobuf_t *fifobuf, unsigned size)
-{
- unsigned available;
- char *start;
-
- PJ_CHECK_STACK();
-
- if (fifobuf->full) {
- PJ_LOG(6, (THIS_FILE,
- "fifobuf_alloc fifobuf=%p, size=%d: full!",
- fifobuf, size));
- return NULL;
- }
-
- /* try to allocate from the end part of the fifo */
- if (fifobuf->uend >= fifobuf->ubegin) {
- available = fifobuf->last - fifobuf->uend;
- if (available >= size+SZ) {
- char *ptr = fifobuf->uend;
- fifobuf->uend += (size+SZ);
- if (fifobuf->uend == fifobuf->last)
- fifobuf->uend = fifobuf->first;
- if (fifobuf->uend == fifobuf->ubegin)
- fifobuf->full = 1;
- *(unsigned*)ptr = size+SZ;
- ptr += SZ;
-
- PJ_LOG(6, (THIS_FILE,
- "fifobuf_alloc fifobuf=%p, size=%d: returning %p, p1=%p, p2=%p",
- fifobuf, size, ptr, fifobuf->ubegin, fifobuf->uend));
- return ptr;
- }
- }
-
- /* try to allocate from the start part of the fifo */
- start = (fifobuf->uend <= fifobuf->ubegin) ? fifobuf->uend : fifobuf->first;
- available = fifobuf->ubegin - start;
- if (available >= size+SZ) {
- char *ptr = start;
- fifobuf->uend = start + size + SZ;
- if (fifobuf->uend == fifobuf->ubegin)
- fifobuf->full = 1;
- *(unsigned*)ptr = size+SZ;
- ptr += SZ;
-
- PJ_LOG(6, (THIS_FILE,
- "fifobuf_alloc fifobuf=%p, size=%d: returning %p, p1=%p, p2=%p",
- fifobuf, size, ptr, fifobuf->ubegin, fifobuf->uend));
- return ptr;
- }
-
- PJ_LOG(6, (THIS_FILE,
- "fifobuf_alloc fifobuf=%p, size=%d: no space left! p1=%p, p2=%p",
- fifobuf, size, fifobuf->ubegin, fifobuf->uend));
- return NULL;
-}
-
-PJ_DEF(pj_status_t)
-pj_fifobuf_unalloc (pj_fifobuf_t *fifobuf, void *buf)
-{
- char *ptr = buf;
- char *endptr;
- unsigned sz;
-
- PJ_CHECK_STACK();
-
- ptr -= SZ;
- sz = *(unsigned*)ptr;
-
- endptr = fifobuf->uend;
- if (endptr == fifobuf->first)
- endptr = fifobuf->last;
-
- if (ptr+sz != endptr) {
- pj_assert(!"Invalid pointer to undo alloc");
- return -1;
- }
-
- fifobuf->uend = ptr;
- fifobuf->full = 0;
-
- PJ_LOG(6, (THIS_FILE,
- "fifobuf_unalloc fifobuf=%p, ptr=%p, size=%d, p1=%p, p2=%p",
- fifobuf, buf, sz, fifobuf->ubegin, fifobuf->uend));
-
- return 0;
-}
-
-PJ_DEF(pj_status_t)
-pj_fifobuf_free (pj_fifobuf_t *fifobuf, void *buf)
-{
- char *ptr = buf;
- char *end;
- unsigned sz;
-
- PJ_CHECK_STACK();
-
- ptr -= SZ;
- if (ptr < fifobuf->first || ptr >= fifobuf->last) {
- pj_assert(!"Invalid pointer to free");
- return -1;
- }
-
- if (ptr != fifobuf->ubegin && ptr != fifobuf->first) {
- pj_assert(!"Invalid free() sequence!");
- return -1;
- }
-
- end = (fifobuf->uend > fifobuf->ubegin) ? fifobuf->uend : fifobuf->last;
- sz = *(unsigned*)ptr;
- if (ptr+sz > end) {
- pj_assert(!"Invalid size!");
- return -1;
- }
-
- fifobuf->ubegin = ptr + sz;
-
- /* Rollover */
- if (fifobuf->ubegin == fifobuf->last)
- fifobuf->ubegin = fifobuf->first;
-
- /* Reset if fifobuf is empty */
- if (fifobuf->ubegin == fifobuf->uend)
- fifobuf->ubegin = fifobuf->uend = fifobuf->first;
-
- fifobuf->full = 0;
-
- PJ_LOG(6, (THIS_FILE,
- "fifobuf_free fifobuf=%p, ptr=%p, size=%d, p1=%p, p2=%p",
- fifobuf, buf, sz, fifobuf->ubegin, fifobuf->uend));
-
- return 0;
-}
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/fifobuf.h>
+#include <pj/log.h>
+#include <pj/assert.h>
+#include <pj/os.h>
+
+#define THIS_FILE "fifobuf"
+
+#define SZ sizeof(unsigned)
+
+PJ_DEF(void)
+pj_fifobuf_init (pj_fifobuf_t *fifobuf, void *buffer, unsigned size)
+{
+ PJ_CHECK_STACK();
+
+ PJ_LOG(6, (THIS_FILE,
+ "fifobuf_init fifobuf=%p buffer=%p, size=%d",
+ fifobuf, buffer, size));
+
+ fifobuf->first = buffer;
+ fifobuf->last = fifobuf->first + size;
+ fifobuf->ubegin = fifobuf->uend = fifobuf->first;
+ fifobuf->full = 0;
+}
+
+PJ_DEF(unsigned)
+pj_fifobuf_max_size (pj_fifobuf_t *fifobuf)
+{
+ unsigned s1, s2;
+
+ PJ_CHECK_STACK();
+
+ if (fifobuf->uend >= fifobuf->ubegin) {
+ s1 = fifobuf->last - fifobuf->uend;
+ s2 = fifobuf->ubegin - fifobuf->first;
+ } else {
+ s1 = s2 = fifobuf->ubegin - fifobuf->uend;
+ }
+
+ return s1<s2 ? s2 : s1;
+}
+
+PJ_DEF(void*)
+pj_fifobuf_alloc (pj_fifobuf_t *fifobuf, unsigned size)
+{
+ unsigned available;
+ char *start;
+
+ PJ_CHECK_STACK();
+
+ if (fifobuf->full) {
+ PJ_LOG(6, (THIS_FILE,
+ "fifobuf_alloc fifobuf=%p, size=%d: full!",
+ fifobuf, size));
+ return NULL;
+ }
+
+ /* try to allocate from the end part of the fifo */
+ if (fifobuf->uend >= fifobuf->ubegin) {
+ available = fifobuf->last - fifobuf->uend;
+ if (available >= size+SZ) {
+ char *ptr = fifobuf->uend;
+ fifobuf->uend += (size+SZ);
+ if (fifobuf->uend == fifobuf->last)
+ fifobuf->uend = fifobuf->first;
+ if (fifobuf->uend == fifobuf->ubegin)
+ fifobuf->full = 1;
+ *(unsigned*)ptr = size+SZ;
+ ptr += SZ;
+
+ PJ_LOG(6, (THIS_FILE,
+ "fifobuf_alloc fifobuf=%p, size=%d: returning %p, p1=%p, p2=%p",
+ fifobuf, size, ptr, fifobuf->ubegin, fifobuf->uend));
+ return ptr;
+ }
+ }
+
+ /* try to allocate from the start part of the fifo */
+ start = (fifobuf->uend <= fifobuf->ubegin) ? fifobuf->uend : fifobuf->first;
+ available = fifobuf->ubegin - start;
+ if (available >= size+SZ) {
+ char *ptr = start;
+ fifobuf->uend = start + size + SZ;
+ if (fifobuf->uend == fifobuf->ubegin)
+ fifobuf->full = 1;
+ *(unsigned*)ptr = size+SZ;
+ ptr += SZ;
+
+ PJ_LOG(6, (THIS_FILE,
+ "fifobuf_alloc fifobuf=%p, size=%d: returning %p, p1=%p, p2=%p",
+ fifobuf, size, ptr, fifobuf->ubegin, fifobuf->uend));
+ return ptr;
+ }
+
+ PJ_LOG(6, (THIS_FILE,
+ "fifobuf_alloc fifobuf=%p, size=%d: no space left! p1=%p, p2=%p",
+ fifobuf, size, fifobuf->ubegin, fifobuf->uend));
+ return NULL;
+}
+
+PJ_DEF(pj_status_t)
+pj_fifobuf_unalloc (pj_fifobuf_t *fifobuf, void *buf)
+{
+ char *ptr = buf;
+ char *endptr;
+ unsigned sz;
+
+ PJ_CHECK_STACK();
+
+ ptr -= SZ;
+ sz = *(unsigned*)ptr;
+
+ endptr = fifobuf->uend;
+ if (endptr == fifobuf->first)
+ endptr = fifobuf->last;
+
+ if (ptr+sz != endptr) {
+ pj_assert(!"Invalid pointer to undo alloc");
+ return -1;
+ }
+
+ fifobuf->uend = ptr;
+ fifobuf->full = 0;
+
+ PJ_LOG(6, (THIS_FILE,
+ "fifobuf_unalloc fifobuf=%p, ptr=%p, size=%d, p1=%p, p2=%p",
+ fifobuf, buf, sz, fifobuf->ubegin, fifobuf->uend));
+
+ return 0;
+}
+
+PJ_DEF(pj_status_t)
+pj_fifobuf_free (pj_fifobuf_t *fifobuf, void *buf)
+{
+ char *ptr = buf;
+ char *end;
+ unsigned sz;
+
+ PJ_CHECK_STACK();
+
+ ptr -= SZ;
+ if (ptr < fifobuf->first || ptr >= fifobuf->last) {
+ pj_assert(!"Invalid pointer to free");
+ return -1;
+ }
+
+ if (ptr != fifobuf->ubegin && ptr != fifobuf->first) {
+ pj_assert(!"Invalid free() sequence!");
+ return -1;
+ }
+
+ end = (fifobuf->uend > fifobuf->ubegin) ? fifobuf->uend : fifobuf->last;
+ sz = *(unsigned*)ptr;
+ if (ptr+sz > end) {
+ pj_assert(!"Invalid size!");
+ return -1;
+ }
+
+ fifobuf->ubegin = ptr + sz;
+
+ /* Rollover */
+ if (fifobuf->ubegin == fifobuf->last)
+ fifobuf->ubegin = fifobuf->first;
+
+ /* Reset if fifobuf is empty */
+ if (fifobuf->ubegin == fifobuf->uend)
+ fifobuf->ubegin = fifobuf->uend = fifobuf->first;
+
+ fifobuf->full = 0;
+
+ PJ_LOG(6, (THIS_FILE,
+ "fifobuf_free fifobuf=%p, ptr=%p, size=%d, p1=%p, p2=%p",
+ fifobuf, buf, sz, fifobuf->ubegin, fifobuf->uend));
+
+ return 0;
+}
diff --git a/pjlib/src/pj/file_access_unistd.c b/pjlib/src/pj/file_access_unistd.c
index 8e46e0ed..b4e0ab48 100644
--- a/pjlib/src/pj/file_access_unistd.c
+++ b/pjlib/src/pj/file_access_unistd.c
@@ -1,96 +1,117 @@
-/* $Id$ */
-#include <pj/file_access.h>
-#include <pj/assert.h>
-#include <pj/errno.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <stdio.h> /* rename() */
-#include <errno.h>
-
-/*
- * pj_file_exists()
- */
-PJ_DEF(pj_bool_t) pj_file_exists(const char *filename)
-{
- struct stat buf;
-
- PJ_ASSERT_RETURN(filename, 0);
-
- if (stat(filename, &buf) != 0)
- return 0;
-
- return PJ_TRUE;
-}
-
-
-/*
- * pj_file_size()
- */
-PJ_DEF(pj_off_t) pj_file_size(const char *filename)
-{
- struct stat buf;
-
- PJ_ASSERT_RETURN(filename, -1);
-
- if (stat(filename, &buf) != 0)
- return -1;
-
- return buf.st_size;
-}
-
-
-/*
- * pj_file_delete()
- */
-PJ_DEF(pj_status_t) pj_file_delete(const char *filename)
-{
- PJ_ASSERT_RETURN(filename, PJ_EINVAL);
-
- if (unlink(filename)!=0) {
- return PJ_RETURN_OS_ERROR(errno);
- }
- return PJ_SUCCESS;
-}
-
-
-/*
- * pj_file_move()
- */
-PJ_DEF(pj_status_t) pj_file_move( const char *oldname, const char *newname)
-{
- PJ_ASSERT_RETURN(oldname && newname, PJ_EINVAL);
-
- if (rename(oldname, newname) != 0) {
- return PJ_RETURN_OS_ERROR(errno);
- }
- return PJ_SUCCESS;
-}
-
-
-/*
- * pj_file_getstat()
- */
-PJ_DEF(pj_status_t) pj_file_getstat(const char *filename,
- pj_file_stat *statbuf)
-{
- struct stat buf;
-
- PJ_ASSERT_RETURN(filename && statbuf, PJ_EINVAL);
-
- if (stat(filename, &buf) != 0) {
- return PJ_RETURN_OS_ERROR(errno);
- }
-
- statbuf->size = buf.st_size;
- statbuf->ctime.sec = buf.st_ctime;
- statbuf->ctime.msec = 0;
- statbuf->mtime.sec = buf.st_mtime;
- statbuf->mtime.msec = 0;
- statbuf->atime.sec = buf.st_atime;
- statbuf->atime.msec = 0;
-
- return PJ_SUCCESS;
-}
-
+/* $Id$ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/file_access.h>
+#include <pj/assert.h>
+#include <pj/errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h> /* rename() */
+#include <errno.h>
+
+/*
+ * pj_file_exists()
+ */
+PJ_DEF(pj_bool_t) pj_file_exists(const char *filename)
+{
+ struct stat buf;
+
+ PJ_ASSERT_RETURN(filename, 0);
+
+ if (stat(filename, &buf) != 0)
+ return 0;
+
+ return PJ_TRUE;
+}
+
+
+/*
+ * pj_file_size()
+ */
+PJ_DEF(pj_off_t) pj_file_size(const char *filename)
+{
+ struct stat buf;
+
+ PJ_ASSERT_RETURN(filename, -1);
+
+ if (stat(filename, &buf) != 0)
+ return -1;
+
+ return buf.st_size;
+}
+
+
+/*
+ * pj_file_delete()
+ */
+PJ_DEF(pj_status_t) pj_file_delete(const char *filename)
+{
+ PJ_ASSERT_RETURN(filename, PJ_EINVAL);
+
+ if (unlink(filename)!=0) {
+ return PJ_RETURN_OS_ERROR(errno);
+ }
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * pj_file_move()
+ */
+PJ_DEF(pj_status_t) pj_file_move( const char *oldname, const char *newname)
+{
+ PJ_ASSERT_RETURN(oldname && newname, PJ_EINVAL);
+
+ if (rename(oldname, newname) != 0) {
+ return PJ_RETURN_OS_ERROR(errno);
+ }
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * pj_file_getstat()
+ */
+PJ_DEF(pj_status_t) pj_file_getstat(const char *filename,
+ pj_file_stat *statbuf)
+{
+ struct stat buf;
+
+ PJ_ASSERT_RETURN(filename && statbuf, PJ_EINVAL);
+
+ if (stat(filename, &buf) != 0) {
+ return PJ_RETURN_OS_ERROR(errno);
+ }
+
+ statbuf->size = buf.st_size;
+ statbuf->ctime.sec = buf.st_ctime;
+ statbuf->ctime.msec = 0;
+ statbuf->mtime.sec = buf.st_mtime;
+ statbuf->mtime.msec = 0;
+ statbuf->atime.sec = buf.st_atime;
+ statbuf->atime.msec = 0;
+
+ return PJ_SUCCESS;
+}
+
diff --git a/pjlib/src/pj/file_access_win32.c b/pjlib/src/pj/file_access_win32.c
index 36405658..7aeceb8f 100644
--- a/pjlib/src/pj/file_access_win32.c
+++ b/pjlib/src/pj/file_access_win32.c
@@ -1,4 +1,25 @@
/* $Id$ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
#include <pj/file_access.h>
#include <pj/assert.h>
#include <pj/errno.h>
diff --git a/pjlib/src/pj/file_io_ansi.c b/pjlib/src/pj/file_io_ansi.c
index 0946eddc..3acb91ee 100644
--- a/pjlib/src/pj/file_io_ansi.c
+++ b/pjlib/src/pj/file_io_ansi.c
@@ -1,140 +1,161 @@
-/* $Id$ */
-#include <pj/file_io.h>
-#include <pj/assert.h>
-#include <pj/errno.h>
-#include <stdio.h>
-#include <errno.h>
-
-PJ_DEF(pj_status_t) pj_file_open( pj_pool_t *pool,
- const char *pathname,
- unsigned flags,
- pj_oshandle_t *fd)
-{
- char mode[8];
- char *p = mode;
-
- PJ_ASSERT_RETURN(pathname && fd, PJ_EINVAL);
- PJ_UNUSED_ARG(pool);
-
- if ((flags & PJ_O_APPEND) == PJ_O_APPEND) {
- if ((flags & PJ_O_WRONLY) == PJ_O_WRONLY) {
- *p++ = 'a';
- if ((flags & PJ_O_RDONLY) == PJ_O_RDONLY)
- *p++ = '+';
- } else {
- /* This is invalid.
- * Can not specify PJ_O_RDONLY with PJ_O_APPEND!
- */
- }
- } else {
- if ((flags & PJ_O_RDONLY) == PJ_O_RDONLY) {
- *p++ = 'r';
- if ((flags & PJ_O_WRONLY) == PJ_O_WRONLY)
- *p++ = '+';
- } else {
- *p++ = 'w';
- }
- }
-
- if (p==mode)
- return PJ_EINVAL;
-
- *p++ = 'b';
- *p++ = '\0';
-
- *fd = fopen(pathname, mode);
- if (*fd == NULL)
- return PJ_RETURN_OS_ERROR(errno);
-
- return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_file_close(pj_oshandle_t fd)
-{
- PJ_ASSERT_RETURN(fd, PJ_EINVAL);
- if (fclose((FILE*)fd) != 0)
- return PJ_RETURN_OS_ERROR(errno);
-
- return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_file_write( pj_oshandle_t fd,
- const void *data,
- pj_ssize_t *size)
-{
- size_t written;
-
- clearerr((FILE*)fd);
- written = fwrite(data, 1, *size, (FILE*)fd);
+/* $Id$ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/file_io.h>
+#include <pj/assert.h>
+#include <pj/errno.h>
+#include <stdio.h>
+#include <errno.h>
+
+PJ_DEF(pj_status_t) pj_file_open( pj_pool_t *pool,
+ const char *pathname,
+ unsigned flags,
+ pj_oshandle_t *fd)
+{
+ char mode[8];
+ char *p = mode;
+
+ PJ_ASSERT_RETURN(pathname && fd, PJ_EINVAL);
+ PJ_UNUSED_ARG(pool);
+
+ if ((flags & PJ_O_APPEND) == PJ_O_APPEND) {
+ if ((flags & PJ_O_WRONLY) == PJ_O_WRONLY) {
+ *p++ = 'a';
+ if ((flags & PJ_O_RDONLY) == PJ_O_RDONLY)
+ *p++ = '+';
+ } else {
+ /* This is invalid.
+ * Can not specify PJ_O_RDONLY with PJ_O_APPEND!
+ */
+ }
+ } else {
+ if ((flags & PJ_O_RDONLY) == PJ_O_RDONLY) {
+ *p++ = 'r';
+ if ((flags & PJ_O_WRONLY) == PJ_O_WRONLY)
+ *p++ = '+';
+ } else {
+ *p++ = 'w';
+ }
+ }
+
+ if (p==mode)
+ return PJ_EINVAL;
+
+ *p++ = 'b';
+ *p++ = '\0';
+
+ *fd = fopen(pathname, mode);
+ if (*fd == NULL)
+ return PJ_RETURN_OS_ERROR(errno);
+
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_file_close(pj_oshandle_t fd)
+{
+ PJ_ASSERT_RETURN(fd, PJ_EINVAL);
+ if (fclose((FILE*)fd) != 0)
+ return PJ_RETURN_OS_ERROR(errno);
+
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_file_write( pj_oshandle_t fd,
+ const void *data,
+ pj_ssize_t *size)
+{
+ size_t written;
+
+ clearerr((FILE*)fd);
+ written = fwrite(data, 1, *size, (FILE*)fd);
if (ferror((FILE*)fd)) {
- *size = -1;
- return PJ_RETURN_OS_ERROR(errno);
- }
-
- *size = written;
- return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_file_read( pj_oshandle_t fd,
- void *data,
- pj_ssize_t *size)
-{
- size_t bytes;
-
- clearerr((FILE*)fd);
- bytes = fread(data, 1, *size, (FILE*)fd);
+ *size = -1;
+ return PJ_RETURN_OS_ERROR(errno);
+ }
+
+ *size = written;
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_file_read( pj_oshandle_t fd,
+ void *data,
+ pj_ssize_t *size)
+{
+ size_t bytes;
+
+ clearerr((FILE*)fd);
+ bytes = fread(data, 1, *size, (FILE*)fd);
if (ferror((FILE*)fd)) {
- *size = -1;
- return PJ_RETURN_OS_ERROR(errno);
- }
-
- *size = bytes;
- return PJ_SUCCESS;
-}
+ *size = -1;
+ return PJ_RETURN_OS_ERROR(errno);
+ }
+
+ *size = bytes;
+ return PJ_SUCCESS;
+}
PJ_DEF(pj_bool_t) pj_file_eof(pj_oshandle_t fd, enum pj_file_access access)
{
PJ_UNUSED_ARG(access);
return feof((FILE*)fd) ? PJ_TRUE : 0;
}
-
-PJ_DEF(pj_status_t) pj_file_setpos( pj_oshandle_t fd,
- pj_off_t offset,
- enum pj_file_seek_type whence)
-{
- int mode;
-
- switch (whence) {
- case PJ_SEEK_SET:
- mode = SEEK_SET; break;
- case PJ_SEEK_CUR:
- mode = SEEK_CUR; break;
- case PJ_SEEK_END:
- mode = SEEK_END; break;
- default:
- pj_assert(!"Invalid whence in file_setpos");
- return PJ_EINVAL;
- }
-
- if (fseek((FILE*)fd, (long)offset, mode) != 0)
- return PJ_RETURN_OS_ERROR(errno);
-
- return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_file_getpos( pj_oshandle_t fd,
- pj_off_t *pos)
-{
- long offset;
-
- offset = ftell((FILE*)fd);
- if (offset == -1) {
- *pos = -1;
- return PJ_RETURN_OS_ERROR(errno);
- }
-
- *pos = offset;
- return PJ_SUCCESS;
-}
-
-
+
+PJ_DEF(pj_status_t) pj_file_setpos( pj_oshandle_t fd,
+ pj_off_t offset,
+ enum pj_file_seek_type whence)
+{
+ int mode;
+
+ switch (whence) {
+ case PJ_SEEK_SET:
+ mode = SEEK_SET; break;
+ case PJ_SEEK_CUR:
+ mode = SEEK_CUR; break;
+ case PJ_SEEK_END:
+ mode = SEEK_END; break;
+ default:
+ pj_assert(!"Invalid whence in file_setpos");
+ return PJ_EINVAL;
+ }
+
+ if (fseek((FILE*)fd, (long)offset, mode) != 0)
+ return PJ_RETURN_OS_ERROR(errno);
+
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_file_getpos( pj_oshandle_t fd,
+ pj_off_t *pos)
+{
+ long offset;
+
+ offset = ftell((FILE*)fd);
+ if (offset == -1) {
+ *pos = -1;
+ return PJ_RETURN_OS_ERROR(errno);
+ }
+
+ *pos = offset;
+ return PJ_SUCCESS;
+}
+
+
diff --git a/pjlib/src/pj/file_io_win32.c b/pjlib/src/pj/file_io_win32.c
index d9908410..d90f5f4c 100644
--- a/pjlib/src/pj/file_io_win32.c
+++ b/pjlib/src/pj/file_io_win32.c
@@ -1,13 +1,34 @@
-/* $Id$ */
-#include <pj/file_io.h>
-#include <pj/errno.h>
-#include <pj/assert.h>
-
-#include <windows.h>
-
-#ifndef INVALID_SET_FILE_POINTER
-# define INVALID_SET_FILE_POINTER ((DWORD)-1)
-#endif
+/* $Id$ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/file_io.h>
+#include <pj/errno.h>
+#include <pj/assert.h>
+
+#include <windows.h>
+
+#ifndef INVALID_SET_FILE_POINTER
+# define INVALID_SET_FILE_POINTER ((DWORD)-1)
+#endif
/**
* Check for end-of-file condition on the specified descriptor.
@@ -19,97 +40,97 @@
*/
PJ_DECL(pj_bool_t) pj_file_eof(pj_oshandle_t fd,
enum pj_file_access access);
-
-
-PJ_DEF(pj_status_t) pj_file_open( pj_pool_t *pool,
- const char *pathname,
- unsigned flags,
- pj_oshandle_t *fd)
-{
- HANDLE hFile;
- DWORD dwDesiredAccess = 0;
- DWORD dwShareMode = 0;
- DWORD dwCreationDisposition = 0;
- DWORD dwFlagsAndAttributes = 0;
-
- PJ_UNUSED_ARG(pool);
-
- PJ_ASSERT_RETURN(pathname!=NULL, PJ_EINVAL);
-
- if ((flags & PJ_O_WRONLY) == PJ_O_WRONLY) {
- dwDesiredAccess |= GENERIC_WRITE;
- if ((flags & PJ_O_APPEND) == PJ_O_APPEND) {
- dwDesiredAccess |= FILE_APPEND_DATA;
- } else {
+
+
+PJ_DEF(pj_status_t) pj_file_open( pj_pool_t *pool,
+ const char *pathname,
+ unsigned flags,
+ pj_oshandle_t *fd)
+{
+ HANDLE hFile;
+ DWORD dwDesiredAccess = 0;
+ DWORD dwShareMode = 0;
+ DWORD dwCreationDisposition = 0;
+ DWORD dwFlagsAndAttributes = 0;
+
+ PJ_UNUSED_ARG(pool);
+
+ PJ_ASSERT_RETURN(pathname!=NULL, PJ_EINVAL);
+
+ if ((flags & PJ_O_WRONLY) == PJ_O_WRONLY) {
+ dwDesiredAccess |= GENERIC_WRITE;
+ if ((flags & PJ_O_APPEND) == PJ_O_APPEND) {
+ dwDesiredAccess |= FILE_APPEND_DATA;
+ } else {
dwDesiredAccess &= ~(FILE_APPEND_DATA);
dwCreationDisposition |= CREATE_ALWAYS;
- }
- }
+ }
+ }
if ((flags & PJ_O_RDONLY) == PJ_O_RDONLY) {
dwDesiredAccess |= GENERIC_READ;
if (flags == PJ_O_RDONLY)
dwCreationDisposition |= OPEN_EXISTING;
}
-
- if (dwDesiredAccess == 0) {
- pj_assert(!"Invalid file open flags");
- return PJ_EINVAL;
- }
-
- dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
- dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
-
- hFile = CreateFile(pathname, dwDesiredAccess, dwShareMode, NULL,
- dwCreationDisposition, dwFlagsAndAttributes, NULL);
- if (hFile == INVALID_HANDLE_VALUE) {
- *fd = 0;
- return PJ_RETURN_OS_ERROR(GetLastError());
- }
-
- *fd = hFile;
- return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_file_close(pj_oshandle_t fd)
-{
- if (CloseHandle(fd)==0)
- return PJ_RETURN_OS_ERROR(GetLastError());
- return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_file_write( pj_oshandle_t fd,
- const void *data,
- pj_ssize_t *size)
-{
- BOOL rc;
- DWORD bytesWritten;
-
- rc = WriteFile(fd, data, *size, &bytesWritten, NULL);
- if (!rc) {
- *size = -1;
- return PJ_RETURN_OS_ERROR(GetLastError());
- }
-
- *size = bytesWritten;
- return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_file_read( pj_oshandle_t fd,
- void *data,
- pj_ssize_t *size)
-{
- BOOL rc;
- DWORD bytesRead;
-
- rc = ReadFile(fd, data, *size, &bytesRead, NULL);
- if (!rc) {
- *size = -1;
- return PJ_RETURN_OS_ERROR(GetLastError());
- }
-
- *size = bytesRead;
- return PJ_SUCCESS;
-}
+
+ if (dwDesiredAccess == 0) {
+ pj_assert(!"Invalid file open flags");
+ return PJ_EINVAL;
+ }
+
+ dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+ dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
+
+ hFile = CreateFile(pathname, dwDesiredAccess, dwShareMode, NULL,
+ dwCreationDisposition, dwFlagsAndAttributes, NULL);
+ if (hFile == INVALID_HANDLE_VALUE) {
+ *fd = 0;
+ return PJ_RETURN_OS_ERROR(GetLastError());
+ }
+
+ *fd = hFile;
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_file_close(pj_oshandle_t fd)
+{
+ if (CloseHandle(fd)==0)
+ return PJ_RETURN_OS_ERROR(GetLastError());
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_file_write( pj_oshandle_t fd,
+ const void *data,
+ pj_ssize_t *size)
+{
+ BOOL rc;
+ DWORD bytesWritten;
+
+ rc = WriteFile(fd, data, *size, &bytesWritten, NULL);
+ if (!rc) {
+ *size = -1;
+ return PJ_RETURN_OS_ERROR(GetLastError());
+ }
+
+ *size = bytesWritten;
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_file_read( pj_oshandle_t fd,
+ void *data,
+ pj_ssize_t *size)
+{
+ BOOL rc;
+ DWORD bytesRead;
+
+ rc = ReadFile(fd, data, *size, &bytesRead, NULL);
+ if (!rc) {
+ *size = -1;
+ return PJ_RETURN_OS_ERROR(GetLastError());
+ }
+
+ *size = bytesRead;
+ return PJ_SUCCESS;
+}
/*
PJ_DEF(pj_bool_t) pj_file_eof(pj_oshandle_t fd, enum pj_file_access access)
@@ -134,53 +155,53 @@ PJ_DEF(pj_bool_t) pj_file_eof(pj_oshandle_t fd, enum pj_file_access access)
return 0;
}
*/
-
-PJ_DEF(pj_status_t) pj_file_setpos( pj_oshandle_t fd,
- pj_off_t offset,
- enum pj_file_seek_type whence)
-{
- DWORD dwMoveMethod;
- DWORD dwNewPos;
- LONG hi32;
-
- if (whence == PJ_SEEK_SET)
- dwMoveMethod = FILE_BEGIN;
- else if (whence == PJ_SEEK_CUR)
- dwMoveMethod = FILE_CURRENT;
- else if (whence == PJ_SEEK_END)
- dwMoveMethod = FILE_END;
- else {
- pj_assert(!"Invalid whence in file_setpos");
- return PJ_EINVAL;
- }
-
- hi32 = (LONG)(offset >> 32);
- dwNewPos = SetFilePointer(fd, (long)offset, &hi32, dwMoveMethod);
- if (dwNewPos == (DWORD)INVALID_SET_FILE_POINTER) {
- DWORD dwStatus = GetLastError();
- if (dwStatus != 0)
- return PJ_RETURN_OS_ERROR(dwStatus);
- /* dwNewPos actually is not an error. */
- }
-
- return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_file_getpos( pj_oshandle_t fd,
- pj_off_t *pos)
-{
- LONG hi32 = 0;
- DWORD lo32;
-
- lo32 = SetFilePointer(fd, 0, &hi32, FILE_CURRENT);
- if (lo32 == (DWORD)INVALID_SET_FILE_POINTER) {
- DWORD dwStatus = GetLastError();
- if (dwStatus != 0)
- return PJ_RETURN_OS_ERROR(dwStatus);
- }
-
- *pos = hi32;
- *pos = (*pos << 32) + lo32;
- return PJ_SUCCESS;
-}
-
+
+PJ_DEF(pj_status_t) pj_file_setpos( pj_oshandle_t fd,
+ pj_off_t offset,
+ enum pj_file_seek_type whence)
+{
+ DWORD dwMoveMethod;
+ DWORD dwNewPos;
+ LONG hi32;
+
+ if (whence == PJ_SEEK_SET)
+ dwMoveMethod = FILE_BEGIN;
+ else if (whence == PJ_SEEK_CUR)
+ dwMoveMethod = FILE_CURRENT;
+ else if (whence == PJ_SEEK_END)
+ dwMoveMethod = FILE_END;
+ else {
+ pj_assert(!"Invalid whence in file_setpos");
+ return PJ_EINVAL;
+ }
+
+ hi32 = (LONG)(offset >> 32);
+ dwNewPos = SetFilePointer(fd, (long)offset, &hi32, dwMoveMethod);
+ if (dwNewPos == (DWORD)INVALID_SET_FILE_POINTER) {
+ DWORD dwStatus = GetLastError();
+ if (dwStatus != 0)
+ return PJ_RETURN_OS_ERROR(dwStatus);
+ /* dwNewPos actually is not an error. */
+ }
+
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_file_getpos( pj_oshandle_t fd,
+ pj_off_t *pos)
+{
+ LONG hi32 = 0;
+ DWORD lo32;
+
+ lo32 = SetFilePointer(fd, 0, &hi32, FILE_CURRENT);
+ if (lo32 == (DWORD)INVALID_SET_FILE_POINTER) {
+ DWORD dwStatus = GetLastError();
+ if (dwStatus != 0)
+ return PJ_RETURN_OS_ERROR(dwStatus);
+ }
+
+ *pos = hi32;
+ *pos = (*pos << 32) + lo32;
+ return PJ_SUCCESS;
+}
+
diff --git a/pjlib/src/pj/guid.c b/pjlib/src/pj/guid.c
index a99b3a80..735ea882 100644
--- a/pjlib/src/pj/guid.c
+++ b/pjlib/src/pj/guid.c
@@ -1,10 +1,31 @@
-/* $Id$
- */
-#include <pj/guid.h>
-#include <pj/pool.h>
-
-PJ_DEF(void) pj_create_unique_string(pj_pool_t *pool, pj_str_t *str)
-{
- str->ptr = pj_pool_alloc(pool, PJ_GUID_STRING_LENGTH);
- pj_generate_unique_string(str);
-}
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/guid.h>
+#include <pj/pool.h>
+
+PJ_DEF(void) pj_create_unique_string(pj_pool_t *pool, pj_str_t *str)
+{
+ str->ptr = pj_pool_alloc(pool, PJ_GUID_STRING_LENGTH);
+ pj_generate_unique_string(str);
+}
diff --git a/pjlib/src/pj/guid_simple.c b/pjlib/src/pj/guid_simple.c
index 6e41672a..4fb0a672 100644
--- a/pjlib/src/pj/guid_simple.c
+++ b/pjlib/src/pj/guid_simple.c
@@ -1,52 +1,73 @@
-/* $Id$
- *
- */
-#include <pj/guid.h>
-#include <pj/os.h>
-#include <pj/rand.h>
-#include <pj/string.h>
-#include <pj/compat/sprintf.h>
-
-const unsigned PJ_GUID_STRING_LENGTH=20;
-
-static void init_mac_address(unsigned char mac_addr[16])
-{
- unsigned long *ulval1 = (unsigned long*) &mac_addr[0];
- unsigned short *usval1 = (unsigned short*) &mac_addr[4];
-
- *ulval1 = pj_rand();
- *usval1 = (unsigned short) pj_rand();
-}
-
-PJ_DEF(pj_str_t*) pj_generate_unique_string(pj_str_t *str)
-{
- static int guid_initialized;
- static unsigned pid;
- static char str_pid[5];
- static unsigned char mac_addr[6];
- static char str_mac_addr[16];
- static unsigned clock_seq;
-
- PJ_CHECK_STACK();
-
- if (guid_initialized == 0) {
- pid = pj_getpid();
- init_mac_address(mac_addr);
- clock_seq = 0;
-
- sprintf(str_pid, "%04x", pid);
- sprintf(str_mac_addr, "%02x%02x%02x%02x%02x%02x",
- mac_addr[0], mac_addr[1], mac_addr[2],
- mac_addr[3], mac_addr[4], mac_addr[5]);
-
- guid_initialized = 1;
- }
-
- strcpy(str->ptr, str_pid);
- sprintf(str->ptr+4, "%04x", clock_seq++);
- pj_memcpy(str->ptr+8, str_mac_addr, 12);
- str->slen = 20;
-
- return str;
-}
-
+/* $Id$
+ *
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/guid.h>
+#include <pj/os.h>
+#include <pj/rand.h>
+#include <pj/string.h>
+#include <pj/compat/sprintf.h>
+
+const unsigned PJ_GUID_STRING_LENGTH=20;
+
+static void init_mac_address(unsigned char mac_addr[16])
+{
+ unsigned long *ulval1 = (unsigned long*) &mac_addr[0];
+ unsigned short *usval1 = (unsigned short*) &mac_addr[4];
+
+ *ulval1 = pj_rand();
+ *usval1 = (unsigned short) pj_rand();
+}
+
+PJ_DEF(pj_str_t*) pj_generate_unique_string(pj_str_t *str)
+{
+ static int guid_initialized;
+ static unsigned pid;
+ static char str_pid[5];
+ static unsigned char mac_addr[6];
+ static char str_mac_addr[16];
+ static unsigned clock_seq;
+
+ PJ_CHECK_STACK();
+
+ if (guid_initialized == 0) {
+ pid = pj_getpid();
+ init_mac_address(mac_addr);
+ clock_seq = 0;
+
+ sprintf(str_pid, "%04x", pid);
+ sprintf(str_mac_addr, "%02x%02x%02x%02x%02x%02x",
+ mac_addr[0], mac_addr[1], mac_addr[2],
+ mac_addr[3], mac_addr[4], mac_addr[5]);
+
+ guid_initialized = 1;
+ }
+
+ strcpy(str->ptr, str_pid);
+ sprintf(str->ptr+4, "%04x", clock_seq++);
+ pj_memcpy(str->ptr+8, str_mac_addr, 12);
+ str->slen = 20;
+
+ return str;
+}
+
diff --git a/pjlib/src/pj/guid_win32.c b/pjlib/src/pj/guid_win32.c
index 0832b8c5..b34b6e18 100644
--- a/pjlib/src/pj/guid_win32.c
+++ b/pjlib/src/pj/guid_win32.c
@@ -1,52 +1,73 @@
-/* $Id$
- */
-#include <pj/guid.h>
-#include <pj/string.h>
-#include <pj/sock.h>
-#include <windows.h>
-#include <objbase.h>
-#include <pj/os.h>
-
-
-const unsigned PJ_GUID_STRING_LENGTH=32;
-
-PJ_INLINE(void) hex2digit(unsigned value, char *p)
-{
- static char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
- *p++ = hex[ (value & 0xF0) >> 4 ];
- *p++ = hex[ (value & 0x0F) ];
-}
-
-static void guid_to_str( const GUID *guid, pj_str_t *str )
-{
- unsigned i;
- GUID guid_copy;
- const unsigned char *src = (const unsigned char*)&guid_copy;
- char *dst = str->ptr;
-
- pj_memcpy(&guid_copy, guid, sizeof(*guid));
- guid_copy.Data1 = pj_ntohl(guid_copy.Data1);
- guid_copy.Data2 = pj_ntohs(guid_copy.Data2);
- guid_copy.Data3 = pj_ntohs(guid_copy.Data3);
-
- for (i=0; i<16; ++i) {
- hex2digit( *src, dst );
- dst += 2;
- ++src;
- }
- str->slen = 32;
-}
-
-
-PJ_DEF(pj_str_t*) pj_generate_unique_string(pj_str_t *str)
-{
- GUID guid;
-
- PJ_CHECK_STACK();
-
- CoCreateGuid(&guid);
- guid_to_str( &guid, str );
- return str;
-}
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/guid.h>
+#include <pj/string.h>
+#include <pj/sock.h>
+#include <windows.h>
+#include <objbase.h>
+#include <pj/os.h>
+
+
+const unsigned PJ_GUID_STRING_LENGTH=32;
+
+PJ_INLINE(void) hex2digit(unsigned value, char *p)
+{
+ static char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+ *p++ = hex[ (value & 0xF0) >> 4 ];
+ *p++ = hex[ (value & 0x0F) ];
+}
+
+static void guid_to_str( const GUID *guid, pj_str_t *str )
+{
+ unsigned i;
+ GUID guid_copy;
+ const unsigned char *src = (const unsigned char*)&guid_copy;
+ char *dst = str->ptr;
+
+ pj_memcpy(&guid_copy, guid, sizeof(*guid));
+ guid_copy.Data1 = pj_ntohl(guid_copy.Data1);
+ guid_copy.Data2 = pj_ntohs(guid_copy.Data2);
+ guid_copy.Data3 = pj_ntohs(guid_copy.Data3);
+
+ for (i=0; i<16; ++i) {
+ hex2digit( *src, dst );
+ dst += 2;
+ ++src;
+ }
+ str->slen = 32;
+}
+
+
+PJ_DEF(pj_str_t*) pj_generate_unique_string(pj_str_t *str)
+{
+ GUID guid;
+
+ PJ_CHECK_STACK();
+
+ CoCreateGuid(&guid);
+ guid_to_str( &guid, str );
+ return str;
+}
+
diff --git a/pjlib/src/pj/hash.c b/pjlib/src/pj/hash.c
index 195c8817..499032cb 100644
--- a/pjlib/src/pj/hash.c
+++ b/pjlib/src/pj/hash.c
@@ -1,55 +1,77 @@
-/* $Id$
- */
-#include <pj/hash.h>
-#include <pj/log.h>
-#include <pj/string.h>
-#include <pj/pool.h>
-#include <pj/os.h>
-
-/**
- * The hash multiplier used to calculate hash value.
- */
-#define PJ_HASH_MULTIPLIER 33
-
-
-struct pj_hash_entry
-{
- struct pj_hash_entry *next;
- const void *key;
- pj_uint32_t hash;
- pj_uint32_t keylen;
- void *value;
-};
-
-
-struct pj_hash_table_t
-{
- pj_hash_entry **table;
- unsigned count, rows;
- pj_hash_iterator_t iterator;
-};
-
-
-
-PJ_DEF(pj_uint32_t) pj_hash_calc(pj_uint32_t hash, const void *key, unsigned keylen)
-{
- PJ_CHECK_STACK();
-
- if (keylen==PJ_HASH_KEY_STRING) {
- const unsigned char *p = key;
- for ( ; *p; ++p ) {
- hash = hash * PJ_HASH_MULTIPLIER + *p;
- }
- keylen = p - (const unsigned char*)key;
- } else {
- const unsigned char *p = key,
- *end = p + keylen;
- for ( ; p!=end; ++p) {
- hash = hash * PJ_HASH_MULTIPLIER + *p;
- }
- }
- return hash;
-}
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/hash.h>
+#include <pj/log.h>
+#include <pj/string.h>
+#include <pj/pool.h>
+#include <pj/os.h>
+#include <pj/ctype.h>
+
+/**
+ * The hash multiplier used to calculate hash value.
+ */
+#define PJ_HASH_MULTIPLIER 33
+
+
+struct pj_hash_entry
+{
+ struct pj_hash_entry *next;
+ const void *key;
+ pj_uint32_t hash;
+ pj_uint32_t keylen;
+ void *value;
+};
+
+
+struct pj_hash_table_t
+{
+ pj_hash_entry **table;
+ unsigned count, rows;
+ pj_hash_iterator_t iterator;
+};
+
+
+
+PJ_DEF(pj_uint32_t) pj_hash_calc(pj_uint32_t hash, const void *key, unsigned keylen)
+{
+ PJ_CHECK_STACK();
+
+ if (keylen==PJ_HASH_KEY_STRING) {
+ const unsigned char *p = key;
+ for ( ; *p; ++p ) {
+ hash = hash * PJ_HASH_MULTIPLIER + *p;
+ }
+ keylen = p - (const unsigned char*)key;
+ } else {
+ const unsigned char *p = key,
+ *end = p + keylen;
+ for ( ; p!=end; ++p) {
+ hash = hash * PJ_HASH_MULTIPLIER + *p;
+ }
+ }
+ return hash;
+}
PJ_DEF(pj_uint32_t) pj_hash_calc_tolower( pj_uint32_t hval,
char *result,
@@ -64,194 +86,194 @@ PJ_DEF(pj_uint32_t) pj_hash_calc_tolower( pj_uint32_t hval,
return hval;
}
-
-
-PJ_DEF(pj_hash_table_t*) pj_hash_create(pj_pool_t *pool, unsigned size)
-{
- pj_hash_table_t *h;
- unsigned table_size;
-
- h = pj_pool_alloc(pool, sizeof(pj_hash_table_t));
- h->count = 0;
-
- PJ_LOG( 5, ("hashtbl", "hash table %p created from pool %s", h, pj_pool_getobjname(pool)));
-
- /* size must be 2^n - 1.
- round-up the size to this rule, except when size is 2^n, then size
- will be round-down to 2^n-1.
- */
- table_size = 8;
- do {
- table_size <<= 1;
- } while (table_size <= size);
- table_size -= 1;
-
- h->rows = table_size;
- h->table = pj_pool_calloc(pool, table_size+1, sizeof(pj_hash_entry*));
- return h;
-}
-
-static pj_hash_entry **find_entry( pj_pool_t *pool, pj_hash_table_t *ht,
- const void *key, unsigned keylen,
- void *val)
-{
- pj_uint32_t hash;
- pj_hash_entry **p_entry, *entry;
-
- hash=0;
- if (keylen==PJ_HASH_KEY_STRING) {
- const unsigned char *p = key;
- for ( ; *p; ++p ) {
- hash = hash * PJ_HASH_MULTIPLIER + *p;
- }
- keylen = p - (const unsigned char*)key;
- } else {
- const unsigned char *p = key,
- *end = p + keylen;
- for ( ; p!=end; ++p) {
- hash = hash * PJ_HASH_MULTIPLIER + *p;
- }
- }
-
- /* scan the linked list */
- for (p_entry = &ht->table[hash & ht->rows], entry=*p_entry;
- entry;
- p_entry = &entry->next, entry = *p_entry)
- {
- if (entry->hash==hash && entry->keylen==keylen &&
- memcmp(entry->key, key, keylen)==0)
- {
- break;
- }
- }
-
- if (entry || val==NULL)
- return p_entry;
-
- /* create a new entry */
- entry = pj_pool_alloc(pool, sizeof(pj_hash_entry));
- PJ_LOG(5, ("hashtbl", "%p: New p_entry %p created, pool used=%u, cap=%u", ht, entry,
- pj_pool_get_used_size(pool), pj_pool_get_capacity(pool)));
- entry->next = NULL;
- entry->hash = hash;
- entry->key = key;
- entry->keylen = keylen;
- entry->value = val;
- *p_entry = entry;
-
- ++ht->count;
-
- return p_entry;
-}
-
-PJ_DEF(void *) pj_hash_get( pj_hash_table_t *ht,
- const void *key, unsigned keylen )
-{
- pj_hash_entry *entry;
- entry = *find_entry( NULL, ht, key, keylen, NULL);
- return entry ? entry->value : NULL;
-}
-
-PJ_DEF(void) pj_hash_set( pj_pool_t *pool, pj_hash_table_t *ht,
- const void *key, unsigned keylen,
- void *value )
-{
- pj_hash_entry **p_entry;
-
- p_entry = find_entry( pool, ht, key, keylen, value );
- if (*p_entry) {
- if (value == NULL) {
- /* delete entry */
- PJ_LOG(5, ("hashtbl", "%p: p_entry %p deleted", ht, *p_entry));
- *p_entry = (*p_entry)->next;
- --ht->count;
-
- } else {
- /* overwrite */
- (*p_entry)->value = value;
- PJ_LOG(5, ("hashtbl", "%p: p_entry %p value set to %p", ht, *p_entry, value));
- }
- }
-}
-
-PJ_DEF(unsigned) pj_hash_count( pj_hash_table_t *ht )
-{
- return ht->count;
-}
-
-PJ_DEF(pj_hash_iterator_t*) pj_hash_first( pj_hash_table_t *ht,
- pj_hash_iterator_t *it )
-{
- it->index = 0;
- it->entry = NULL;
-
- for (; it->index < ht->rows; ++it->index) {
- it->entry = ht->table[it->index];
- if (it->entry) {
- break;
- }
- }
-
- return it->entry ? it : NULL;
-}
-
-PJ_DEF(pj_hash_iterator_t*) pj_hash_next( pj_hash_table_t *ht,
- pj_hash_iterator_t *it )
-{
- it->entry = it->entry->next;
- if (it->entry) {
- return it;
- }
-
- for (++it->index; it->index < ht->rows; ++it->index) {
- it->entry = ht->table[it->index];
- if (it->entry) {
- break;
- }
- }
-
- return it->entry ? it : NULL;
-}
-
-PJ_DEF(void*) pj_hash_this( pj_hash_table_t *ht, pj_hash_iterator_t *it )
-{
- PJ_CHECK_STACK();
- PJ_UNUSED_ARG(ht);
- return it->entry->value;
-}
-
-#if 0
-void pj_hash_dump_collision( pj_hash_table_t *ht )
-{
- unsigned min=0xFFFFFFFF, max=0;
- unsigned i;
- char line[120];
- int len, totlen = 0;
-
- for (i=0; i<ht->rows; ++i) {
- unsigned count = 0;
- pj_hash_entry *entry = ht->table[i];
- while (entry) {
- ++count;
- entry = entry->next;
- }
- if (count < min)
- min = count;
- if (count > max)
- max = count;
- len = pj_snprintf( line+totlen, sizeof(line)-totlen, "%3d:%3d ", i, count);
- if (len < 1)
- break;
- totlen += len;
-
- if ((i+1) % 10 == 0) {
- line[totlen] = '\0';
- PJ_LOG(4,(__FILE__, line));
- }
- }
-
- PJ_LOG(4,(__FILE__,"Count: %d, min: %d, max: %d\n", ht->count, min, max));
-}
-#endif
-
-
+
+
+PJ_DEF(pj_hash_table_t*) pj_hash_create(pj_pool_t *pool, unsigned size)
+{
+ pj_hash_table_t *h;
+ unsigned table_size;
+
+ h = pj_pool_alloc(pool, sizeof(pj_hash_table_t));
+ h->count = 0;
+
+ PJ_LOG( 5, ("hashtbl", "hash table %p created from pool %s", h, pj_pool_getobjname(pool)));
+
+ /* size must be 2^n - 1.
+ round-up the size to this rule, except when size is 2^n, then size
+ will be round-down to 2^n-1.
+ */
+ table_size = 8;
+ do {
+ table_size <<= 1;
+ } while (table_size <= size);
+ table_size -= 1;
+
+ h->rows = table_size;
+ h->table = pj_pool_calloc(pool, table_size+1, sizeof(pj_hash_entry*));
+ return h;
+}
+
+static pj_hash_entry **find_entry( pj_pool_t *pool, pj_hash_table_t *ht,
+ const void *key, unsigned keylen,
+ void *val)
+{
+ pj_uint32_t hash;
+ pj_hash_entry **p_entry, *entry;
+
+ hash=0;
+ if (keylen==PJ_HASH_KEY_STRING) {
+ const unsigned char *p = key;
+ for ( ; *p; ++p ) {
+ hash = hash * PJ_HASH_MULTIPLIER + *p;
+ }
+ keylen = p - (const unsigned char*)key;
+ } else {
+ const unsigned char *p = key,
+ *end = p + keylen;
+ for ( ; p!=end; ++p) {
+ hash = hash * PJ_HASH_MULTIPLIER + *p;
+ }
+ }
+
+ /* scan the linked list */
+ for (p_entry = &ht->table[hash & ht->rows], entry=*p_entry;
+ entry;
+ p_entry = &entry->next, entry = *p_entry)
+ {
+ if (entry->hash==hash && entry->keylen==keylen &&
+ memcmp(entry->key, key, keylen)==0)
+ {
+ break;
+ }
+ }
+
+ if (entry || val==NULL)
+ return p_entry;
+
+ /* create a new entry */
+ entry = pj_pool_alloc(pool, sizeof(pj_hash_entry));
+ PJ_LOG(5, ("hashtbl", "%p: New p_entry %p created, pool used=%u, cap=%u", ht, entry,
+ pj_pool_get_used_size(pool), pj_pool_get_capacity(pool)));
+ entry->next = NULL;
+ entry->hash = hash;
+ entry->key = key;
+ entry->keylen = keylen;
+ entry->value = val;
+ *p_entry = entry;
+
+ ++ht->count;
+
+ return p_entry;
+}
+
+PJ_DEF(void *) pj_hash_get( pj_hash_table_t *ht,
+ const void *key, unsigned keylen )
+{
+ pj_hash_entry *entry;
+ entry = *find_entry( NULL, ht, key, keylen, NULL);
+ return entry ? entry->value : NULL;
+}
+
+PJ_DEF(void) pj_hash_set( pj_pool_t *pool, pj_hash_table_t *ht,
+ const void *key, unsigned keylen,
+ void *value )
+{
+ pj_hash_entry **p_entry;
+
+ p_entry = find_entry( pool, ht, key, keylen, value );
+ if (*p_entry) {
+ if (value == NULL) {
+ /* delete entry */
+ PJ_LOG(5, ("hashtbl", "%p: p_entry %p deleted", ht, *p_entry));
+ *p_entry = (*p_entry)->next;
+ --ht->count;
+
+ } else {
+ /* overwrite */
+ (*p_entry)->value = value;
+ PJ_LOG(5, ("hashtbl", "%p: p_entry %p value set to %p", ht, *p_entry, value));
+ }
+ }
+}
+
+PJ_DEF(unsigned) pj_hash_count( pj_hash_table_t *ht )
+{
+ return ht->count;
+}
+
+PJ_DEF(pj_hash_iterator_t*) pj_hash_first( pj_hash_table_t *ht,
+ pj_hash_iterator_t *it )
+{
+ it->index = 0;
+ it->entry = NULL;
+
+ for (; it->index < ht->rows; ++it->index) {
+ it->entry = ht->table[it->index];
+ if (it->entry) {
+ break;
+ }
+ }
+
+ return it->entry ? it : NULL;
+}
+
+PJ_DEF(pj_hash_iterator_t*) pj_hash_next( pj_hash_table_t *ht,
+ pj_hash_iterator_t *it )
+{
+ it->entry = it->entry->next;
+ if (it->entry) {
+ return it;
+ }
+
+ for (++it->index; it->index < ht->rows; ++it->index) {
+ it->entry = ht->table[it->index];
+ if (it->entry) {
+ break;
+ }
+ }
+
+ return it->entry ? it : NULL;
+}
+
+PJ_DEF(void*) pj_hash_this( pj_hash_table_t *ht, pj_hash_iterator_t *it )
+{
+ PJ_CHECK_STACK();
+ PJ_UNUSED_ARG(ht);
+ return it->entry->value;
+}
+
+#if 0
+void pj_hash_dump_collision( pj_hash_table_t *ht )
+{
+ unsigned min=0xFFFFFFFF, max=0;
+ unsigned i;
+ char line[120];
+ int len, totlen = 0;
+
+ for (i=0; i<ht->rows; ++i) {
+ unsigned count = 0;
+ pj_hash_entry *entry = ht->table[i];
+ while (entry) {
+ ++count;
+ entry = entry->next;
+ }
+ if (count < min)
+ min = count;
+ if (count > max)
+ max = count;
+ len = pj_snprintf( line+totlen, sizeof(line)-totlen, "%3d:%3d ", i, count);
+ if (len < 1)
+ break;
+ totlen += len;
+
+ if ((i+1) % 10 == 0) {
+ line[totlen] = '\0';
+ PJ_LOG(4,(__FILE__, line));
+ }
+ }
+
+ PJ_LOG(4,(__FILE__,"Count: %d, min: %d, max: %d\n", ht->count, min, max));
+}
+#endif
+
+
diff --git a/pjlib/src/pj/ioqueue_common_abs.c b/pjlib/src/pj/ioqueue_common_abs.c
index c2e11211..ed71772e 100644
--- a/pjlib/src/pj/ioqueue_common_abs.c
+++ b/pjlib/src/pj/ioqueue_common_abs.c
@@ -1,837 +1,858 @@
-/* $Id$ */
-
-/*
- * ioqueue_common_abs.c
- *
- * This contains common functionalities to emulate proactor pattern with
- * various event dispatching mechanisms (e.g. select, epoll).
- *
- * This file will be included by the appropriate ioqueue implementation.
- * This file is NOT supposed to be compiled as stand-alone source.
- */
-
-static void ioqueue_init( pj_ioqueue_t *ioqueue )
-{
- ioqueue->lock = NULL;
- ioqueue->auto_delete_lock = 0;
-}
-
-static pj_status_t ioqueue_destroy(pj_ioqueue_t *ioqueue)
-{
- if (ioqueue->auto_delete_lock && ioqueue->lock ) {
- pj_lock_release(ioqueue->lock);
- return pj_lock_destroy(ioqueue->lock);
- } else
- return PJ_SUCCESS;
-}
-
-/*
- * pj_ioqueue_set_lock()
- */
-PJ_DEF(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioqueue,
- pj_lock_t *lock,
- pj_bool_t auto_delete )
-{
- PJ_ASSERT_RETURN(ioqueue && lock, PJ_EINVAL);
-
- if (ioqueue->auto_delete_lock && ioqueue->lock) {
- pj_lock_destroy(ioqueue->lock);
- }
-
- ioqueue->lock = lock;
- ioqueue->auto_delete_lock = auto_delete;
-
- return PJ_SUCCESS;
-}
-
-static pj_status_t ioqueue_init_key( pj_pool_t *pool,
- pj_ioqueue_t *ioqueue,
- pj_ioqueue_key_t *key,
- pj_sock_t sock,
- void *user_data,
- const pj_ioqueue_callback *cb)
-{
- pj_status_t rc;
- int optlen;
-
- key->ioqueue = ioqueue;
- key->fd = sock;
- key->user_data = user_data;
- pj_list_init(&key->read_list);
- pj_list_init(&key->write_list);
-#if PJ_HAS_TCP
- pj_list_init(&key->accept_list);
-#endif
-
- /* Save callback. */
- pj_memcpy(&key->cb, cb, sizeof(pj_ioqueue_callback));
-
- /* Get socket type. When socket type is datagram, some optimization
- * will be performed during send to allow parallel send operations.
- */
- optlen = sizeof(key->fd_type);
- rc = pj_sock_getsockopt(sock, PJ_SOL_SOCKET, PJ_SO_TYPE,
- &key->fd_type, &optlen);
- if (rc != PJ_SUCCESS)
- key->fd_type = PJ_SOCK_STREAM;
-
- /* Create mutex for the key. */
- rc = pj_mutex_create_simple(pool, NULL, &key->mutex);
-
- return rc;
-}
-
-static void ioqueue_destroy_key( pj_ioqueue_key_t *key )
-{
- pj_mutex_destroy(key->mutex);
-}
-
-/*
- * pj_ioqueue_get_user_data()
- *
- * Obtain value associated with a key.
- */
-PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key )
-{
- PJ_ASSERT_RETURN(key != NULL, NULL);
- return key->user_data;
-}
-
-/*
- * pj_ioqueue_set_user_data()
- */
-PJ_DEF(pj_status_t) pj_ioqueue_set_user_data( pj_ioqueue_key_t *key,
- void *user_data,
- void **old_data)
-{
- PJ_ASSERT_RETURN(key, PJ_EINVAL);
-
- if (old_data)
- *old_data = key->user_data;
- key->user_data = user_data;
-
- return PJ_SUCCESS;
-}
-
-PJ_INLINE(int) key_has_pending_write(pj_ioqueue_key_t *key)
-{
- return !pj_list_empty(&key->write_list);
-}
-
-PJ_INLINE(int) key_has_pending_read(pj_ioqueue_key_t *key)
-{
- return !pj_list_empty(&key->read_list);
-}
-
-PJ_INLINE(int) key_has_pending_accept(pj_ioqueue_key_t *key)
-{
-#if PJ_HAS_TCP
- return !pj_list_empty(&key->accept_list);
-#else
- return 0;
-#endif
-}
-
-PJ_INLINE(int) key_has_pending_connect(pj_ioqueue_key_t *key)
-{
- return key->connecting;
-}
-
-
-/*
- * ioqueue_dispatch_event()
- *
- * Report occurence of an event in the key to be processed by the
- * framework.
- */
-void ioqueue_dispatch_write_event(pj_ioqueue_t *ioqueue, pj_ioqueue_key_t *h)
-{
- /* Lock the key. */
- pj_mutex_lock(h->mutex);
-
-#if defined(PJ_HAS_TCP) && PJ_HAS_TCP!=0
- if (h->connecting) {
- /* Completion of connect() operation */
- pj_ssize_t bytes_transfered;
-
- /* Clear operation. */
- h->connecting = 0;
-
- ioqueue_remove_from_set(ioqueue, h->fd, WRITEABLE_EVENT);
- ioqueue_remove_from_set(ioqueue, h->fd, EXCEPTION_EVENT);
-
- /* Unlock; from this point we don't need to hold key's mutex. */
- pj_mutex_unlock(h->mutex);
-
-#if (defined(PJ_HAS_SO_ERROR) && PJ_HAS_SO_ERROR!=0)
- /* from connect(2):
- * On Linux, use getsockopt to read the SO_ERROR option at
- * level SOL_SOCKET to determine whether connect() completed
- * successfully (if SO_ERROR is zero).
- */
- {
- int value;
- socklen_t vallen = sizeof(value);
- int gs_rc = getsockopt(h->fd, SOL_SOCKET, SO_ERROR,
- &value, &vallen);
- if (gs_rc != 0) {
- /* Argh!! What to do now???
- * Just indicate that the socket is connected. The
- * application will get error as soon as it tries to use
- * the socket to send/receive.
- */
- bytes_transfered = 0;
- } else {
- bytes_transfered = value;
- }
- }
-#elif defined(PJ_WIN32) && PJ_WIN32!=0
- bytes_transfered = 0; /* success */
-#else
- /* Excellent information in D.J. Bernstein page:
- * http://cr.yp.to/docs/connect.html
- *
- * Seems like the most portable way of detecting connect()
- * failure is to call getpeername(). If socket is connected,
- * getpeername() will return 0. If the socket is not connected,
- * it will return ENOTCONN, and read(fd, &ch, 1) will produce
- * the right errno through error slippage. This is a combination
- * of suggestions from Douglas C. Schmidt and Ken Keys.
- */
- int gp_rc;
- struct sockaddr_in addr;
- socklen_t addrlen = sizeof(addr);
-
- gp_rc = getpeername(h->fd, (struct sockaddr*)&addr, &addrlen);
- bytes_transfered = gp_rc;
-#endif
-
- /* Call callback. */
- if (h->cb.on_connect_complete)
- (*h->cb.on_connect_complete)(h, bytes_transfered);
-
- /* Done. */
-
- } else
-#endif /* PJ_HAS_TCP */
- if (key_has_pending_write(h)) {
- /* Socket is writable. */
- struct write_operation *write_op;
- pj_ssize_t sent;
- pj_status_t send_rc;
-
- /* Get the first in the queue. */
- write_op = h->write_list.next;
-
- /* For datagrams, we can remove the write_op from the list
- * so that send() can work in parallel.
- */
- if (h->fd_type == PJ_SOCK_DGRAM) {
+/* $Id$ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * ioqueue_common_abs.c
+ *
+ * This contains common functionalities to emulate proactor pattern with
+ * various event dispatching mechanisms (e.g. select, epoll).
+ *
+ * This file will be included by the appropriate ioqueue implementation.
+ * This file is NOT supposed to be compiled as stand-alone source.
+ */
+
+static void ioqueue_init( pj_ioqueue_t *ioqueue )
+{
+ ioqueue->lock = NULL;
+ ioqueue->auto_delete_lock = 0;
+}
+
+static pj_status_t ioqueue_destroy(pj_ioqueue_t *ioqueue)
+{
+ if (ioqueue->auto_delete_lock && ioqueue->lock ) {
+ pj_lock_release(ioqueue->lock);
+ return pj_lock_destroy(ioqueue->lock);
+ } else
+ return PJ_SUCCESS;
+}
+
+/*
+ * pj_ioqueue_set_lock()
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioqueue,
+ pj_lock_t *lock,
+ pj_bool_t auto_delete )
+{
+ PJ_ASSERT_RETURN(ioqueue && lock, PJ_EINVAL);
+
+ if (ioqueue->auto_delete_lock && ioqueue->lock) {
+ pj_lock_destroy(ioqueue->lock);
+ }
+
+ ioqueue->lock = lock;
+ ioqueue->auto_delete_lock = auto_delete;
+
+ return PJ_SUCCESS;
+}
+
+static pj_status_t ioqueue_init_key( pj_pool_t *pool,
+ pj_ioqueue_t *ioqueue,
+ pj_ioqueue_key_t *key,
+ pj_sock_t sock,
+ void *user_data,
+ const pj_ioqueue_callback *cb)
+{
+ pj_status_t rc;
+ int optlen;
+
+ key->ioqueue = ioqueue;
+ key->fd = sock;
+ key->user_data = user_data;
+ pj_list_init(&key->read_list);
+ pj_list_init(&key->write_list);
+#if PJ_HAS_TCP
+ pj_list_init(&key->accept_list);
+#endif
+
+ /* Save callback. */
+ pj_memcpy(&key->cb, cb, sizeof(pj_ioqueue_callback));
+
+ /* Get socket type. When socket type is datagram, some optimization
+ * will be performed during send to allow parallel send operations.
+ */
+ optlen = sizeof(key->fd_type);
+ rc = pj_sock_getsockopt(sock, PJ_SOL_SOCKET, PJ_SO_TYPE,
+ &key->fd_type, &optlen);
+ if (rc != PJ_SUCCESS)
+ key->fd_type = PJ_SOCK_STREAM;
+
+ /* Create mutex for the key. */
+ rc = pj_mutex_create_simple(pool, NULL, &key->mutex);
+
+ return rc;
+}
+
+static void ioqueue_destroy_key( pj_ioqueue_key_t *key )
+{
+ pj_mutex_destroy(key->mutex);
+}
+
+/*
+ * pj_ioqueue_get_user_data()
+ *
+ * Obtain value associated with a key.
+ */
+PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key )
+{
+ PJ_ASSERT_RETURN(key != NULL, NULL);
+ return key->user_data;
+}
+
+/*
+ * pj_ioqueue_set_user_data()
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_set_user_data( pj_ioqueue_key_t *key,
+ void *user_data,
+ void **old_data)
+{
+ PJ_ASSERT_RETURN(key, PJ_EINVAL);
+
+ if (old_data)
+ *old_data = key->user_data;
+ key->user_data = user_data;
+
+ return PJ_SUCCESS;
+}
+
+PJ_INLINE(int) key_has_pending_write(pj_ioqueue_key_t *key)
+{
+ return !pj_list_empty(&key->write_list);
+}
+
+PJ_INLINE(int) key_has_pending_read(pj_ioqueue_key_t *key)
+{
+ return !pj_list_empty(&key->read_list);
+}
+
+PJ_INLINE(int) key_has_pending_accept(pj_ioqueue_key_t *key)
+{
+#if PJ_HAS_TCP
+ return !pj_list_empty(&key->accept_list);
+#else
+ return 0;
+#endif
+}
+
+PJ_INLINE(int) key_has_pending_connect(pj_ioqueue_key_t *key)
+{
+ return key->connecting;
+}
+
+
+/*
+ * ioqueue_dispatch_event()
+ *
+ * Report occurence of an event in the key to be processed by the
+ * framework.
+ */
+void ioqueue_dispatch_write_event(pj_ioqueue_t *ioqueue, pj_ioqueue_key_t *h)
+{
+ /* Lock the key. */
+ pj_mutex_lock(h->mutex);
+
+#if defined(PJ_HAS_TCP) && PJ_HAS_TCP!=0
+ if (h->connecting) {
+ /* Completion of connect() operation */
+ pj_ssize_t bytes_transfered;
+
+ /* Clear operation. */
+ h->connecting = 0;
+
+ ioqueue_remove_from_set(ioqueue, h->fd, WRITEABLE_EVENT);
+ ioqueue_remove_from_set(ioqueue, h->fd, EXCEPTION_EVENT);
+
+ /* Unlock; from this point we don't need to hold key's mutex. */
+ pj_mutex_unlock(h->mutex);
+
+#if (defined(PJ_HAS_SO_ERROR) && PJ_HAS_SO_ERROR!=0)
+ /* from connect(2):
+ * On Linux, use getsockopt to read the SO_ERROR option at
+ * level SOL_SOCKET to determine whether connect() completed
+ * successfully (if SO_ERROR is zero).
+ */
+ {
+ int value;
+ socklen_t vallen = sizeof(value);
+ int gs_rc = getsockopt(h->fd, SOL_SOCKET, SO_ERROR,
+ &value, &vallen);
+ if (gs_rc != 0) {
+ /* Argh!! What to do now???
+ * Just indicate that the socket is connected. The
+ * application will get error as soon as it tries to use
+ * the socket to send/receive.
+ */
+ bytes_transfered = 0;
+ } else {
+ bytes_transfered = value;
+ }
+ }
+#elif defined(PJ_WIN32) && PJ_WIN32!=0
+ bytes_transfered = 0; /* success */
+#else
+ /* Excellent information in D.J. Bernstein page:
+ * http://cr.yp.to/docs/connect.html
+ *
+ * Seems like the most portable way of detecting connect()
+ * failure is to call getpeername(). If socket is connected,
+ * getpeername() will return 0. If the socket is not connected,
+ * it will return ENOTCONN, and read(fd, &ch, 1) will produce
+ * the right errno through error slippage. This is a combination
+ * of suggestions from Douglas C. Schmidt and Ken Keys.
+ */
+ int gp_rc;
+ struct sockaddr_in addr;
+ socklen_t addrlen = sizeof(addr);
+
+ gp_rc = getpeername(h->fd, (struct sockaddr*)&addr, &addrlen);
+ bytes_transfered = gp_rc;
+#endif
+
+ /* Call callback. */
+ if (h->cb.on_connect_complete)
+ (*h->cb.on_connect_complete)(h, bytes_transfered);
+
+ /* Done. */
+
+ } else
+#endif /* PJ_HAS_TCP */
+ if (key_has_pending_write(h)) {
+ /* Socket is writable. */
+ struct write_operation *write_op;
+ pj_ssize_t sent;
+ pj_status_t send_rc;
+
+ /* Get the first in the queue. */
+ write_op = h->write_list.next;
+
+ /* For datagrams, we can remove the write_op from the list
+ * so that send() can work in parallel.
+ */
+ if (h->fd_type == PJ_SOCK_DGRAM) {
pj_list_erase(write_op);
write_op->op = 0;
-
- if (pj_list_empty(&h->write_list))
- ioqueue_remove_from_set(ioqueue, h->fd, WRITEABLE_EVENT);
-
- pj_mutex_unlock(h->mutex);
- }
-
- /* Send the data.
- * Unfortunately we must do this while holding key's mutex, thus
- * preventing parallel write on a single key.. :-((
- */
- sent = write_op->size - write_op->written;
- if (write_op->op == PJ_IOQUEUE_OP_SEND) {
- send_rc = pj_sock_send(h->fd, write_op->buf+write_op->written,
- &sent, write_op->flags);
- } else if (write_op->op == PJ_IOQUEUE_OP_SEND_TO) {
- send_rc = pj_sock_sendto(h->fd,
- write_op->buf+write_op->written,
- &sent, write_op->flags,
- &write_op->rmt_addr,
- write_op->rmt_addrlen);
- } else {
- pj_assert(!"Invalid operation type!");
- send_rc = PJ_EBUG;
- }
-
- if (send_rc == PJ_SUCCESS) {
- write_op->written += sent;
- } else {
- pj_assert(send_rc > 0);
- write_op->written = -send_rc;
- }
-
- /* Are we finished with this buffer? */
- if (send_rc!=PJ_SUCCESS ||
- write_op->written == (pj_ssize_t)write_op->size ||
- h->fd_type == PJ_SOCK_DGRAM)
- {
- if (h->fd_type != PJ_SOCK_DGRAM) {
- /* Write completion of the whole stream. */
+
+ if (pj_list_empty(&h->write_list))
+ ioqueue_remove_from_set(ioqueue, h->fd, WRITEABLE_EVENT);
+
+ pj_mutex_unlock(h->mutex);
+ }
+
+ /* Send the data.
+ * Unfortunately we must do this while holding key's mutex, thus
+ * preventing parallel write on a single key.. :-((
+ */
+ sent = write_op->size - write_op->written;
+ if (write_op->op == PJ_IOQUEUE_OP_SEND) {
+ send_rc = pj_sock_send(h->fd, write_op->buf+write_op->written,
+ &sent, write_op->flags);
+ } else if (write_op->op == PJ_IOQUEUE_OP_SEND_TO) {
+ send_rc = pj_sock_sendto(h->fd,
+ write_op->buf+write_op->written,
+ &sent, write_op->flags,
+ &write_op->rmt_addr,
+ write_op->rmt_addrlen);
+ } else {
+ pj_assert(!"Invalid operation type!");
+ send_rc = PJ_EBUG;
+ }
+
+ if (send_rc == PJ_SUCCESS) {
+ write_op->written += sent;
+ } else {
+ pj_assert(send_rc > 0);
+ write_op->written = -send_rc;
+ }
+
+ /* Are we finished with this buffer? */
+ if (send_rc!=PJ_SUCCESS ||
+ write_op->written == (pj_ssize_t)write_op->size ||
+ h->fd_type == PJ_SOCK_DGRAM)
+ {
+ if (h->fd_type != PJ_SOCK_DGRAM) {
+ /* Write completion of the whole stream. */
pj_list_erase(write_op);
- write_op->op = 0;
-
- /* Clear operation if there's no more data to send. */
- if (pj_list_empty(&h->write_list))
- ioqueue_remove_from_set(ioqueue, h->fd, WRITEABLE_EVENT);
-
- /* No need to hold mutex anymore */
- pj_mutex_unlock(h->mutex);
- }
-
- /* Call callback. */
- if (h->cb.on_write_complete) {
- (*h->cb.on_write_complete)(h,
- (pj_ioqueue_op_key_t*)write_op,
- write_op->written);
- }
-
- } else {
- pj_mutex_unlock(h->mutex);
- }
-
- /* Done. */
- } else {
- /*
+ write_op->op = 0;
+
+ /* Clear operation if there's no more data to send. */
+ if (pj_list_empty(&h->write_list))
+ ioqueue_remove_from_set(ioqueue, h->fd, WRITEABLE_EVENT);
+
+ /* No need to hold mutex anymore */
+ pj_mutex_unlock(h->mutex);
+ }
+
+ /* Call callback. */
+ if (h->cb.on_write_complete) {
+ (*h->cb.on_write_complete)(h,
+ (pj_ioqueue_op_key_t*)write_op,
+ write_op->written);
+ }
+
+ } else {
+ pj_mutex_unlock(h->mutex);
+ }
+
+ /* Done. */
+ } else {
+ /*
* This is normal; execution may fall here when multiple threads
* are signalled for the same event, but only one thread eventually
* able to process the event.
- */
- pj_mutex_unlock(h->mutex);
- }
-}
-
-void ioqueue_dispatch_read_event( pj_ioqueue_t *ioqueue, pj_ioqueue_key_t *h )
-{
- pj_status_t rc;
-
- /* Lock the key. */
- pj_mutex_lock(h->mutex);
-
-# if PJ_HAS_TCP
- if (!pj_list_empty(&h->accept_list)) {
-
- struct accept_operation *accept_op;
-
- /* Get one accept operation from the list. */
- accept_op = h->accept_list.next;
+ */
+ pj_mutex_unlock(h->mutex);
+ }
+}
+
+void ioqueue_dispatch_read_event( pj_ioqueue_t *ioqueue, pj_ioqueue_key_t *h )
+{
+ pj_status_t rc;
+
+ /* Lock the key. */
+ pj_mutex_lock(h->mutex);
+
+# if PJ_HAS_TCP
+ if (!pj_list_empty(&h->accept_list)) {
+
+ struct accept_operation *accept_op;
+
+ /* Get one accept operation from the list. */
+ accept_op = h->accept_list.next;
pj_list_erase(accept_op);
- accept_op->op = 0;
-
- /* Clear bit in fdset if there is no more pending accept */
- if (pj_list_empty(&h->accept_list))
- ioqueue_remove_from_set(ioqueue, h->fd, READABLE_EVENT);
-
- /* Unlock; from this point we don't need to hold key's mutex. */
- pj_mutex_unlock(h->mutex);
-
- rc=pj_sock_accept(h->fd, accept_op->accept_fd,
- accept_op->rmt_addr, accept_op->addrlen);
- if (rc==PJ_SUCCESS && accept_op->local_addr) {
- rc = pj_sock_getsockname(*accept_op->accept_fd,
- accept_op->local_addr,
- accept_op->addrlen);
- }
-
- /* Call callback. */
- if (h->cb.on_accept_complete) {
- (*h->cb.on_accept_complete)(h,
- (pj_ioqueue_op_key_t*)accept_op,
- *accept_op->accept_fd, rc);
- }
-
- }
- else
-# endif
- if (key_has_pending_read(h)) {
- struct read_operation *read_op;
- pj_ssize_t bytes_read;
-
- /* Get one pending read operation from the list. */
- read_op = h->read_list.next;
+ accept_op->op = 0;
+
+ /* Clear bit in fdset if there is no more pending accept */
+ if (pj_list_empty(&h->accept_list))
+ ioqueue_remove_from_set(ioqueue, h->fd, READABLE_EVENT);
+
+ /* Unlock; from this point we don't need to hold key's mutex. */
+ pj_mutex_unlock(h->mutex);
+
+ rc=pj_sock_accept(h->fd, accept_op->accept_fd,
+ accept_op->rmt_addr, accept_op->addrlen);
+ if (rc==PJ_SUCCESS && accept_op->local_addr) {
+ rc = pj_sock_getsockname(*accept_op->accept_fd,
+ accept_op->local_addr,
+ accept_op->addrlen);
+ }
+
+ /* Call callback. */
+ if (h->cb.on_accept_complete) {
+ (*h->cb.on_accept_complete)(h,
+ (pj_ioqueue_op_key_t*)accept_op,
+ *accept_op->accept_fd, rc);
+ }
+
+ }
+ else
+# endif
+ if (key_has_pending_read(h)) {
+ struct read_operation *read_op;
+ pj_ssize_t bytes_read;
+
+ /* Get one pending read operation from the list. */
+ read_op = h->read_list.next;
pj_list_erase(read_op);
- read_op->op = 0;
-
- /* Clear fdset if there is no pending read. */
- if (pj_list_empty(&h->read_list))
- ioqueue_remove_from_set(ioqueue, h->fd, READABLE_EVENT);
-
- /* Unlock; from this point we don't need to hold key's mutex. */
- pj_mutex_unlock(h->mutex);
-
- bytes_read = read_op->size;
-
- if ((read_op->op == PJ_IOQUEUE_OP_RECV_FROM)) {
- rc = pj_sock_recvfrom(h->fd, read_op->buf, &bytes_read, 0,
- read_op->rmt_addr,
- read_op->rmt_addrlen);
- } else if ((read_op->op == PJ_IOQUEUE_OP_RECV)) {
- rc = pj_sock_recv(h->fd, read_op->buf, &bytes_read, 0);
- } else {
- pj_assert(read_op->op == PJ_IOQUEUE_OP_READ);
- /*
- * User has specified pj_ioqueue_read().
- * On Win32, we should do ReadFile(). But because we got
- * here because of select() anyway, user must have put a
- * socket descriptor on h->fd, which in this case we can
- * just call pj_sock_recv() instead of ReadFile().
- * On Unix, user may put a file in h->fd, so we'll have
- * to call read() here.
- * This may not compile on systems which doesn't have
- * read(). That's why we only specify PJ_LINUX here so
- * that error is easier to catch.
- */
-# if defined(PJ_WIN32) && PJ_WIN32 != 0
- rc = pj_sock_recv(h->fd, read_op->buf, &bytes_read, 0);
- //rc = ReadFile((HANDLE)h->fd, read_op->buf, read_op->size,
- // &bytes_read, NULL);
-# elif (defined(PJ_HAS_UNISTD_H) && PJ_HAS_UNISTD_H != 0)
- bytes_read = read(h->fd, read_op->buf, bytes_read);
- rc = (bytes_read >= 0) ? PJ_SUCCESS : pj_get_os_error();
-# elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0
- bytes_read = sys_read(h->fd, read_op->buf, bytes_read);
- rc = (bytes_read >= 0) ? PJ_SUCCESS : -bytes_read;
-# else
-# error "Implement read() for this platform!"
-# endif
- }
-
- if (rc != PJ_SUCCESS) {
-# if defined(PJ_WIN32) && PJ_WIN32 != 0
- /* On Win32, for UDP, WSAECONNRESET on the receive side
- * indicates that previous sending has triggered ICMP Port
- * Unreachable message.
- * But we wouldn't know at this point which one of previous
- * key that has triggered the error, since UDP socket can
- * be shared!
- * So we'll just ignore it!
- */
-
- if (rc == PJ_STATUS_FROM_OS(WSAECONNRESET)) {
- //PJ_LOG(4,(THIS_FILE,
- // "Ignored ICMP port unreach. on key=%p", h));
- }
-# endif
-
- /* In any case we would report this to caller. */
- bytes_read = -rc;
- }
-
- /* Call callback. */
- if (h->cb.on_read_complete) {
- (*h->cb.on_read_complete)(h,
- (pj_ioqueue_op_key_t*)read_op,
- bytes_read);
- }
-
- } else {
+ read_op->op = 0;
+
+ /* Clear fdset if there is no pending read. */
+ if (pj_list_empty(&h->read_list))
+ ioqueue_remove_from_set(ioqueue, h->fd, READABLE_EVENT);
+
+ /* Unlock; from this point we don't need to hold key's mutex. */
+ pj_mutex_unlock(h->mutex);
+
+ bytes_read = read_op->size;
+
+ if ((read_op->op == PJ_IOQUEUE_OP_RECV_FROM)) {
+ rc = pj_sock_recvfrom(h->fd, read_op->buf, &bytes_read, 0,
+ read_op->rmt_addr,
+ read_op->rmt_addrlen);
+ } else if ((read_op->op == PJ_IOQUEUE_OP_RECV)) {
+ rc = pj_sock_recv(h->fd, read_op->buf, &bytes_read, 0);
+ } else {
+ pj_assert(read_op->op == PJ_IOQUEUE_OP_READ);
+ /*
+ * User has specified pj_ioqueue_read().
+ * On Win32, we should do ReadFile(). But because we got
+ * here because of select() anyway, user must have put a
+ * socket descriptor on h->fd, which in this case we can
+ * just call pj_sock_recv() instead of ReadFile().
+ * On Unix, user may put a file in h->fd, so we'll have
+ * to call read() here.
+ * This may not compile on systems which doesn't have
+ * read(). That's why we only specify PJ_LINUX here so
+ * that error is easier to catch.
+ */
+# if defined(PJ_WIN32) && PJ_WIN32 != 0
+ rc = pj_sock_recv(h->fd, read_op->buf, &bytes_read, 0);
+ //rc = ReadFile((HANDLE)h->fd, read_op->buf, read_op->size,
+ // &bytes_read, NULL);
+# elif (defined(PJ_HAS_UNISTD_H) && PJ_HAS_UNISTD_H != 0)
+ bytes_read = read(h->fd, read_op->buf, bytes_read);
+ rc = (bytes_read >= 0) ? PJ_SUCCESS : pj_get_os_error();
+# elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0
+ bytes_read = sys_read(h->fd, read_op->buf, bytes_read);
+ rc = (bytes_read >= 0) ? PJ_SUCCESS : -bytes_read;
+# else
+# error "Implement read() for this platform!"
+# endif
+ }
+
+ if (rc != PJ_SUCCESS) {
+# if defined(PJ_WIN32) && PJ_WIN32 != 0
+ /* On Win32, for UDP, WSAECONNRESET on the receive side
+ * indicates that previous sending has triggered ICMP Port
+ * Unreachable message.
+ * But we wouldn't know at this point which one of previous
+ * key that has triggered the error, since UDP socket can
+ * be shared!
+ * So we'll just ignore it!
+ */
+
+ if (rc == PJ_STATUS_FROM_OS(WSAECONNRESET)) {
+ //PJ_LOG(4,(THIS_FILE,
+ // "Ignored ICMP port unreach. on key=%p", h));
+ }
+# endif
+
+ /* In any case we would report this to caller. */
+ bytes_read = -rc;
+ }
+
+ /* Call callback. */
+ if (h->cb.on_read_complete) {
+ (*h->cb.on_read_complete)(h,
+ (pj_ioqueue_op_key_t*)read_op,
+ bytes_read);
+ }
+
+ } else {
/*
* This is normal; execution may fall here when multiple threads
* are signalled for the same event, but only one thread eventually
* able to process the event.
*/
- pj_mutex_unlock(h->mutex);
- }
-}
-
-
-void ioqueue_dispatch_exception_event( pj_ioqueue_t *ioqueue,
- pj_ioqueue_key_t *h )
-{
- pj_mutex_lock(h->mutex);
-
- if (!h->connecting) {
- /* It is possible that more than one thread was woken up, thus
- * the remaining thread will see h->connecting as zero because
- * it has been processed by other thread.
- */
- pj_mutex_unlock(h->mutex);
- return;
- }
-
- /* Clear operation. */
- h->connecting = 0;
-
- pj_mutex_unlock(h->mutex);
-
- ioqueue_remove_from_set(ioqueue, h->fd, WRITEABLE_EVENT);
- ioqueue_remove_from_set(ioqueue, h->fd, EXCEPTION_EVENT);
-
- /* Call callback. */
- if (h->cb.on_connect_complete)
- (*h->cb.on_connect_complete)(h, -1);
-}
-
-/*
- * pj_ioqueue_recv()
- *
- * Start asynchronous recv() from the socket.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_recv( pj_ioqueue_key_t *key,
- pj_ioqueue_op_key_t *op_key,
- void *buffer,
- pj_ssize_t *length,
- unsigned flags )
-{
- pj_status_t status;
- pj_ssize_t size;
- struct read_operation *read_op;
-
- PJ_ASSERT_RETURN(key && op_key && buffer && length, PJ_EINVAL);
- PJ_CHECK_STACK();
+ pj_mutex_unlock(h->mutex);
+ }
+}
+
+
+void ioqueue_dispatch_exception_event( pj_ioqueue_t *ioqueue,
+ pj_ioqueue_key_t *h )
+{
+ pj_mutex_lock(h->mutex);
+
+ if (!h->connecting) {
+ /* It is possible that more than one thread was woken up, thus
+ * the remaining thread will see h->connecting as zero because
+ * it has been processed by other thread.
+ */
+ pj_mutex_unlock(h->mutex);
+ return;
+ }
+
+ /* Clear operation. */
+ h->connecting = 0;
+
+ pj_mutex_unlock(h->mutex);
+
+ ioqueue_remove_from_set(ioqueue, h->fd, WRITEABLE_EVENT);
+ ioqueue_remove_from_set(ioqueue, h->fd, EXCEPTION_EVENT);
+
+ /* Call callback. */
+ if (h->cb.on_connect_complete)
+ (*h->cb.on_connect_complete)(h, -1);
+}
+
+/*
+ * pj_ioqueue_recv()
+ *
+ * Start asynchronous recv() from the socket.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_recv( pj_ioqueue_key_t *key,
+ pj_ioqueue_op_key_t *op_key,
+ void *buffer,
+ pj_ssize_t *length,
+ unsigned flags )
+{
+ pj_status_t status;
+ pj_ssize_t size;
+ struct read_operation *read_op;
+
+ PJ_ASSERT_RETURN(key && op_key && buffer && length, PJ_EINVAL);
+ PJ_CHECK_STACK();
read_op = (struct read_operation*)op_key;
read_op->op = 0;
-
- /* Try to see if there's data immediately available.
- */
- size = *length;
- status = pj_sock_recv(key->fd, buffer, &size, flags);
- if (status == PJ_SUCCESS) {
- /* Yes! Data is available! */
- *length = size;
- return PJ_SUCCESS;
- } else {
- /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report
- * the error to caller.
- */
- if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL))
- return status;
- }
-
- /*
- * No data is immediately available.
- * Must schedule asynchronous operation to the ioqueue.
- */
- read_op->op = PJ_IOQUEUE_OP_RECV;
- read_op->buf = buffer;
- read_op->size = *length;
- read_op->flags = flags;
-
- pj_mutex_lock(key->mutex);
- pj_list_insert_before(&key->read_list, read_op);
- ioqueue_add_to_set(key->ioqueue, key->fd, READABLE_EVENT);
- pj_mutex_unlock(key->mutex);
-
- return PJ_EPENDING;
-}
-
-/*
- * pj_ioqueue_recvfrom()
- *
- * Start asynchronous recvfrom() from the socket.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_key_t *key,
- pj_ioqueue_op_key_t *op_key,
- void *buffer,
- pj_ssize_t *length,
- unsigned flags,
- pj_sockaddr_t *addr,
- int *addrlen)
-{
- pj_status_t status;
- pj_ssize_t size;
- struct read_operation *read_op;
-
- PJ_ASSERT_RETURN(key && op_key && buffer && length, PJ_EINVAL);
- PJ_CHECK_STACK();
+
+ /* Try to see if there's data immediately available.
+ */
+ size = *length;
+ status = pj_sock_recv(key->fd, buffer, &size, flags);
+ if (status == PJ_SUCCESS) {
+ /* Yes! Data is available! */
+ *length = size;
+ return PJ_SUCCESS;
+ } else {
+ /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report
+ * the error to caller.
+ */
+ if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL))
+ return status;
+ }
+
+ /*
+ * No data is immediately available.
+ * Must schedule asynchronous operation to the ioqueue.
+ */
+ read_op->op = PJ_IOQUEUE_OP_RECV;
+ read_op->buf = buffer;
+ read_op->size = *length;
+ read_op->flags = flags;
+
+ pj_mutex_lock(key->mutex);
+ pj_list_insert_before(&key->read_list, read_op);
+ ioqueue_add_to_set(key->ioqueue, key->fd, READABLE_EVENT);
+ pj_mutex_unlock(key->mutex);
+
+ return PJ_EPENDING;
+}
+
+/*
+ * pj_ioqueue_recvfrom()
+ *
+ * Start asynchronous recvfrom() from the socket.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_key_t *key,
+ pj_ioqueue_op_key_t *op_key,
+ void *buffer,
+ pj_ssize_t *length,
+ unsigned flags,
+ pj_sockaddr_t *addr,
+ int *addrlen)
+{
+ pj_status_t status;
+ pj_ssize_t size;
+ struct read_operation *read_op;
+
+ PJ_ASSERT_RETURN(key && op_key && buffer && length, PJ_EINVAL);
+ PJ_CHECK_STACK();
read_op = (struct read_operation*)op_key;
read_op->op = 0;
-
- /* Try to see if there's data immediately available.
- */
- size = *length;
- status = pj_sock_recvfrom(key->fd, buffer, &size, flags,
- addr, addrlen);
- if (status == PJ_SUCCESS) {
- /* Yes! Data is available! */
- *length = size;
- return PJ_SUCCESS;
- } else {
- /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report
- * the error to caller.
- */
- if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL))
- return status;
- }
-
- /*
- * No data is immediately available.
- * Must schedule asynchronous operation to the ioqueue.
- */
- read_op->op = PJ_IOQUEUE_OP_RECV_FROM;
- read_op->buf = buffer;
- read_op->size = *length;
- read_op->flags = flags;
- read_op->rmt_addr = addr;
- read_op->rmt_addrlen = addrlen;
-
- pj_mutex_lock(key->mutex);
- pj_list_insert_before(&key->read_list, read_op);
- ioqueue_add_to_set(key->ioqueue, key->fd, READABLE_EVENT);
- pj_mutex_unlock(key->mutex);
-
- return PJ_EPENDING;
-}
-
-/*
- * pj_ioqueue_send()
- *
- * Start asynchronous send() to the descriptor.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_send( pj_ioqueue_key_t *key,
- pj_ioqueue_op_key_t *op_key,
- const void *data,
- pj_ssize_t *length,
- unsigned flags)
-{
- struct write_operation *write_op;
- pj_status_t status;
- pj_ssize_t sent;
-
- PJ_ASSERT_RETURN(key && op_key && data && length, PJ_EINVAL);
- PJ_CHECK_STACK();
+
+ /* Try to see if there's data immediately available.
+ */
+ size = *length;
+ status = pj_sock_recvfrom(key->fd, buffer, &size, flags,
+ addr, addrlen);
+ if (status == PJ_SUCCESS) {
+ /* Yes! Data is available! */
+ *length = size;
+ return PJ_SUCCESS;
+ } else {
+ /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report
+ * the error to caller.
+ */
+ if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL))
+ return status;
+ }
+
+ /*
+ * No data is immediately available.
+ * Must schedule asynchronous operation to the ioqueue.
+ */
+ read_op->op = PJ_IOQUEUE_OP_RECV_FROM;
+ read_op->buf = buffer;
+ read_op->size = *length;
+ read_op->flags = flags;
+ read_op->rmt_addr = addr;
+ read_op->rmt_addrlen = addrlen;
+
+ pj_mutex_lock(key->mutex);
+ pj_list_insert_before(&key->read_list, read_op);
+ ioqueue_add_to_set(key->ioqueue, key->fd, READABLE_EVENT);
+ pj_mutex_unlock(key->mutex);
+
+ return PJ_EPENDING;
+}
+
+/*
+ * pj_ioqueue_send()
+ *
+ * Start asynchronous send() to the descriptor.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_send( pj_ioqueue_key_t *key,
+ pj_ioqueue_op_key_t *op_key,
+ const void *data,
+ pj_ssize_t *length,
+ unsigned flags)
+{
+ struct write_operation *write_op;
+ pj_status_t status;
+ pj_ssize_t sent;
+
+ PJ_ASSERT_RETURN(key && op_key && data && length, PJ_EINVAL);
+ PJ_CHECK_STACK();
write_op = (struct write_operation*)op_key;
write_op->op = 0;
-
- /* Fast track:
- * Try to send data immediately, only if there's no pending write!
- * Note:
- * We are speculating that the list is empty here without properly
- * acquiring ioqueue's mutex first. This is intentional, to maximize
- * performance via parallelism.
- *
- * This should be safe, because:
- * - by convention, we require caller to make sure that the
- * key is not unregistered while other threads are invoking
- * an operation on the same key.
- * - pj_list_empty() is safe to be invoked by multiple threads,
- * even when other threads are modifying the list.
- */
- if (pj_list_empty(&key->write_list)) {
- /*
- * See if data can be sent immediately.
- */
- sent = *length;
- status = pj_sock_send(key->fd, data, &sent, flags);
- if (status == PJ_SUCCESS) {
- /* Success! */
- *length = sent;
- return PJ_SUCCESS;
- } else {
- /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report
- * the error to caller.
- */
- if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL)) {
- return status;
- }
- }
- }
-
- /*
- * Schedule asynchronous send.
- */
- write_op->op = PJ_IOQUEUE_OP_SEND;
- write_op->buf = (void*)data;
- write_op->size = *length;
- write_op->written = 0;
- write_op->flags = flags;
-
- pj_mutex_lock(key->mutex);
- pj_list_insert_before(&key->write_list, write_op);
- ioqueue_add_to_set(key->ioqueue, key->fd, WRITEABLE_EVENT);
- pj_mutex_unlock(key->mutex);
-
- return PJ_EPENDING;
-}
-
-
-/*
- * pj_ioqueue_sendto()
- *
- * Start asynchronous write() to the descriptor.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_key_t *key,
- pj_ioqueue_op_key_t *op_key,
- const void *data,
- pj_ssize_t *length,
- unsigned flags,
- const pj_sockaddr_t *addr,
- int addrlen)
-{
- struct write_operation *write_op;
- pj_status_t status;
- pj_ssize_t sent;
-
- PJ_ASSERT_RETURN(key && op_key && data && length, PJ_EINVAL);
- PJ_CHECK_STACK();
+
+ /* Fast track:
+ * Try to send data immediately, only if there's no pending write!
+ * Note:
+ * We are speculating that the list is empty here without properly
+ * acquiring ioqueue's mutex first. This is intentional, to maximize
+ * performance via parallelism.
+ *
+ * This should be safe, because:
+ * - by convention, we require caller to make sure that the
+ * key is not unregistered while other threads are invoking
+ * an operation on the same key.
+ * - pj_list_empty() is safe to be invoked by multiple threads,
+ * even when other threads are modifying the list.
+ */
+ if (pj_list_empty(&key->write_list)) {
+ /*
+ * See if data can be sent immediately.
+ */
+ sent = *length;
+ status = pj_sock_send(key->fd, data, &sent, flags);
+ if (status == PJ_SUCCESS) {
+ /* Success! */
+ *length = sent;
+ return PJ_SUCCESS;
+ } else {
+ /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report
+ * the error to caller.
+ */
+ if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL)) {
+ return status;
+ }
+ }
+ }
+
+ /*
+ * Schedule asynchronous send.
+ */
+ write_op->op = PJ_IOQUEUE_OP_SEND;
+ write_op->buf = (void*)data;
+ write_op->size = *length;
+ write_op->written = 0;
+ write_op->flags = flags;
+
+ pj_mutex_lock(key->mutex);
+ pj_list_insert_before(&key->write_list, write_op);
+ ioqueue_add_to_set(key->ioqueue, key->fd, WRITEABLE_EVENT);
+ pj_mutex_unlock(key->mutex);
+
+ return PJ_EPENDING;
+}
+
+
+/*
+ * pj_ioqueue_sendto()
+ *
+ * Start asynchronous write() to the descriptor.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_key_t *key,
+ pj_ioqueue_op_key_t *op_key,
+ const void *data,
+ pj_ssize_t *length,
+ unsigned flags,
+ const pj_sockaddr_t *addr,
+ int addrlen)
+{
+ struct write_operation *write_op;
+ pj_status_t status;
+ pj_ssize_t sent;
+
+ PJ_ASSERT_RETURN(key && op_key && data && length, PJ_EINVAL);
+ PJ_CHECK_STACK();
write_op = (struct write_operation*)op_key;
write_op->op = 0;
-
- /* Fast track:
- * Try to send data immediately, only if there's no pending write!
- * Note:
- * We are speculating that the list is empty here without properly
- * acquiring ioqueue's mutex first. This is intentional, to maximize
- * performance via parallelism.
- *
- * This should be safe, because:
- * - by convention, we require caller to make sure that the
- * key is not unregistered while other threads are invoking
- * an operation on the same key.
- * - pj_list_empty() is safe to be invoked by multiple threads,
- * even when other threads are modifying the list.
- */
- if (pj_list_empty(&key->write_list)) {
- /*
- * See if data can be sent immediately.
- */
- sent = *length;
- status = pj_sock_sendto(key->fd, data, &sent, flags, addr, addrlen);
- if (status == PJ_SUCCESS) {
- /* Success! */
- *length = sent;
- return PJ_SUCCESS;
- } else {
- /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report
- * the error to caller.
- */
- if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL)) {
- return status;
- }
- }
- }
-
- /*
- * Check that address storage can hold the address parameter.
- */
- PJ_ASSERT_RETURN(addrlen <= sizeof(pj_sockaddr_in), PJ_EBUG);
-
- /*
- * Schedule asynchronous send.
- */
- write_op->op = PJ_IOQUEUE_OP_SEND_TO;
- write_op->buf = (void*)data;
- write_op->size = *length;
- write_op->written = 0;
- write_op->flags = flags;
- pj_memcpy(&write_op->rmt_addr, addr, addrlen);
- write_op->rmt_addrlen = addrlen;
-
- pj_mutex_lock(key->mutex);
- pj_list_insert_before(&key->write_list, write_op);
- ioqueue_add_to_set(key->ioqueue, key->fd, WRITEABLE_EVENT);
- pj_mutex_unlock(key->mutex);
-
- return PJ_EPENDING;
-}
-
-#if PJ_HAS_TCP
-/*
- * Initiate overlapped accept() operation.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_accept( pj_ioqueue_key_t *key,
- pj_ioqueue_op_key_t *op_key,
- pj_sock_t *new_sock,
- pj_sockaddr_t *local,
- pj_sockaddr_t *remote,
- int *addrlen)
-{
- struct accept_operation *accept_op;
- pj_status_t status;
-
- /* check parameters. All must be specified! */
- PJ_ASSERT_RETURN(key && op_key && new_sock, PJ_EINVAL);
+
+ /* Fast track:
+ * Try to send data immediately, only if there's no pending write!
+ * Note:
+ * We are speculating that the list is empty here without properly
+ * acquiring ioqueue's mutex first. This is intentional, to maximize
+ * performance via parallelism.
+ *
+ * This should be safe, because:
+ * - by convention, we require caller to make sure that the
+ * key is not unregistered while other threads are invoking
+ * an operation on the same key.
+ * - pj_list_empty() is safe to be invoked by multiple threads,
+ * even when other threads are modifying the list.
+ */
+ if (pj_list_empty(&key->write_list)) {
+ /*
+ * See if data can be sent immediately.
+ */
+ sent = *length;
+ status = pj_sock_sendto(key->fd, data, &sent, flags, addr, addrlen);
+ if (status == PJ_SUCCESS) {
+ /* Success! */
+ *length = sent;
+ return PJ_SUCCESS;
+ } else {
+ /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report
+ * the error to caller.
+ */
+ if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL)) {
+ return status;
+ }
+ }
+ }
+
+ /*
+ * Check that address storage can hold the address parameter.
+ */
+ PJ_ASSERT_RETURN(addrlen <= sizeof(pj_sockaddr_in), PJ_EBUG);
+
+ /*
+ * Schedule asynchronous send.
+ */
+ write_op->op = PJ_IOQUEUE_OP_SEND_TO;
+ write_op->buf = (void*)data;
+ write_op->size = *length;
+ write_op->written = 0;
+ write_op->flags = flags;
+ pj_memcpy(&write_op->rmt_addr, addr, addrlen);
+ write_op->rmt_addrlen = addrlen;
+
+ pj_mutex_lock(key->mutex);
+ pj_list_insert_before(&key->write_list, write_op);
+ ioqueue_add_to_set(key->ioqueue, key->fd, WRITEABLE_EVENT);
+ pj_mutex_unlock(key->mutex);
+
+ return PJ_EPENDING;
+}
+
+#if PJ_HAS_TCP
+/*
+ * Initiate overlapped accept() operation.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_accept( pj_ioqueue_key_t *key,
+ pj_ioqueue_op_key_t *op_key,
+ pj_sock_t *new_sock,
+ pj_sockaddr_t *local,
+ pj_sockaddr_t *remote,
+ int *addrlen)
+{
+ struct accept_operation *accept_op;
+ pj_status_t status;
+
+ /* check parameters. All must be specified! */
+ PJ_ASSERT_RETURN(key && op_key && new_sock, PJ_EINVAL);
accept_op = (struct accept_operation*)op_key;
accept_op->op = 0;
-
- /* Fast track:
- * See if there's new connection available immediately.
- */
- if (pj_list_empty(&key->accept_list)) {
- status = pj_sock_accept(key->fd, new_sock, remote, addrlen);
- if (status == PJ_SUCCESS) {
- /* Yes! New connection is available! */
- if (local && addrlen) {
- status = pj_sock_getsockname(*new_sock, local, addrlen);
- if (status != PJ_SUCCESS) {
- pj_sock_close(*new_sock);
- *new_sock = PJ_INVALID_SOCKET;
- return status;
- }
- }
- return PJ_SUCCESS;
- } else {
- /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report
- * the error to caller.
- */
- if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL)) {
- return status;
- }
- }
- }
-
- /*
- * No connection is available immediately.
- * Schedule accept() operation to be completed when there is incoming
- * connection available.
- */
- accept_op->op = PJ_IOQUEUE_OP_ACCEPT;
- accept_op->accept_fd = new_sock;
- accept_op->rmt_addr = remote;
- accept_op->addrlen= addrlen;
- accept_op->local_addr = local;
-
- pj_mutex_lock(key->mutex);
- pj_list_insert_before(&key->accept_list, accept_op);
- ioqueue_add_to_set(key->ioqueue, key->fd, READABLE_EVENT);
- pj_mutex_unlock(key->mutex);
-
- return PJ_EPENDING;
-}
-
-/*
- * Initiate overlapped connect() operation (well, it's non-blocking actually,
- * since there's no overlapped version of connect()).
- */
-PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_key_t *key,
- const pj_sockaddr_t *addr,
- int addrlen )
-{
- pj_status_t status;
-
- /* check parameters. All must be specified! */
- PJ_ASSERT_RETURN(key && addr && addrlen, PJ_EINVAL);
-
- /* Check if socket has not been marked for connecting */
- if (key->connecting != 0)
- return PJ_EPENDING;
-
- status = pj_sock_connect(key->fd, addr, addrlen);
- if (status == PJ_SUCCESS) {
- /* Connected! */
- return PJ_SUCCESS;
- } else {
- if (status == PJ_STATUS_FROM_OS(PJ_BLOCKING_CONNECT_ERROR_VAL)) {
- /* Pending! */
- pj_mutex_lock(key->mutex);
- key->connecting = PJ_TRUE;
- ioqueue_add_to_set(key->ioqueue, key->fd, WRITEABLE_EVENT);
- ioqueue_add_to_set(key->ioqueue, key->fd, EXCEPTION_EVENT);
- pj_mutex_unlock(key->mutex);
- return PJ_EPENDING;
- } else {
- /* Error! */
- return status;
- }
- }
-}
-#endif /* PJ_HAS_TCP */
+
+ /* Fast track:
+ * See if there's new connection available immediately.
+ */
+ if (pj_list_empty(&key->accept_list)) {
+ status = pj_sock_accept(key->fd, new_sock, remote, addrlen);
+ if (status == PJ_SUCCESS) {
+ /* Yes! New connection is available! */
+ if (local && addrlen) {
+ status = pj_sock_getsockname(*new_sock, local, addrlen);
+ if (status != PJ_SUCCESS) {
+ pj_sock_close(*new_sock);
+ *new_sock = PJ_INVALID_SOCKET;
+ return status;
+ }
+ }
+ return PJ_SUCCESS;
+ } else {
+ /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report
+ * the error to caller.
+ */
+ if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL)) {
+ return status;
+ }
+ }
+ }
+
+ /*
+ * No connection is available immediately.
+ * Schedule accept() operation to be completed when there is incoming
+ * connection available.
+ */
+ accept_op->op = PJ_IOQUEUE_OP_ACCEPT;
+ accept_op->accept_fd = new_sock;
+ accept_op->rmt_addr = remote;
+ accept_op->addrlen= addrlen;
+ accept_op->local_addr = local;
+
+ pj_mutex_lock(key->mutex);
+ pj_list_insert_before(&key->accept_list, accept_op);
+ ioqueue_add_to_set(key->ioqueue, key->fd, READABLE_EVENT);
+ pj_mutex_unlock(key->mutex);
+
+ return PJ_EPENDING;
+}
+
+/*
+ * Initiate overlapped connect() operation (well, it's non-blocking actually,
+ * since there's no overlapped version of connect()).
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_key_t *key,
+ const pj_sockaddr_t *addr,
+ int addrlen )
+{
+ pj_status_t status;
+
+ /* check parameters. All must be specified! */
+ PJ_ASSERT_RETURN(key && addr && addrlen, PJ_EINVAL);
+
+ /* Check if socket has not been marked for connecting */
+ if (key->connecting != 0)
+ return PJ_EPENDING;
+
+ status = pj_sock_connect(key->fd, addr, addrlen);
+ if (status == PJ_SUCCESS) {
+ /* Connected! */
+ return PJ_SUCCESS;
+ } else {
+ if (status == PJ_STATUS_FROM_OS(PJ_BLOCKING_CONNECT_ERROR_VAL)) {
+ /* Pending! */
+ pj_mutex_lock(key->mutex);
+ key->connecting = PJ_TRUE;
+ ioqueue_add_to_set(key->ioqueue, key->fd, WRITEABLE_EVENT);
+ ioqueue_add_to_set(key->ioqueue, key->fd, EXCEPTION_EVENT);
+ pj_mutex_unlock(key->mutex);
+ return PJ_EPENDING;
+ } else {
+ /* Error! */
+ return status;
+ }
+ }
+}
+#endif /* PJ_HAS_TCP */
PJ_DEF(void) pj_ioqueue_op_key_init( pj_ioqueue_op_key_t *op_key,
@@ -840,7 +861,7 @@ PJ_DEF(void) pj_ioqueue_op_key_init( pj_ioqueue_op_key_t *op_key,
pj_memset(op_key, 0, size);
}
-
+
/*
* pj_ioqueue_is_pending()
*/
diff --git a/pjlib/src/pj/ioqueue_common_abs.h b/pjlib/src/pj/ioqueue_common_abs.h
index 1902ff46..85f6f37e 100644
--- a/pjlib/src/pj/ioqueue_common_abs.h
+++ b/pjlib/src/pj/ioqueue_common_abs.h
@@ -1,108 +1,129 @@
-/* $Id */
-
-/* ioqueue_common_abs.h
- *
- * This file contains private declarations for abstracting various
- * event polling/dispatching mechanisms (e.g. select, poll, epoll)
- * to the ioqueue.
- */
-
-#include <pj/list.h>
-
-/*
- * The select ioqueue relies on socket functions (pj_sock_xxx()) to return
- * the correct error code.
- */
-#if PJ_RETURN_OS_ERROR(100) != PJ_STATUS_FROM_OS(100)
-# error "Proper error reporting must be enabled for ioqueue to work!"
-#endif
-
-
-struct generic_operation
-{
- PJ_DECL_LIST_MEMBER(struct generic_operation);
- pj_ioqueue_operation_e op;
-};
-
-struct read_operation
-{
- PJ_DECL_LIST_MEMBER(struct read_operation);
- pj_ioqueue_operation_e op;
-
- void *buf;
- pj_size_t size;
- unsigned flags;
- pj_sockaddr_t *rmt_addr;
- int *rmt_addrlen;
-};
-
-struct write_operation
-{
- PJ_DECL_LIST_MEMBER(struct write_operation);
- pj_ioqueue_operation_e op;
-
- char *buf;
- pj_size_t size;
- pj_ssize_t written;
- unsigned flags;
- pj_sockaddr_in rmt_addr;
- int rmt_addrlen;
-};
-
-#if PJ_HAS_TCP
-struct accept_operation
-{
- PJ_DECL_LIST_MEMBER(struct accept_operation);
- pj_ioqueue_operation_e op;
-
- pj_sock_t *accept_fd;
- pj_sockaddr_t *local_addr;
- pj_sockaddr_t *rmt_addr;
- int *addrlen;
-};
-#endif
-
-union operation_key
-{
- struct generic_operation generic;
- struct read_operation read;
- struct write_operation write;
-#if PJ_HAS_TCP
- struct accept_operation accept;
-#endif
-};
-
-#define DECLARE_COMMON_KEY \
- PJ_DECL_LIST_MEMBER(struct pj_ioqueue_key_t); \
- pj_ioqueue_t *ioqueue; \
- pj_mutex_t *mutex; \
- pj_sock_t fd; \
- int fd_type; \
- void *user_data; \
- pj_ioqueue_callback cb; \
- int connecting; \
- struct read_operation read_list; \
- struct write_operation write_list; \
- struct accept_operation accept_list;
-
-
-#define DECLARE_COMMON_IOQUEUE \
- pj_lock_t *lock; \
- pj_bool_t auto_delete_lock;
-
-
-enum ioqueue_event_type
-{
- NO_EVENT,
- READABLE_EVENT,
- WRITEABLE_EVENT,
- EXCEPTION_EVENT,
-};
-
-static void ioqueue_add_to_set( pj_ioqueue_t *ioqueue,
- pj_sock_t fd,
- enum ioqueue_event_type event_type );
-static void ioqueue_remove_from_set( pj_ioqueue_t *ioqueue,
- pj_sock_t fd,
- enum ioqueue_event_type event_type);
-
+/* $Id */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* ioqueue_common_abs.h
+ *
+ * This file contains private declarations for abstracting various
+ * event polling/dispatching mechanisms (e.g. select, poll, epoll)
+ * to the ioqueue.
+ */
+
+#include <pj/list.h>
+
+/*
+ * The select ioqueue relies on socket functions (pj_sock_xxx()) to return
+ * the correct error code.
+ */
+#if PJ_RETURN_OS_ERROR(100) != PJ_STATUS_FROM_OS(100)
+# error "Proper error reporting must be enabled for ioqueue to work!"
+#endif
+
+
+struct generic_operation
+{
+ PJ_DECL_LIST_MEMBER(struct generic_operation);
+ pj_ioqueue_operation_e op;
+};
+
+struct read_operation
+{
+ PJ_DECL_LIST_MEMBER(struct read_operation);
+ pj_ioqueue_operation_e op;
+
+ void *buf;
+ pj_size_t size;
+ unsigned flags;
+ pj_sockaddr_t *rmt_addr;
+ int *rmt_addrlen;
+};
+
+struct write_operation
+{
+ PJ_DECL_LIST_MEMBER(struct write_operation);
+ pj_ioqueue_operation_e op;
+
+ char *buf;
+ pj_size_t size;
+ pj_ssize_t written;
+ unsigned flags;
+ pj_sockaddr_in rmt_addr;
+ int rmt_addrlen;
+};
+
+#if PJ_HAS_TCP
+struct accept_operation
+{
+ PJ_DECL_LIST_MEMBER(struct accept_operation);
+ pj_ioqueue_operation_e op;
+
+ pj_sock_t *accept_fd;
+ pj_sockaddr_t *local_addr;
+ pj_sockaddr_t *rmt_addr;
+ int *addrlen;
+};
+#endif
+
+union operation_key
+{
+ struct generic_operation generic;
+ struct read_operation read;
+ struct write_operation write;
+#if PJ_HAS_TCP
+ struct accept_operation accept;
+#endif
+};
+
+#define DECLARE_COMMON_KEY \
+ PJ_DECL_LIST_MEMBER(struct pj_ioqueue_key_t); \
+ pj_ioqueue_t *ioqueue; \
+ pj_mutex_t *mutex; \
+ pj_sock_t fd; \
+ int fd_type; \
+ void *user_data; \
+ pj_ioqueue_callback cb; \
+ int connecting; \
+ struct read_operation read_list; \
+ struct write_operation write_list; \
+ struct accept_operation accept_list;
+
+
+#define DECLARE_COMMON_IOQUEUE \
+ pj_lock_t *lock; \
+ pj_bool_t auto_delete_lock;
+
+
+enum ioqueue_event_type
+{
+ NO_EVENT,
+ READABLE_EVENT,
+ WRITEABLE_EVENT,
+ EXCEPTION_EVENT,
+};
+
+static void ioqueue_add_to_set( pj_ioqueue_t *ioqueue,
+ pj_sock_t fd,
+ enum ioqueue_event_type event_type );
+static void ioqueue_remove_from_set( pj_ioqueue_t *ioqueue,
+ pj_sock_t fd,
+ enum ioqueue_event_type event_type);
+
diff --git a/pjlib/src/pj/ioqueue_dummy.c b/pjlib/src/pj/ioqueue_dummy.c
index 3a9927f9..b09e5ed0 100644
--- a/pjlib/src/pj/ioqueue_dummy.c
+++ b/pjlib/src/pj/ioqueue_dummy.c
@@ -1,178 +1,199 @@
-/* $Id$
- *
- */
-#include <pj/ioqueue.h>
-#include <pj/os.h>
-#include <pj/log.h>
-#include <pj/list.h>
-#include <pj/pool.h>
-#include <pj/string.h>
-#include <pj/assert.h>
-#include <pj/sock.h>
-#include <pj/errno.h>
-
-#define THIS_FILE "ioqueue"
-
-#define PJ_IOQUEUE_IS_READ_OP(op) \
- ((op & PJ_IOQUEUE_OP_READ) || (op & PJ_IOQUEUE_OP_RECV_FROM))
-#define PJ_IOQUEUE_IS_WRITE_OP(op) \
- ((op & PJ_IOQUEUE_OP_WRITE) || (op & PJ_IOQUEUE_OP_SEND_TO))
-
-
-#if PJ_HAS_TCP
-# define PJ_IOQUEUE_IS_ACCEPT_OP(op) (op & PJ_IOQUEUE_OP_ACCEPT)
-# define PJ_IOQUEUE_IS_CONNECT_OP(op) (op & PJ_IOQUEUE_OP_CONNECT)
-#else
-# define PJ_IOQUEUE_IS_ACCEPT_OP(op) 0
-# define PJ_IOQUEUE_IS_CONNECT_OP(op) 0
-#endif
-
-#if defined(PJ_DEBUG) && PJ_DEBUG != 0
-# define VALIDATE_FD_SET 1
-#else
-# define VALIDATE_FD_SET 0
-#endif
-
-struct pj_ioqueue_key_t
-{
- PJ_DECL_LIST_MEMBER(struct pj_ioqueue_key_t)
- pj_sock_t fd;
- pj_ioqueue_operation_e op;
- void *user_data;
- pj_ioqueue_callback cb;
-};
-
-struct pj_ioqueue_t
-{
-};
-
-PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool,
- pj_size_t max_fd,
- int max_threads,
- pj_ioqueue_t **ptr_ioqueue)
-{
- return PJ_ENOTSUP;
-}
-
-PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioque)
-{
- return PJ_ENOTSUP;
-}
-
-PJ_DEF(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioque,
- pj_lock_t *lock,
- pj_bool_t auto_delete )
-{
- return PJ_ENOTSUP;
-}
-
-PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,
- pj_ioqueue_t *ioque,
- pj_sock_t sock,
- void *user_data,
- const pj_ioqueue_callback *cb,
- pj_ioqueue_key_t **ptr_key)
-{
- return PJ_ENOTSUP;
-}
-
-PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_t *ioque,
- pj_ioqueue_key_t *key)
-{
- return PJ_ENOTSUP;
-}
-
-PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key )
-{
- return NULL;
-}
-
-
-PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioque, const pj_time_val *timeout)
-{
- return -1;
-}
-
-PJ_DEF(pj_status_t) pj_ioqueue_read( pj_ioqueue_t *ioque,
- pj_ioqueue_key_t *key,
- void *buffer,
- pj_size_t buflen)
-{
- return -1;
-}
-
-PJ_DEF(pj_status_t) pj_ioqueue_recv( pj_ioqueue_t *ioque,
- pj_ioqueue_key_t *key,
- void *buffer,
- pj_size_t buflen,
- unsigned flags)
-{
- return -1;
-}
-
-PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_t *ioque,
- pj_ioqueue_key_t *key,
- void *buffer,
- pj_size_t buflen,
- unsigned flags,
- pj_sockaddr_t *addr,
- int *addrlen)
-{
- return -1;
-}
-
-PJ_DEF(pj_status_t) pj_ioqueue_write( pj_ioqueue_t *ioque,
- pj_ioqueue_key_t *key,
- const void *data,
- pj_size_t datalen)
-{
- return -1;
-}
-
-PJ_DEF(pj_status_t) pj_ioqueue_send( pj_ioqueue_t *ioque,
- pj_ioqueue_key_t *key,
- const void *data,
- pj_size_t datalen,
- unsigned flags)
-{
- return -1;
-}
-
-PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_t *ioque,
- pj_ioqueue_key_t *key,
- const void *data,
- pj_size_t datalen,
- unsigned flags,
- const pj_sockaddr_t *addr,
- int addrlen)
-{
- return -1;
-}
-
-#if PJ_HAS_TCP
-/*
- * Initiate overlapped accept() operation.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_accept( pj_ioqueue_t *ioqueue,
- pj_ioqueue_key_t *key,
- pj_sock_t *new_sock,
- pj_sockaddr_t *local,
- pj_sockaddr_t *remote,
- int *addrlen)
-{
- return -1;
-}
-
-/*
- * Initiate overlapped connect() operation (well, it's non-blocking actually,
- * since there's no overlapped version of connect()).
- */
-PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_t *ioqueue,
- pj_ioqueue_key_t *key,
- const pj_sockaddr_t *addr,
- int addrlen )
-{
- return -1;
-}
-#endif /* PJ_HAS_TCP */
-
+/* $Id$
+ *
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/ioqueue.h>
+#include <pj/os.h>
+#include <pj/log.h>
+#include <pj/list.h>
+#include <pj/pool.h>
+#include <pj/string.h>
+#include <pj/assert.h>
+#include <pj/sock.h>
+#include <pj/errno.h>
+
+#define THIS_FILE "ioqueue"
+
+#define PJ_IOQUEUE_IS_READ_OP(op) \
+ ((op & PJ_IOQUEUE_OP_READ) || (op & PJ_IOQUEUE_OP_RECV_FROM))
+#define PJ_IOQUEUE_IS_WRITE_OP(op) \
+ ((op & PJ_IOQUEUE_OP_WRITE) || (op & PJ_IOQUEUE_OP_SEND_TO))
+
+
+#if PJ_HAS_TCP
+# define PJ_IOQUEUE_IS_ACCEPT_OP(op) (op & PJ_IOQUEUE_OP_ACCEPT)
+# define PJ_IOQUEUE_IS_CONNECT_OP(op) (op & PJ_IOQUEUE_OP_CONNECT)
+#else
+# define PJ_IOQUEUE_IS_ACCEPT_OP(op) 0
+# define PJ_IOQUEUE_IS_CONNECT_OP(op) 0
+#endif
+
+#if defined(PJ_DEBUG) && PJ_DEBUG != 0
+# define VALIDATE_FD_SET 1
+#else
+# define VALIDATE_FD_SET 0
+#endif
+
+struct pj_ioqueue_key_t
+{
+ PJ_DECL_LIST_MEMBER(struct pj_ioqueue_key_t)
+ pj_sock_t fd;
+ pj_ioqueue_operation_e op;
+ void *user_data;
+ pj_ioqueue_callback cb;
+};
+
+struct pj_ioqueue_t
+{
+};
+
+PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool,
+ pj_size_t max_fd,
+ int max_threads,
+ pj_ioqueue_t **ptr_ioqueue)
+{
+ return PJ_ENOTSUP;
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioque)
+{
+ return PJ_ENOTSUP;
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioque,
+ pj_lock_t *lock,
+ pj_bool_t auto_delete )
+{
+ return PJ_ENOTSUP;
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,
+ pj_ioqueue_t *ioque,
+ pj_sock_t sock,
+ void *user_data,
+ const pj_ioqueue_callback *cb,
+ pj_ioqueue_key_t **ptr_key)
+{
+ return PJ_ENOTSUP;
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_t *ioque,
+ pj_ioqueue_key_t *key)
+{
+ return PJ_ENOTSUP;
+}
+
+PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key )
+{
+ return NULL;
+}
+
+
+PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioque, const pj_time_val *timeout)
+{
+ return -1;
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_read( pj_ioqueue_t *ioque,
+ pj_ioqueue_key_t *key,
+ void *buffer,
+ pj_size_t buflen)
+{
+ return -1;
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_recv( pj_ioqueue_t *ioque,
+ pj_ioqueue_key_t *key,
+ void *buffer,
+ pj_size_t buflen,
+ unsigned flags)
+{
+ return -1;
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_t *ioque,
+ pj_ioqueue_key_t *key,
+ void *buffer,
+ pj_size_t buflen,
+ unsigned flags,
+ pj_sockaddr_t *addr,
+ int *addrlen)
+{
+ return -1;
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_write( pj_ioqueue_t *ioque,
+ pj_ioqueue_key_t *key,
+ const void *data,
+ pj_size_t datalen)
+{
+ return -1;
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_send( pj_ioqueue_t *ioque,
+ pj_ioqueue_key_t *key,
+ const void *data,
+ pj_size_t datalen,
+ unsigned flags)
+{
+ return -1;
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_t *ioque,
+ pj_ioqueue_key_t *key,
+ const void *data,
+ pj_size_t datalen,
+ unsigned flags,
+ const pj_sockaddr_t *addr,
+ int addrlen)
+{
+ return -1;
+}
+
+#if PJ_HAS_TCP
+/*
+ * Initiate overlapped accept() operation.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_accept( pj_ioqueue_t *ioqueue,
+ pj_ioqueue_key_t *key,
+ pj_sock_t *new_sock,
+ pj_sockaddr_t *local,
+ pj_sockaddr_t *remote,
+ int *addrlen)
+{
+ return -1;
+}
+
+/*
+ * Initiate overlapped connect() operation (well, it's non-blocking actually,
+ * since there's no overlapped version of connect()).
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_t *ioqueue,
+ pj_ioqueue_key_t *key,
+ const pj_sockaddr_t *addr,
+ int addrlen )
+{
+ return -1;
+}
+#endif /* PJ_HAS_TCP */
+
diff --git a/pjlib/src/pj/ioqueue_epoll.c b/pjlib/src/pj/ioqueue_epoll.c
index 140bd130..86490422 100644
--- a/pjlib/src/pj/ioqueue_epoll.c
+++ b/pjlib/src/pj/ioqueue_epoll.c
@@ -1,458 +1,479 @@
-/* $Id$
- */
-/*
- * ioqueue_epoll.c
- *
- * This is the implementation of IOQueue framework using /dev/epoll
- * API in _both_ Linux user-mode and kernel-mode.
- */
-
-#include <pj/ioqueue.h>
-#include <pj/os.h>
-#include <pj/lock.h>
-#include <pj/log.h>
-#include <pj/list.h>
-#include <pj/pool.h>
-#include <pj/string.h>
-#include <pj/assert.h>
-#include <pj/errno.h>
-#include <pj/sock.h>
-#include <pj/compat/socket.h>
-
-#if !defined(PJ_LINUX_KERNEL) || PJ_LINUX_KERNEL==0
- /*
- * Linux user mode
- */
-# include <sys/epoll.h>
-# include <errno.h>
-# include <unistd.h>
-
-# define epoll_data data.ptr
-# define epoll_data_type void*
-# define ioctl_val_type unsigned long
-# define getsockopt_val_ptr int*
-# define os_getsockopt getsockopt
-# define os_ioctl ioctl
-# define os_read read
-# define os_close close
-# define os_epoll_create epoll_create
-# define os_epoll_ctl epoll_ctl
-# define os_epoll_wait epoll_wait
-#else
- /*
- * Linux kernel mode.
- */
-# include <linux/config.h>
-# include <linux/version.h>
-# if defined(MODVERSIONS)
-# include <linux/modversions.h>
-# endif
-# include <linux/kernel.h>
-# include <linux/poll.h>
-# include <linux/eventpoll.h>
-# include <linux/syscalls.h>
-# include <linux/errno.h>
-# include <linux/unistd.h>
-# include <asm/ioctls.h>
- enum EPOLL_EVENTS
- {
- EPOLLIN = 0x001,
- EPOLLOUT = 0x004,
- EPOLLERR = 0x008,
- };
-# define os_epoll_create sys_epoll_create
- static int os_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
- {
- long rc;
- mm_segment_t oldfs = get_fs();
- set_fs(KERNEL_DS);
- rc = sys_epoll_ctl(epfd, op, fd, event);
- set_fs(oldfs);
- if (rc) {
- errno = -rc;
- return -1;
- } else {
- return 0;
- }
- }
- static int os_epoll_wait(int epfd, struct epoll_event *events,
- int maxevents, int timeout)
- {
- int count;
- mm_segment_t oldfs = get_fs();
- set_fs(KERNEL_DS);
- count = sys_epoll_wait(epfd, events, maxevents, timeout);
- set_fs(oldfs);
- return count;
- }
-# define os_close sys_close
-# define os_getsockopt pj_sock_getsockopt
- static int os_read(int fd, void *buf, size_t len)
- {
- long rc;
- mm_segment_t oldfs = get_fs();
- set_fs(KERNEL_DS);
- rc = sys_read(fd, buf, len);
- set_fs(oldfs);
- if (rc) {
- errno = -rc;
- return -1;
- } else {
- return 0;
- }
- }
-# define socklen_t unsigned
-# define ioctl_val_type unsigned long
- int ioctl(int fd, int opt, ioctl_val_type value);
- static int os_ioctl(int fd, int opt, ioctl_val_type value)
- {
- int rc;
- mm_segment_t oldfs = get_fs();
- set_fs(KERNEL_DS);
- rc = ioctl(fd, opt, value);
- set_fs(oldfs);
- if (rc < 0) {
- errno = -rc;
- return rc;
- } else
- return rc;
- }
-# define getsockopt_val_ptr char*
-
-# define epoll_data data
-# define epoll_data_type __u32
-#endif
-
-#define THIS_FILE "ioq_epoll"
-
-//#define TRACE_(expr) PJ_LOG(3,expr)
-#define TRACE_(expr)
-
-/*
- * Include common ioqueue abstraction.
- */
-#include "ioqueue_common_abs.h"
-
-/*
- * This describes each key.
- */
-struct pj_ioqueue_key_t
-{
- DECLARE_COMMON_KEY
-};
-
-/*
- * This describes the I/O queue.
- */
-struct pj_ioqueue_t
-{
- DECLARE_COMMON_IOQUEUE
-
- unsigned max, count;
- pj_ioqueue_key_t hlist;
- int epfd;
-};
-
-/* Include implementation for common abstraction after we declare
- * pj_ioqueue_key_t and pj_ioqueue_t.
- */
-#include "ioqueue_common_abs.c"
-
-/*
- * pj_ioqueue_name()
- */
-PJ_DEF(const char*) pj_ioqueue_name(void)
-{
-#if defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL!=0
- return "epoll-kernel";
-#else
- return "epoll";
-#endif
-}
-
-/*
- * pj_ioqueue_create()
- *
- * Create select ioqueue.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool,
- pj_size_t max_fd,
- pj_ioqueue_t **p_ioqueue)
-{
- pj_ioqueue_t *ioqueue;
- pj_status_t rc;
- pj_lock_t *lock;
-
- /* Check that arguments are valid. */
- PJ_ASSERT_RETURN(pool != NULL && p_ioqueue != NULL &&
- max_fd > 0, PJ_EINVAL);
-
- /* Check that size of pj_ioqueue_op_key_t is sufficient */
- PJ_ASSERT_RETURN(sizeof(pj_ioqueue_op_key_t)-sizeof(void*) >=
- sizeof(union operation_key), PJ_EBUG);
-
- ioqueue = pj_pool_alloc(pool, sizeof(pj_ioqueue_t));
-
- ioqueue_init(ioqueue);
-
- ioqueue->max = max_fd;
- ioqueue->count = 0;
- pj_list_init(&ioqueue->hlist);
-
- rc = pj_lock_create_simple_mutex(pool, "ioq%p", &lock);
- if (rc != PJ_SUCCESS)
- return rc;
-
- rc = pj_ioqueue_set_lock(ioqueue, lock, PJ_TRUE);
- if (rc != PJ_SUCCESS)
- return rc;
-
- ioqueue->epfd = os_epoll_create(max_fd);
- if (ioqueue->epfd < 0) {
- ioqueue_destroy(ioqueue);
- return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
- }
-
- PJ_LOG(4, ("pjlib", "epoll I/O Queue created (%p)", ioqueue));
-
- *p_ioqueue = ioqueue;
- return PJ_SUCCESS;
-}
-
-/*
- * pj_ioqueue_destroy()
- *
- * Destroy ioqueue.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioqueue)
-{
- PJ_ASSERT_RETURN(ioqueue, PJ_EINVAL);
- PJ_ASSERT_RETURN(ioqueue->epfd > 0, PJ_EINVALIDOP);
-
- pj_lock_acquire(ioqueue->lock);
- os_close(ioqueue->epfd);
- ioqueue->epfd = 0;
- return ioqueue_destroy(ioqueue);
-}
-
-/*
- * pj_ioqueue_register_sock()
- *
- * Register a socket to ioqueue.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,
- pj_ioqueue_t *ioqueue,
- pj_sock_t sock,
- void *user_data,
- const pj_ioqueue_callback *cb,
- pj_ioqueue_key_t **p_key)
-{
- pj_ioqueue_key_t *key = NULL;
- pj_uint32_t value;
- struct epoll_event ev;
- int status;
- pj_status_t rc = PJ_SUCCESS;
-
- PJ_ASSERT_RETURN(pool && ioqueue && sock != PJ_INVALID_SOCKET &&
- cb && p_key, PJ_EINVAL);
-
- pj_lock_acquire(ioqueue->lock);
-
- if (ioqueue->count >= ioqueue->max) {
- rc = PJ_ETOOMANY;
- TRACE_((THIS_FILE, "pj_ioqueue_register_sock error: too many files"));
- goto on_return;
- }
-
- /* Set socket to nonblocking. */
- value = 1;
- if ((rc=os_ioctl(sock, FIONBIO, (ioctl_val_type)&value))) {
- TRACE_((THIS_FILE, "pj_ioqueue_register_sock error: ioctl rc=%d",
- rc));
- rc = pj_get_netos_error();
- goto on_return;
- }
-
- /* Create key. */
- key = (pj_ioqueue_key_t*)pj_pool_zalloc(pool, sizeof(pj_ioqueue_key_t));
- rc = ioqueue_init_key(pool, ioqueue, key, sock, user_data, cb);
- if (rc != PJ_SUCCESS) {
- key = NULL;
- goto on_return;
- }
-
- /* os_epoll_ctl. */
- ev.events = EPOLLIN | EPOLLOUT | EPOLLERR;
- ev.epoll_data = (epoll_data_type)key;
- status = os_epoll_ctl(ioqueue->epfd, EPOLL_CTL_ADD, sock, &ev);
- if (status < 0) {
- rc = pj_get_os_error();
- key = NULL;
- TRACE_((THIS_FILE,
- "pj_ioqueue_register_sock error: os_epoll_ctl rc=%d",
- status));
- goto on_return;
- }
-
- /* Register */
- pj_list_insert_before(&ioqueue->hlist, key);
- ++ioqueue->count;
-
-on_return:
- *p_key = key;
- pj_lock_release(ioqueue->lock);
-
- return rc;
-}
-
-/*
- * pj_ioqueue_unregister()
- *
- * Unregister handle from ioqueue.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key)
-{
- pj_ioqueue_t *ioqueue;
- struct epoll_event ev;
- int status;
-
- PJ_ASSERT_RETURN(key != NULL, PJ_EINVAL);
-
- ioqueue = key->ioqueue;
- pj_lock_acquire(ioqueue->lock);
-
- pj_assert(ioqueue->count > 0);
- --ioqueue->count;
- pj_list_erase(key);
-
- ev.events = 0;
- ev.epoll_data = (epoll_data_type)key;
- status = os_epoll_ctl( ioqueue->epfd, EPOLL_CTL_DEL, key->fd, &ev);
- if (status != 0) {
- pj_status_t rc = pj_get_os_error();
- pj_lock_release(ioqueue->lock);
- return rc;
- }
-
- pj_lock_release(ioqueue->lock);
-
- /* Destroy the key. */
- ioqueue_destroy_key(key);
-
- return PJ_SUCCESS;
-}
-
-/* ioqueue_remove_from_set()
- * This function is called from ioqueue_dispatch_event() to instruct
- * the ioqueue to remove the specified descriptor from ioqueue's descriptor
- * set for the specified event.
- */
-static void ioqueue_remove_from_set( pj_ioqueue_t *ioqueue,
- pj_sock_t fd,
- enum ioqueue_event_type event_type)
-{
-}
-
-/*
- * ioqueue_add_to_set()
- * This function is called from pj_ioqueue_recv(), pj_ioqueue_send() etc
- * to instruct the ioqueue to add the specified handle to ioqueue's descriptor
- * set for the specified event.
- */
-static void ioqueue_add_to_set( pj_ioqueue_t *ioqueue,
- pj_sock_t fd,
- enum ioqueue_event_type event_type )
-{
-}
-
-/*
- * pj_ioqueue_poll()
- *
- */
-PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioqueue, const pj_time_val *timeout)
-{
- int i, count, processed;
- struct epoll_event events[PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL];
- int msec;
- struct queue {
- pj_ioqueue_key_t *key;
- enum ioqueue_event_type event_type;
- } queue[PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL];
-
- PJ_CHECK_STACK();
-
- msec = timeout ? PJ_TIME_VAL_MSEC(*timeout) : 9000;
-
- count = os_epoll_wait( ioqueue->epfd, events, PJ_ARRAY_SIZE(events), msec);
- if (count <= 0)
- return count;
-
- /* Lock ioqueue. */
- pj_lock_acquire(ioqueue->lock);
-
- for (processed=0, i=0; i<count; ++i) {
- pj_ioqueue_key_t *h = (pj_ioqueue_key_t*)(epoll_data_type)
- events[i].epoll_data;
-
- /*
- * Check readability.
- */
- if ((events[i].events & EPOLLIN) &&
- (key_has_pending_read(h) || key_has_pending_accept(h))) {
- queue[processed].key = h;
- queue[processed].event_type = READABLE_EVENT;
- ++processed;
- }
-
- /*
- * Check for writeability.
- */
- if ((events[i].events & EPOLLOUT) && key_has_pending_write(h)) {
- queue[processed].key = h;
- queue[processed].event_type = WRITEABLE_EVENT;
- ++processed;
- }
-
-#if PJ_HAS_TCP
- /*
- * Check for completion of connect() operation.
- */
- if ((events[i].events & EPOLLOUT) && (h->connecting)) {
- queue[processed].key = h;
- queue[processed].event_type = WRITEABLE_EVENT;
- ++processed;
- }
-#endif /* PJ_HAS_TCP */
-
- /*
- * Check for error condition.
- */
- if (events[i].events & EPOLLERR && (h->connecting)) {
- queue[processed].key = h;
- queue[processed].event_type = EXCEPTION_EVENT;
- ++processed;
- }
- }
- pj_lock_release(ioqueue->lock);
-
- /* Now process the events. */
- for (i=0; i<processed; ++i) {
- switch (queue[i].event_type) {
- case READABLE_EVENT:
- ioqueue_dispatch_read_event(ioqueue, queue[i].key);
- break;
- case WRITEABLE_EVENT:
- ioqueue_dispatch_write_event(ioqueue, queue[i].key);
- break;
- case EXCEPTION_EVENT:
- ioqueue_dispatch_exception_event(ioqueue, queue[i].key);
- break;
- case NO_EVENT:
- pj_assert(!"Invalid event!");
- break;
- }
- }
-
- return processed;
-}
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*
+ * ioqueue_epoll.c
+ *
+ * This is the implementation of IOQueue framework using /dev/epoll
+ * API in _both_ Linux user-mode and kernel-mode.
+ */
+
+#include <pj/ioqueue.h>
+#include <pj/os.h>
+#include <pj/lock.h>
+#include <pj/log.h>
+#include <pj/list.h>
+#include <pj/pool.h>
+#include <pj/string.h>
+#include <pj/assert.h>
+#include <pj/errno.h>
+#include <pj/sock.h>
+#include <pj/compat/socket.h>
+
+#if !defined(PJ_LINUX_KERNEL) || PJ_LINUX_KERNEL==0
+ /*
+ * Linux user mode
+ */
+# include <sys/epoll.h>
+# include <errno.h>
+# include <unistd.h>
+
+# define epoll_data data.ptr
+# define epoll_data_type void*
+# define ioctl_val_type unsigned long
+# define getsockopt_val_ptr int*
+# define os_getsockopt getsockopt
+# define os_ioctl ioctl
+# define os_read read
+# define os_close close
+# define os_epoll_create epoll_create
+# define os_epoll_ctl epoll_ctl
+# define os_epoll_wait epoll_wait
+#else
+ /*
+ * Linux kernel mode.
+ */
+# include <linux/config.h>
+# include <linux/version.h>
+# if defined(MODVERSIONS)
+# include <linux/modversions.h>
+# endif
+# include <linux/kernel.h>
+# include <linux/poll.h>
+# include <linux/eventpoll.h>
+# include <linux/syscalls.h>
+# include <linux/errno.h>
+# include <linux/unistd.h>
+# include <asm/ioctls.h>
+ enum EPOLL_EVENTS
+ {
+ EPOLLIN = 0x001,
+ EPOLLOUT = 0x004,
+ EPOLLERR = 0x008,
+ };
+# define os_epoll_create sys_epoll_create
+ static int os_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
+ {
+ long rc;
+ mm_segment_t oldfs = get_fs();
+ set_fs(KERNEL_DS);
+ rc = sys_epoll_ctl(epfd, op, fd, event);
+ set_fs(oldfs);
+ if (rc) {
+ errno = -rc;
+ return -1;
+ } else {
+ return 0;
+ }
+ }
+ static int os_epoll_wait(int epfd, struct epoll_event *events,
+ int maxevents, int timeout)
+ {
+ int count;
+ mm_segment_t oldfs = get_fs();
+ set_fs(KERNEL_DS);
+ count = sys_epoll_wait(epfd, events, maxevents, timeout);
+ set_fs(oldfs);
+ return count;
+ }
+# define os_close sys_close
+# define os_getsockopt pj_sock_getsockopt
+ static int os_read(int fd, void *buf, size_t len)
+ {
+ long rc;
+ mm_segment_t oldfs = get_fs();
+ set_fs(KERNEL_DS);
+ rc = sys_read(fd, buf, len);
+ set_fs(oldfs);
+ if (rc) {
+ errno = -rc;
+ return -1;
+ } else {
+ return 0;
+ }
+ }
+# define socklen_t unsigned
+# define ioctl_val_type unsigned long
+ int ioctl(int fd, int opt, ioctl_val_type value);
+ static int os_ioctl(int fd, int opt, ioctl_val_type value)
+ {
+ int rc;
+ mm_segment_t oldfs = get_fs();
+ set_fs(KERNEL_DS);
+ rc = ioctl(fd, opt, value);
+ set_fs(oldfs);
+ if (rc < 0) {
+ errno = -rc;
+ return rc;
+ } else
+ return rc;
+ }
+# define getsockopt_val_ptr char*
+
+# define epoll_data data
+# define epoll_data_type __u32
+#endif
+
+#define THIS_FILE "ioq_epoll"
+
+//#define TRACE_(expr) PJ_LOG(3,expr)
+#define TRACE_(expr)
+
+/*
+ * Include common ioqueue abstraction.
+ */
+#include "ioqueue_common_abs.h"
+
+/*
+ * This describes each key.
+ */
+struct pj_ioqueue_key_t
+{
+ DECLARE_COMMON_KEY
+};
+
+/*
+ * This describes the I/O queue.
+ */
+struct pj_ioqueue_t
+{
+ DECLARE_COMMON_IOQUEUE
+
+ unsigned max, count;
+ pj_ioqueue_key_t hlist;
+ int epfd;
+};
+
+/* Include implementation for common abstraction after we declare
+ * pj_ioqueue_key_t and pj_ioqueue_t.
+ */
+#include "ioqueue_common_abs.c"
+
+/*
+ * pj_ioqueue_name()
+ */
+PJ_DEF(const char*) pj_ioqueue_name(void)
+{
+#if defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL!=0
+ return "epoll-kernel";
+#else
+ return "epoll";
+#endif
+}
+
+/*
+ * pj_ioqueue_create()
+ *
+ * Create select ioqueue.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool,
+ pj_size_t max_fd,
+ pj_ioqueue_t **p_ioqueue)
+{
+ pj_ioqueue_t *ioqueue;
+ pj_status_t rc;
+ pj_lock_t *lock;
+
+ /* Check that arguments are valid. */
+ PJ_ASSERT_RETURN(pool != NULL && p_ioqueue != NULL &&
+ max_fd > 0, PJ_EINVAL);
+
+ /* Check that size of pj_ioqueue_op_key_t is sufficient */
+ PJ_ASSERT_RETURN(sizeof(pj_ioqueue_op_key_t)-sizeof(void*) >=
+ sizeof(union operation_key), PJ_EBUG);
+
+ ioqueue = pj_pool_alloc(pool, sizeof(pj_ioqueue_t));
+
+ ioqueue_init(ioqueue);
+
+ ioqueue->max = max_fd;
+ ioqueue->count = 0;
+ pj_list_init(&ioqueue->hlist);
+
+ rc = pj_lock_create_simple_mutex(pool, "ioq%p", &lock);
+ if (rc != PJ_SUCCESS)
+ return rc;
+
+ rc = pj_ioqueue_set_lock(ioqueue, lock, PJ_TRUE);
+ if (rc != PJ_SUCCESS)
+ return rc;
+
+ ioqueue->epfd = os_epoll_create(max_fd);
+ if (ioqueue->epfd < 0) {
+ ioqueue_destroy(ioqueue);
+ return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
+ }
+
+ PJ_LOG(4, ("pjlib", "epoll I/O Queue created (%p)", ioqueue));
+
+ *p_ioqueue = ioqueue;
+ return PJ_SUCCESS;
+}
+
+/*
+ * pj_ioqueue_destroy()
+ *
+ * Destroy ioqueue.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioqueue)
+{
+ PJ_ASSERT_RETURN(ioqueue, PJ_EINVAL);
+ PJ_ASSERT_RETURN(ioqueue->epfd > 0, PJ_EINVALIDOP);
+
+ pj_lock_acquire(ioqueue->lock);
+ os_close(ioqueue->epfd);
+ ioqueue->epfd = 0;
+ return ioqueue_destroy(ioqueue);
+}
+
+/*
+ * pj_ioqueue_register_sock()
+ *
+ * Register a socket to ioqueue.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,
+ pj_ioqueue_t *ioqueue,
+ pj_sock_t sock,
+ void *user_data,
+ const pj_ioqueue_callback *cb,
+ pj_ioqueue_key_t **p_key)
+{
+ pj_ioqueue_key_t *key = NULL;
+ pj_uint32_t value;
+ struct epoll_event ev;
+ int status;
+ pj_status_t rc = PJ_SUCCESS;
+
+ PJ_ASSERT_RETURN(pool && ioqueue && sock != PJ_INVALID_SOCKET &&
+ cb && p_key, PJ_EINVAL);
+
+ pj_lock_acquire(ioqueue->lock);
+
+ if (ioqueue->count >= ioqueue->max) {
+ rc = PJ_ETOOMANY;
+ TRACE_((THIS_FILE, "pj_ioqueue_register_sock error: too many files"));
+ goto on_return;
+ }
+
+ /* Set socket to nonblocking. */
+ value = 1;
+ if ((rc=os_ioctl(sock, FIONBIO, (ioctl_val_type)&value))) {
+ TRACE_((THIS_FILE, "pj_ioqueue_register_sock error: ioctl rc=%d",
+ rc));
+ rc = pj_get_netos_error();
+ goto on_return;
+ }
+
+ /* Create key. */
+ key = (pj_ioqueue_key_t*)pj_pool_zalloc(pool, sizeof(pj_ioqueue_key_t));
+ rc = ioqueue_init_key(pool, ioqueue, key, sock, user_data, cb);
+ if (rc != PJ_SUCCESS) {
+ key = NULL;
+ goto on_return;
+ }
+
+ /* os_epoll_ctl. */
+ ev.events = EPOLLIN | EPOLLOUT | EPOLLERR;
+ ev.epoll_data = (epoll_data_type)key;
+ status = os_epoll_ctl(ioqueue->epfd, EPOLL_CTL_ADD, sock, &ev);
+ if (status < 0) {
+ rc = pj_get_os_error();
+ key = NULL;
+ TRACE_((THIS_FILE,
+ "pj_ioqueue_register_sock error: os_epoll_ctl rc=%d",
+ status));
+ goto on_return;
+ }
+
+ /* Register */
+ pj_list_insert_before(&ioqueue->hlist, key);
+ ++ioqueue->count;
+
+on_return:
+ *p_key = key;
+ pj_lock_release(ioqueue->lock);
+
+ return rc;
+}
+
+/*
+ * pj_ioqueue_unregister()
+ *
+ * Unregister handle from ioqueue.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key)
+{
+ pj_ioqueue_t *ioqueue;
+ struct epoll_event ev;
+ int status;
+
+ PJ_ASSERT_RETURN(key != NULL, PJ_EINVAL);
+
+ ioqueue = key->ioqueue;
+ pj_lock_acquire(ioqueue->lock);
+
+ pj_assert(ioqueue->count > 0);
+ --ioqueue->count;
+ pj_list_erase(key);
+
+ ev.events = 0;
+ ev.epoll_data = (epoll_data_type)key;
+ status = os_epoll_ctl( ioqueue->epfd, EPOLL_CTL_DEL, key->fd, &ev);
+ if (status != 0) {
+ pj_status_t rc = pj_get_os_error();
+ pj_lock_release(ioqueue->lock);
+ return rc;
+ }
+
+ pj_lock_release(ioqueue->lock);
+
+ /* Destroy the key. */
+ ioqueue_destroy_key(key);
+
+ return PJ_SUCCESS;
+}
+
+/* ioqueue_remove_from_set()
+ * This function is called from ioqueue_dispatch_event() to instruct
+ * the ioqueue to remove the specified descriptor from ioqueue's descriptor
+ * set for the specified event.
+ */
+static void ioqueue_remove_from_set( pj_ioqueue_t *ioqueue,
+ pj_sock_t fd,
+ enum ioqueue_event_type event_type)
+{
+}
+
+/*
+ * ioqueue_add_to_set()
+ * This function is called from pj_ioqueue_recv(), pj_ioqueue_send() etc
+ * to instruct the ioqueue to add the specified handle to ioqueue's descriptor
+ * set for the specified event.
+ */
+static void ioqueue_add_to_set( pj_ioqueue_t *ioqueue,
+ pj_sock_t fd,
+ enum ioqueue_event_type event_type )
+{
+}
+
+/*
+ * pj_ioqueue_poll()
+ *
+ */
+PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioqueue, const pj_time_val *timeout)
+{
+ int i, count, processed;
+ struct epoll_event events[PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL];
+ int msec;
+ struct queue {
+ pj_ioqueue_key_t *key;
+ enum ioqueue_event_type event_type;
+ } queue[PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL];
+
+ PJ_CHECK_STACK();
+
+ msec = timeout ? PJ_TIME_VAL_MSEC(*timeout) : 9000;
+
+ count = os_epoll_wait( ioqueue->epfd, events, PJ_ARRAY_SIZE(events), msec);
+ if (count <= 0)
+ return count;
+
+ /* Lock ioqueue. */
+ pj_lock_acquire(ioqueue->lock);
+
+ for (processed=0, i=0; i<count; ++i) {
+ pj_ioqueue_key_t *h = (pj_ioqueue_key_t*)(epoll_data_type)
+ events[i].epoll_data;
+
+ /*
+ * Check readability.
+ */
+ if ((events[i].events & EPOLLIN) &&
+ (key_has_pending_read(h) || key_has_pending_accept(h))) {
+ queue[processed].key = h;
+ queue[processed].event_type = READABLE_EVENT;
+ ++processed;
+ }
+
+ /*
+ * Check for writeability.
+ */
+ if ((events[i].events & EPOLLOUT) && key_has_pending_write(h)) {
+ queue[processed].key = h;
+ queue[processed].event_type = WRITEABLE_EVENT;
+ ++processed;
+ }
+
+#if PJ_HAS_TCP
+ /*
+ * Check for completion of connect() operation.
+ */
+ if ((events[i].events & EPOLLOUT) && (h->connecting)) {
+ queue[processed].key = h;
+ queue[processed].event_type = WRITEABLE_EVENT;
+ ++processed;
+ }
+#endif /* PJ_HAS_TCP */
+
+ /*
+ * Check for error condition.
+ */
+ if (events[i].events & EPOLLERR && (h->connecting)) {
+ queue[processed].key = h;
+ queue[processed].event_type = EXCEPTION_EVENT;
+ ++processed;
+ }
+ }
+ pj_lock_release(ioqueue->lock);
+
+ /* Now process the events. */
+ for (i=0; i<processed; ++i) {
+ switch (queue[i].event_type) {
+ case READABLE_EVENT:
+ ioqueue_dispatch_read_event(ioqueue, queue[i].key);
+ break;
+ case WRITEABLE_EVENT:
+ ioqueue_dispatch_write_event(ioqueue, queue[i].key);
+ break;
+ case EXCEPTION_EVENT:
+ ioqueue_dispatch_exception_event(ioqueue, queue[i].key);
+ break;
+ case NO_EVENT:
+ pj_assert(!"Invalid event!");
+ break;
+ }
+ }
+
+ return processed;
+}
+
diff --git a/pjlib/src/pj/ioqueue_linux_kernel.c b/pjlib/src/pj/ioqueue_linux_kernel.c
index 9ac8dda3..deaca1ea 100644
--- a/pjlib/src/pj/ioqueue_linux_kernel.c
+++ b/pjlib/src/pj/ioqueue_linux_kernel.c
@@ -1,146 +1,167 @@
-/* $Id$
- *
- */
-#include <pj/ioqueue.h>
-#include <pj/os.h>
-#include <pj/log.h>
-#include <pj/list.h>
-#include <pj/pool.h>
-#include <pj/string.h>
-#include <pj/assert.h>
-#include <pj/sock.h>
-
-#define THIS_FILE "ioqueue"
-
-#define PJ_IOQUEUE_IS_READ_OP(op) \
- ((op & PJ_IOQUEUE_OP_READ) || (op & PJ_IOQUEUE_OP_RECV_FROM))
-#define PJ_IOQUEUE_IS_WRITE_OP(op) \
- ((op & PJ_IOQUEUE_OP_WRITE) || (op & PJ_IOQUEUE_OP_SEND_TO))
-
-
-#if PJ_HAS_TCP
-# define PJ_IOQUEUE_IS_ACCEPT_OP(op) (op & PJ_IOQUEUE_OP_ACCEPT)
-# define PJ_IOQUEUE_IS_CONNECT_OP(op) (op & PJ_IOQUEUE_OP_CONNECT)
-#else
-# define PJ_IOQUEUE_IS_ACCEPT_OP(op) 0
-# define PJ_IOQUEUE_IS_CONNECT_OP(op) 0
-#endif
-
-#if defined(PJ_DEBUG) && PJ_DEBUG != 0
-# define VALIDATE_FD_SET 1
-#else
-# define VALIDATE_FD_SET 0
-#endif
-
-struct pj_ioqueue_key_t
-{
- PJ_DECL_LIST_MEMBER(struct pj_ioqueue_key_t)
- pj_sock_t fd;
- pj_ioqueue_operation_e op;
- void *user_data;
- pj_ioqueue_callback cb;
-};
-
-struct pj_ioqueue_t
-{
-};
-
-PJ_DEF(pj_ioqueue_t*) pj_ioqueue_create(pj_pool_t *pool, pj_size_t max_fd)
-{
- return NULL;
-}
-
-PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioque)
-{
- return 0;
-}
-
-PJ_DEF(pj_ioqueue_key_t*) pj_ioqueue_register( pj_pool_t *pool,
- pj_ioqueue_t *ioque,
- pj_oshandle_t sock,
- void *user_data,
- const pj_ioqueue_callback *cb)
-{
- return NULL;
-}
-
-PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_t *ioque,
- pj_ioqueue_key_t *key)
-{
- return -1;
-}
-
-PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key )
-{
- return NULL;
-}
-
-
-PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioque, const pj_time_val *timeout)
-{
- return -1;
-}
-
-PJ_DEF(int) pj_ioqueue_read( pj_ioqueue_t *ioque,
- pj_ioqueue_key_t *key,
- void *buffer,
- pj_size_t buflen)
-{
- return -1;
-}
-
-PJ_DEF(int) pj_ioqueue_recvfrom( pj_ioqueue_t *ioque,
- pj_ioqueue_key_t *key,
- void *buffer,
- pj_size_t buflen,
- pj_sockaddr_t *addr,
- int *addrlen)
-{
- return -1;
-}
-
-PJ_DEF(int) pj_ioqueue_write( pj_ioqueue_t *ioque,
- pj_ioqueue_key_t *key,
- const void *data,
- pj_size_t datalen)
-{
- return -1;
-}
-
-PJ_DEF(int) pj_ioqueue_sendto( pj_ioqueue_t *ioque,
- pj_ioqueue_key_t *key,
- const void *data,
- pj_size_t datalen,
- const pj_sockaddr_t *addr,
- int addrlen)
-{
- return -1;
-}
-
-#if PJ_HAS_TCP
-/*
- * Initiate overlapped accept() operation.
- */
-PJ_DEF(int) pj_ioqueue_accept( pj_ioqueue_t *ioqueue,
- pj_ioqueue_key_t *key,
- pj_sock_t *new_sock,
- pj_sockaddr_t *local,
- pj_sockaddr_t *remote,
- int *addrlen)
-{
- return -1;
-}
-
-/*
- * Initiate overlapped connect() operation (well, it's non-blocking actually,
- * since there's no overlapped version of connect()).
- */
-PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_t *ioqueue,
- pj_ioqueue_key_t *key,
- const pj_sockaddr_t *addr,
- int addrlen )
-{
- return -1;
-}
-#endif /* PJ_HAS_TCP */
-
+/* $Id$
+ *
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/ioqueue.h>
+#include <pj/os.h>
+#include <pj/log.h>
+#include <pj/list.h>
+#include <pj/pool.h>
+#include <pj/string.h>
+#include <pj/assert.h>
+#include <pj/sock.h>
+
+#define THIS_FILE "ioqueue"
+
+#define PJ_IOQUEUE_IS_READ_OP(op) \
+ ((op & PJ_IOQUEUE_OP_READ) || (op & PJ_IOQUEUE_OP_RECV_FROM))
+#define PJ_IOQUEUE_IS_WRITE_OP(op) \
+ ((op & PJ_IOQUEUE_OP_WRITE) || (op & PJ_IOQUEUE_OP_SEND_TO))
+
+
+#if PJ_HAS_TCP
+# define PJ_IOQUEUE_IS_ACCEPT_OP(op) (op & PJ_IOQUEUE_OP_ACCEPT)
+# define PJ_IOQUEUE_IS_CONNECT_OP(op) (op & PJ_IOQUEUE_OP_CONNECT)
+#else
+# define PJ_IOQUEUE_IS_ACCEPT_OP(op) 0
+# define PJ_IOQUEUE_IS_CONNECT_OP(op) 0
+#endif
+
+#if defined(PJ_DEBUG) && PJ_DEBUG != 0
+# define VALIDATE_FD_SET 1
+#else
+# define VALIDATE_FD_SET 0
+#endif
+
+struct pj_ioqueue_key_t
+{
+ PJ_DECL_LIST_MEMBER(struct pj_ioqueue_key_t)
+ pj_sock_t fd;
+ pj_ioqueue_operation_e op;
+ void *user_data;
+ pj_ioqueue_callback cb;
+};
+
+struct pj_ioqueue_t
+{
+};
+
+PJ_DEF(pj_ioqueue_t*) pj_ioqueue_create(pj_pool_t *pool, pj_size_t max_fd)
+{
+ return NULL;
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioque)
+{
+ return 0;
+}
+
+PJ_DEF(pj_ioqueue_key_t*) pj_ioqueue_register( pj_pool_t *pool,
+ pj_ioqueue_t *ioque,
+ pj_oshandle_t sock,
+ void *user_data,
+ const pj_ioqueue_callback *cb)
+{
+ return NULL;
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_t *ioque,
+ pj_ioqueue_key_t *key)
+{
+ return -1;
+}
+
+PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key )
+{
+ return NULL;
+}
+
+
+PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioque, const pj_time_val *timeout)
+{
+ return -1;
+}
+
+PJ_DEF(int) pj_ioqueue_read( pj_ioqueue_t *ioque,
+ pj_ioqueue_key_t *key,
+ void *buffer,
+ pj_size_t buflen)
+{
+ return -1;
+}
+
+PJ_DEF(int) pj_ioqueue_recvfrom( pj_ioqueue_t *ioque,
+ pj_ioqueue_key_t *key,
+ void *buffer,
+ pj_size_t buflen,
+ pj_sockaddr_t *addr,
+ int *addrlen)
+{
+ return -1;
+}
+
+PJ_DEF(int) pj_ioqueue_write( pj_ioqueue_t *ioque,
+ pj_ioqueue_key_t *key,
+ const void *data,
+ pj_size_t datalen)
+{
+ return -1;
+}
+
+PJ_DEF(int) pj_ioqueue_sendto( pj_ioqueue_t *ioque,
+ pj_ioqueue_key_t *key,
+ const void *data,
+ pj_size_t datalen,
+ const pj_sockaddr_t *addr,
+ int addrlen)
+{
+ return -1;
+}
+
+#if PJ_HAS_TCP
+/*
+ * Initiate overlapped accept() operation.
+ */
+PJ_DEF(int) pj_ioqueue_accept( pj_ioqueue_t *ioqueue,
+ pj_ioqueue_key_t *key,
+ pj_sock_t *new_sock,
+ pj_sockaddr_t *local,
+ pj_sockaddr_t *remote,
+ int *addrlen)
+{
+ return -1;
+}
+
+/*
+ * Initiate overlapped connect() operation (well, it's non-blocking actually,
+ * since there's no overlapped version of connect()).
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_t *ioqueue,
+ pj_ioqueue_key_t *key,
+ const pj_sockaddr_t *addr,
+ int addrlen )
+{
+ return -1;
+}
+#endif /* PJ_HAS_TCP */
+
diff --git a/pjlib/src/pj/ioqueue_select.c b/pjlib/src/pj/ioqueue_select.c
index 09318d4e..de1e97c9 100644
--- a/pjlib/src/pj/ioqueue_select.c
+++ b/pjlib/src/pj/ioqueue_select.c
@@ -1,514 +1,535 @@
-/* $Id$
- */
-/*
- * sock_select.c
- *
- * This is the implementation of IOQueue using pj_sock_select().
- * It runs anywhere where pj_sock_select() is available (currently
- * Win32, Linux, Linux kernel, etc.).
- */
-
-#include <pj/ioqueue.h>
-#include <pj/os.h>
-#include <pj/lock.h>
-#include <pj/log.h>
-#include <pj/list.h>
-#include <pj/pool.h>
-#include <pj/string.h>
-#include <pj/assert.h>
-#include <pj/sock.h>
-#include <pj/compat/socket.h>
-#include <pj/sock_select.h>
-#include <pj/errno.h>
-
-/*
- * Include declaration from common abstraction.
- */
-#include "ioqueue_common_abs.h"
-
-/*
- * ISSUES with ioqueue_select()
- *
- * EAGAIN/EWOULDBLOCK error in recv():
- * - when multiple threads are working with the ioqueue, application
- * may receive EAGAIN or EWOULDBLOCK in the receive callback.
- * This error happens because more than one thread is watching for
- * the same descriptor set, so when all of them call recv() or recvfrom()
- * simultaneously, only one will succeed and the rest will get the error.
- *
- */
-#define THIS_FILE "ioq_select"
-
-/*
- * The select ioqueue relies on socket functions (pj_sock_xxx()) to return
- * the correct error code.
- */
-#if PJ_RETURN_OS_ERROR(100) != PJ_STATUS_FROM_OS(100)
-# error "Error reporting must be enabled for this function to work!"
-#endif
-
-/**
- * Get the number of descriptors in the set. This is defined in sock_select.c
- * This function will only return the number of sockets set from PJ_FD_SET
- * operation. When the set is modified by other means (such as by select()),
- * the count will not be reflected here.
- *
- * That's why don't export this function in the header file, to avoid
- * misunderstanding.
- *
- * @param fdsetp The descriptor set.
- *
- * @return Number of descriptors in the set.
- */
-PJ_DECL(pj_size_t) PJ_FD_COUNT(const pj_fd_set_t *fdsetp);
-
-
-/*
- * During debugging build, VALIDATE_FD_SET is set.
- * This will check the validity of the fd_sets.
- */
-/*
-#if defined(PJ_DEBUG) && PJ_DEBUG != 0
-# define VALIDATE_FD_SET 1
-#else
-# define VALIDATE_FD_SET 0
-#endif
-*/
-#define VALIDATE_FD_SET 0
-
-/*
- * This describes each key.
- */
-struct pj_ioqueue_key_t
-{
- DECLARE_COMMON_KEY
-};
-
-/*
- * This describes the I/O queue itself.
- */
-struct pj_ioqueue_t
-{
- DECLARE_COMMON_IOQUEUE
-
- unsigned max, count;
- pj_ioqueue_key_t key_list;
- pj_fd_set_t rfdset;
- pj_fd_set_t wfdset;
-#if PJ_HAS_TCP
- pj_fd_set_t xfdset;
-#endif
-};
-
-/* Include implementation for common abstraction after we declare
- * pj_ioqueue_key_t and pj_ioqueue_t.
- */
-#include "ioqueue_common_abs.c"
-
-/*
- * pj_ioqueue_name()
- */
-PJ_DEF(const char*) pj_ioqueue_name(void)
-{
- return "select";
-}
-
-/*
- * pj_ioqueue_create()
- *
- * Create select ioqueue.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool,
- pj_size_t max_fd,
- pj_ioqueue_t **p_ioqueue)
-{
- pj_ioqueue_t *ioqueue;
- pj_lock_t *lock;
- pj_status_t rc;
-
- /* Check that arguments are valid. */
- PJ_ASSERT_RETURN(pool != NULL && p_ioqueue != NULL &&
- max_fd > 0 && max_fd <= PJ_IOQUEUE_MAX_HANDLES,
- PJ_EINVAL);
-
- /* Check that size of pj_ioqueue_op_key_t is sufficient */
- PJ_ASSERT_RETURN(sizeof(pj_ioqueue_op_key_t)-sizeof(void*) >=
- sizeof(union operation_key), PJ_EBUG);
-
- ioqueue = pj_pool_alloc(pool, sizeof(pj_ioqueue_t));
-
- ioqueue_init(ioqueue);
-
- ioqueue->max = max_fd;
- ioqueue->count = 0;
- PJ_FD_ZERO(&ioqueue->rfdset);
- PJ_FD_ZERO(&ioqueue->wfdset);
-#if PJ_HAS_TCP
- PJ_FD_ZERO(&ioqueue->xfdset);
-#endif
- pj_list_init(&ioqueue->key_list);
-
- rc = pj_lock_create_simple_mutex(pool, "ioq%p", &lock);
- if (rc != PJ_SUCCESS)
- return rc;
-
- rc = pj_ioqueue_set_lock(ioqueue, lock, PJ_TRUE);
- if (rc != PJ_SUCCESS)
- return rc;
-
- PJ_LOG(4, ("pjlib", "select() I/O Queue created (%p)", ioqueue));
-
- *p_ioqueue = ioqueue;
- return PJ_SUCCESS;
-}
-
-/*
- * pj_ioqueue_destroy()
- *
- * Destroy ioqueue.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioqueue)
-{
- PJ_ASSERT_RETURN(ioqueue, PJ_EINVAL);
-
- pj_lock_acquire(ioqueue->lock);
- return ioqueue_destroy(ioqueue);
-}
-
-
-/*
- * pj_ioqueue_register_sock()
- *
- * Register a handle to ioqueue.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,
- pj_ioqueue_t *ioqueue,
- pj_sock_t sock,
- void *user_data,
- const pj_ioqueue_callback *cb,
- pj_ioqueue_key_t **p_key)
-{
- pj_ioqueue_key_t *key = NULL;
- pj_uint32_t value;
- pj_status_t rc = PJ_SUCCESS;
-
- PJ_ASSERT_RETURN(pool && ioqueue && sock != PJ_INVALID_SOCKET &&
- cb && p_key, PJ_EINVAL);
-
- pj_lock_acquire(ioqueue->lock);
-
- if (ioqueue->count >= ioqueue->max) {
- rc = PJ_ETOOMANY;
- goto on_return;
- }
-
- /* Set socket to nonblocking. */
- value = 1;
-#ifdef PJ_WIN32
- if (ioctlsocket(sock, FIONBIO, (u_long*)&value)) {
-#else
- if (ioctl(sock, FIONBIO, &value)) {
-#endif
- rc = pj_get_netos_error();
- goto on_return;
- }
-
- /* Create key. */
- key = (pj_ioqueue_key_t*)pj_pool_zalloc(pool, sizeof(pj_ioqueue_key_t));
- rc = ioqueue_init_key(pool, ioqueue, key, sock, user_data, cb);
- if (rc != PJ_SUCCESS) {
- key = NULL;
- goto on_return;
- }
-
- /* Register */
- pj_list_insert_before(&ioqueue->key_list, key);
- ++ioqueue->count;
-
-on_return:
- /* On error, socket may be left in non-blocking mode. */
- *p_key = key;
- pj_lock_release(ioqueue->lock);
-
- return rc;
-}
-
-/*
- * pj_ioqueue_unregister()
- *
- * Unregister handle from ioqueue.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key)
-{
- pj_ioqueue_t *ioqueue;
-
- PJ_ASSERT_RETURN(key, PJ_EINVAL);
-
- ioqueue = key->ioqueue;
-
- pj_lock_acquire(ioqueue->lock);
-
- pj_assert(ioqueue->count > 0);
- --ioqueue->count;
- pj_list_erase(key);
- PJ_FD_CLR(key->fd, &ioqueue->rfdset);
- PJ_FD_CLR(key->fd, &ioqueue->wfdset);
-#if PJ_HAS_TCP
- PJ_FD_CLR(key->fd, &ioqueue->xfdset);
-#endif
-
- /* ioqueue_destroy may try to acquire key's mutex.
- * Since normally the order of locking is to lock key's mutex first
- * then ioqueue's mutex, ioqueue_destroy may deadlock unless we
- * release ioqueue's mutex first.
- */
- pj_lock_release(ioqueue->lock);
-
- /* Destroy the key. */
- ioqueue_destroy_key(key);
-
- return PJ_SUCCESS;
-}
-
-
-/* This supposed to check whether the fd_set values are consistent
- * with the operation currently set in each key.
- */
-#if VALIDATE_FD_SET
-static void validate_sets(const pj_ioqueue_t *ioqueue,
- const pj_fd_set_t *rfdset,
- const pj_fd_set_t *wfdset,
- const pj_fd_set_t *xfdset)
-{
- pj_ioqueue_key_t *key;
-
- /*
- * This basicly would not work anymore.
- * We need to lock key before performing the check, but we can't do
- * so because we're holding ioqueue mutex. If we acquire key's mutex
- * now, the will cause deadlock.
- */
- pj_assert(0);
-
- key = ioqueue->key_list.next;
- while (key != &ioqueue->key_list) {
- if (!pj_list_empty(&key->read_list)
-#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
- || !pj_list_empty(&key->accept_list)
-#endif
- )
- {
- pj_assert(PJ_FD_ISSET(key->fd, rfdset));
- }
- else {
- pj_assert(PJ_FD_ISSET(key->fd, rfdset) == 0);
- }
- if (!pj_list_empty(&key->write_list)
-#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
- || key->connecting
-#endif
- )
- {
- pj_assert(PJ_FD_ISSET(key->fd, wfdset));
- }
- else {
- pj_assert(PJ_FD_ISSET(key->fd, wfdset) == 0);
- }
-#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
- if (key->connecting)
- {
- pj_assert(PJ_FD_ISSET(key->fd, xfdset));
- }
- else {
- pj_assert(PJ_FD_ISSET(key->fd, xfdset) == 0);
- }
-#endif /* PJ_HAS_TCP */
-
- key = key->next;
- }
-}
-#endif /* VALIDATE_FD_SET */
-
-
-/* ioqueue_remove_from_set()
- * This function is called from ioqueue_dispatch_event() to instruct
- * the ioqueue to remove the specified descriptor from ioqueue's descriptor
- * set for the specified event.
- */
-static void ioqueue_remove_from_set( pj_ioqueue_t *ioqueue,
- pj_sock_t fd,
- enum ioqueue_event_type event_type)
-{
- pj_lock_acquire(ioqueue->lock);
-
- if (event_type == READABLE_EVENT)
- PJ_FD_CLR((pj_sock_t)fd, &ioqueue->rfdset);
- else if (event_type == WRITEABLE_EVENT)
- PJ_FD_CLR((pj_sock_t)fd, &ioqueue->wfdset);
- else if (event_type == EXCEPTION_EVENT)
- PJ_FD_CLR((pj_sock_t)fd, &ioqueue->xfdset);
- else
- pj_assert(0);
-
- pj_lock_release(ioqueue->lock);
-}
-
-/*
- * ioqueue_add_to_set()
- * This function is called from pj_ioqueue_recv(), pj_ioqueue_send() etc
- * to instruct the ioqueue to add the specified handle to ioqueue's descriptor
- * set for the specified event.
- */
-static void ioqueue_add_to_set( pj_ioqueue_t *ioqueue,
- pj_sock_t fd,
- enum ioqueue_event_type event_type )
-{
- pj_lock_acquire(ioqueue->lock);
-
- if (event_type == READABLE_EVENT)
- PJ_FD_SET((pj_sock_t)fd, &ioqueue->rfdset);
- else if (event_type == WRITEABLE_EVENT)
- PJ_FD_SET((pj_sock_t)fd, &ioqueue->wfdset);
- else if (event_type == EXCEPTION_EVENT)
- PJ_FD_SET((pj_sock_t)fd, &ioqueue->xfdset);
- else
- pj_assert(0);
-
- pj_lock_release(ioqueue->lock);
-}
-
-/*
- * pj_ioqueue_poll()
- *
- * Few things worth written:
- *
- * - we used to do only one callback called per poll, but it didn't go
- * very well. The reason is because on some situation, the write
- * callback gets called all the time, thus doesn't give the read
- * callback to get called. This happens, for example, when user
- * submit write operation inside the write callback.
- * As the result, we changed the behaviour so that now multiple
- * callbacks are called in a single poll. It should be fast too,
- * just that we need to be carefull with the ioqueue data structs.
- *
- * - to guarantee preemptiveness etc, the poll function must strictly
- * work on fd_set copy of the ioqueue (not the original one).
- */
-PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioqueue, const pj_time_val *timeout)
-{
- pj_fd_set_t rfdset, wfdset, xfdset;
- int count, counter;
- pj_ioqueue_key_t *h;
- struct event
- {
- pj_ioqueue_key_t *key;
- enum ioqueue_event_type event_type;
- } event[PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL];
-
- PJ_ASSERT_RETURN(ioqueue, PJ_EINVAL);
-
- /* Lock ioqueue before making fd_set copies */
- pj_lock_acquire(ioqueue->lock);
-
- /* We will only do select() when there are sockets to be polled.
- * Otherwise select() will return error.
- */
- if (PJ_FD_COUNT(&ioqueue->rfdset)==0 &&
- PJ_FD_COUNT(&ioqueue->wfdset)==0 &&
- PJ_FD_COUNT(&ioqueue->xfdset)==0)
- {
- pj_lock_release(ioqueue->lock);
- if (timeout)
- pj_thread_sleep(PJ_TIME_VAL_MSEC(*timeout));
- return 0;
- }
-
- /* Copy ioqueue's pj_fd_set_t to local variables. */
- pj_memcpy(&rfdset, &ioqueue->rfdset, sizeof(pj_fd_set_t));
- pj_memcpy(&wfdset, &ioqueue->wfdset, sizeof(pj_fd_set_t));
-#if PJ_HAS_TCP
- pj_memcpy(&xfdset, &ioqueue->xfdset, sizeof(pj_fd_set_t));
-#else
- PJ_FD_ZERO(&xfdset);
-#endif
-
-#if VALIDATE_FD_SET
- validate_sets(ioqueue, &rfdset, &wfdset, &xfdset);
-#endif
-
- /* Unlock ioqueue before select(). */
- pj_lock_release(ioqueue->lock);
-
- count = pj_sock_select(FD_SETSIZE, &rfdset, &wfdset, &xfdset, timeout);
-
- if (count <= 0)
- return count;
- else if (count > PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL)
- count = PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL;
-
- /* Scan descriptor sets for event and add the events in the event
- * array to be processed later in this function. We do this so that
- * events can be processed in parallel without holding ioqueue lock.
- */
- pj_lock_acquire(ioqueue->lock);
-
- counter = 0;
-
- /* Scan for writable sockets first to handle piggy-back data
- * coming with accept().
- */
- h = ioqueue->key_list.next;
- for ( ; h!=&ioqueue->key_list && counter<count; h = h->next) {
- if ( (key_has_pending_write(h) || key_has_pending_connect(h))
- && PJ_FD_ISSET(h->fd, &wfdset))
- {
- event[counter].key = h;
- event[counter].event_type = WRITEABLE_EVENT;
- ++counter;
- }
-
- /* Scan for readable socket. */
- if ((key_has_pending_read(h) || key_has_pending_accept(h))
- && PJ_FD_ISSET(h->fd, &rfdset))
- {
- event[counter].key = h;
- event[counter].event_type = READABLE_EVENT;
- ++counter;
- }
-
-#if PJ_HAS_TCP
- if (key_has_pending_connect(h) && PJ_FD_ISSET(h->fd, &xfdset)) {
- event[counter].key = h;
- event[counter].event_type = EXCEPTION_EVENT;
- ++counter;
- }
-#endif
- }
-
- pj_lock_release(ioqueue->lock);
-
- count = counter;
-
- /* Now process all events. The dispatch functions will take care
- * of locking in each of the key
- */
- for (counter=0; counter<count; ++counter) {
- switch (event[counter].event_type) {
- case READABLE_EVENT:
- ioqueue_dispatch_read_event(ioqueue, event[counter].key);
- break;
- case WRITEABLE_EVENT:
- ioqueue_dispatch_write_event(ioqueue, event[counter].key);
- break;
- case EXCEPTION_EVENT:
- ioqueue_dispatch_exception_event(ioqueue, event[counter].key);
- break;
- case NO_EVENT:
- pj_assert(!"Invalid event!");
- break;
- }
- }
-
- return count;
-}
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*
+ * sock_select.c
+ *
+ * This is the implementation of IOQueue using pj_sock_select().
+ * It runs anywhere where pj_sock_select() is available (currently
+ * Win32, Linux, Linux kernel, etc.).
+ */
+
+#include <pj/ioqueue.h>
+#include <pj/os.h>
+#include <pj/lock.h>
+#include <pj/log.h>
+#include <pj/list.h>
+#include <pj/pool.h>
+#include <pj/string.h>
+#include <pj/assert.h>
+#include <pj/sock.h>
+#include <pj/compat/socket.h>
+#include <pj/sock_select.h>
+#include <pj/errno.h>
+
+/*
+ * Include declaration from common abstraction.
+ */
+#include "ioqueue_common_abs.h"
+
+/*
+ * ISSUES with ioqueue_select()
+ *
+ * EAGAIN/EWOULDBLOCK error in recv():
+ * - when multiple threads are working with the ioqueue, application
+ * may receive EAGAIN or EWOULDBLOCK in the receive callback.
+ * This error happens because more than one thread is watching for
+ * the same descriptor set, so when all of them call recv() or recvfrom()
+ * simultaneously, only one will succeed and the rest will get the error.
+ *
+ */
+#define THIS_FILE "ioq_select"
+
+/*
+ * The select ioqueue relies on socket functions (pj_sock_xxx()) to return
+ * the correct error code.
+ */
+#if PJ_RETURN_OS_ERROR(100) != PJ_STATUS_FROM_OS(100)
+# error "Error reporting must be enabled for this function to work!"
+#endif
+
+/**
+ * Get the number of descriptors in the set. This is defined in sock_select.c
+ * This function will only return the number of sockets set from PJ_FD_SET
+ * operation. When the set is modified by other means (such as by select()),
+ * the count will not be reflected here.
+ *
+ * That's why don't export this function in the header file, to avoid
+ * misunderstanding.
+ *
+ * @param fdsetp The descriptor set.
+ *
+ * @return Number of descriptors in the set.
+ */
+PJ_DECL(pj_size_t) PJ_FD_COUNT(const pj_fd_set_t *fdsetp);
+
+
+/*
+ * During debugging build, VALIDATE_FD_SET is set.
+ * This will check the validity of the fd_sets.
+ */
+/*
+#if defined(PJ_DEBUG) && PJ_DEBUG != 0
+# define VALIDATE_FD_SET 1
+#else
+# define VALIDATE_FD_SET 0
+#endif
+*/
+#define VALIDATE_FD_SET 0
+
+/*
+ * This describes each key.
+ */
+struct pj_ioqueue_key_t
+{
+ DECLARE_COMMON_KEY
+};
+
+/*
+ * This describes the I/O queue itself.
+ */
+struct pj_ioqueue_t
+{
+ DECLARE_COMMON_IOQUEUE
+
+ unsigned max, count;
+ pj_ioqueue_key_t key_list;
+ pj_fd_set_t rfdset;
+ pj_fd_set_t wfdset;
+#if PJ_HAS_TCP
+ pj_fd_set_t xfdset;
+#endif
+};
+
+/* Include implementation for common abstraction after we declare
+ * pj_ioqueue_key_t and pj_ioqueue_t.
+ */
+#include "ioqueue_common_abs.c"
+
+/*
+ * pj_ioqueue_name()
+ */
+PJ_DEF(const char*) pj_ioqueue_name(void)
+{
+ return "select";
+}
+
+/*
+ * pj_ioqueue_create()
+ *
+ * Create select ioqueue.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool,
+ pj_size_t max_fd,
+ pj_ioqueue_t **p_ioqueue)
+{
+ pj_ioqueue_t *ioqueue;
+ pj_lock_t *lock;
+ pj_status_t rc;
+
+ /* Check that arguments are valid. */
+ PJ_ASSERT_RETURN(pool != NULL && p_ioqueue != NULL &&
+ max_fd > 0 && max_fd <= PJ_IOQUEUE_MAX_HANDLES,
+ PJ_EINVAL);
+
+ /* Check that size of pj_ioqueue_op_key_t is sufficient */
+ PJ_ASSERT_RETURN(sizeof(pj_ioqueue_op_key_t)-sizeof(void*) >=
+ sizeof(union operation_key), PJ_EBUG);
+
+ ioqueue = pj_pool_alloc(pool, sizeof(pj_ioqueue_t));
+
+ ioqueue_init(ioqueue);
+
+ ioqueue->max = max_fd;
+ ioqueue->count = 0;
+ PJ_FD_ZERO(&ioqueue->rfdset);
+ PJ_FD_ZERO(&ioqueue->wfdset);
+#if PJ_HAS_TCP
+ PJ_FD_ZERO(&ioqueue->xfdset);
+#endif
+ pj_list_init(&ioqueue->key_list);
+
+ rc = pj_lock_create_simple_mutex(pool, "ioq%p", &lock);
+ if (rc != PJ_SUCCESS)
+ return rc;
+
+ rc = pj_ioqueue_set_lock(ioqueue, lock, PJ_TRUE);
+ if (rc != PJ_SUCCESS)
+ return rc;
+
+ PJ_LOG(4, ("pjlib", "select() I/O Queue created (%p)", ioqueue));
+
+ *p_ioqueue = ioqueue;
+ return PJ_SUCCESS;
+}
+
+/*
+ * pj_ioqueue_destroy()
+ *
+ * Destroy ioqueue.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioqueue)
+{
+ PJ_ASSERT_RETURN(ioqueue, PJ_EINVAL);
+
+ pj_lock_acquire(ioqueue->lock);
+ return ioqueue_destroy(ioqueue);
+}
+
+
+/*
+ * pj_ioqueue_register_sock()
+ *
+ * Register a handle to ioqueue.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,
+ pj_ioqueue_t *ioqueue,
+ pj_sock_t sock,
+ void *user_data,
+ const pj_ioqueue_callback *cb,
+ pj_ioqueue_key_t **p_key)
+{
+ pj_ioqueue_key_t *key = NULL;
+ pj_uint32_t value;
+ pj_status_t rc = PJ_SUCCESS;
+
+ PJ_ASSERT_RETURN(pool && ioqueue && sock != PJ_INVALID_SOCKET &&
+ cb && p_key, PJ_EINVAL);
+
+ pj_lock_acquire(ioqueue->lock);
+
+ if (ioqueue->count >= ioqueue->max) {
+ rc = PJ_ETOOMANY;
+ goto on_return;
+ }
+
+ /* Set socket to nonblocking. */
+ value = 1;
+#ifdef PJ_WIN32
+ if (ioctlsocket(sock, FIONBIO, (u_long*)&value)) {
+#else
+ if (ioctl(sock, FIONBIO, &value)) {
+#endif
+ rc = pj_get_netos_error();
+ goto on_return;
+ }
+
+ /* Create key. */
+ key = (pj_ioqueue_key_t*)pj_pool_zalloc(pool, sizeof(pj_ioqueue_key_t));
+ rc = ioqueue_init_key(pool, ioqueue, key, sock, user_data, cb);
+ if (rc != PJ_SUCCESS) {
+ key = NULL;
+ goto on_return;
+ }
+
+ /* Register */
+ pj_list_insert_before(&ioqueue->key_list, key);
+ ++ioqueue->count;
+
+on_return:
+ /* On error, socket may be left in non-blocking mode. */
+ *p_key = key;
+ pj_lock_release(ioqueue->lock);
+
+ return rc;
+}
+
+/*
+ * pj_ioqueue_unregister()
+ *
+ * Unregister handle from ioqueue.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key)
+{
+ pj_ioqueue_t *ioqueue;
+
+ PJ_ASSERT_RETURN(key, PJ_EINVAL);
+
+ ioqueue = key->ioqueue;
+
+ pj_lock_acquire(ioqueue->lock);
+
+ pj_assert(ioqueue->count > 0);
+ --ioqueue->count;
+ pj_list_erase(key);
+ PJ_FD_CLR(key->fd, &ioqueue->rfdset);
+ PJ_FD_CLR(key->fd, &ioqueue->wfdset);
+#if PJ_HAS_TCP
+ PJ_FD_CLR(key->fd, &ioqueue->xfdset);
+#endif
+
+ /* ioqueue_destroy may try to acquire key's mutex.
+ * Since normally the order of locking is to lock key's mutex first
+ * then ioqueue's mutex, ioqueue_destroy may deadlock unless we
+ * release ioqueue's mutex first.
+ */
+ pj_lock_release(ioqueue->lock);
+
+ /* Destroy the key. */
+ ioqueue_destroy_key(key);
+
+ return PJ_SUCCESS;
+}
+
+
+/* This supposed to check whether the fd_set values are consistent
+ * with the operation currently set in each key.
+ */
+#if VALIDATE_FD_SET
+static void validate_sets(const pj_ioqueue_t *ioqueue,
+ const pj_fd_set_t *rfdset,
+ const pj_fd_set_t *wfdset,
+ const pj_fd_set_t *xfdset)
+{
+ pj_ioqueue_key_t *key;
+
+ /*
+ * This basicly would not work anymore.
+ * We need to lock key before performing the check, but we can't do
+ * so because we're holding ioqueue mutex. If we acquire key's mutex
+ * now, the will cause deadlock.
+ */
+ pj_assert(0);
+
+ key = ioqueue->key_list.next;
+ while (key != &ioqueue->key_list) {
+ if (!pj_list_empty(&key->read_list)
+#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
+ || !pj_list_empty(&key->accept_list)
+#endif
+ )
+ {
+ pj_assert(PJ_FD_ISSET(key->fd, rfdset));
+ }
+ else {
+ pj_assert(PJ_FD_ISSET(key->fd, rfdset) == 0);
+ }
+ if (!pj_list_empty(&key->write_list)
+#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
+ || key->connecting
+#endif
+ )
+ {
+ pj_assert(PJ_FD_ISSET(key->fd, wfdset));
+ }
+ else {
+ pj_assert(PJ_FD_ISSET(key->fd, wfdset) == 0);
+ }
+#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
+ if (key->connecting)
+ {
+ pj_assert(PJ_FD_ISSET(key->fd, xfdset));
+ }
+ else {
+ pj_assert(PJ_FD_ISSET(key->fd, xfdset) == 0);
+ }
+#endif /* PJ_HAS_TCP */
+
+ key = key->next;
+ }
+}
+#endif /* VALIDATE_FD_SET */
+
+
+/* ioqueue_remove_from_set()
+ * This function is called from ioqueue_dispatch_event() to instruct
+ * the ioqueue to remove the specified descriptor from ioqueue's descriptor
+ * set for the specified event.
+ */
+static void ioqueue_remove_from_set( pj_ioqueue_t *ioqueue,
+ pj_sock_t fd,
+ enum ioqueue_event_type event_type)
+{
+ pj_lock_acquire(ioqueue->lock);
+
+ if (event_type == READABLE_EVENT)
+ PJ_FD_CLR((pj_sock_t)fd, &ioqueue->rfdset);
+ else if (event_type == WRITEABLE_EVENT)
+ PJ_FD_CLR((pj_sock_t)fd, &ioqueue->wfdset);
+ else if (event_type == EXCEPTION_EVENT)
+ PJ_FD_CLR((pj_sock_t)fd, &ioqueue->xfdset);
+ else
+ pj_assert(0);
+
+ pj_lock_release(ioqueue->lock);
+}
+
+/*
+ * ioqueue_add_to_set()
+ * This function is called from pj_ioqueue_recv(), pj_ioqueue_send() etc
+ * to instruct the ioqueue to add the specified handle to ioqueue's descriptor
+ * set for the specified event.
+ */
+static void ioqueue_add_to_set( pj_ioqueue_t *ioqueue,
+ pj_sock_t fd,
+ enum ioqueue_event_type event_type )
+{
+ pj_lock_acquire(ioqueue->lock);
+
+ if (event_type == READABLE_EVENT)
+ PJ_FD_SET((pj_sock_t)fd, &ioqueue->rfdset);
+ else if (event_type == WRITEABLE_EVENT)
+ PJ_FD_SET((pj_sock_t)fd, &ioqueue->wfdset);
+ else if (event_type == EXCEPTION_EVENT)
+ PJ_FD_SET((pj_sock_t)fd, &ioqueue->xfdset);
+ else
+ pj_assert(0);
+
+ pj_lock_release(ioqueue->lock);
+}
+
+/*
+ * pj_ioqueue_poll()
+ *
+ * Few things worth written:
+ *
+ * - we used to do only one callback called per poll, but it didn't go
+ * very well. The reason is because on some situation, the write
+ * callback gets called all the time, thus doesn't give the read
+ * callback to get called. This happens, for example, when user
+ * submit write operation inside the write callback.
+ * As the result, we changed the behaviour so that now multiple
+ * callbacks are called in a single poll. It should be fast too,
+ * just that we need to be carefull with the ioqueue data structs.
+ *
+ * - to guarantee preemptiveness etc, the poll function must strictly
+ * work on fd_set copy of the ioqueue (not the original one).
+ */
+PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioqueue, const pj_time_val *timeout)
+{
+ pj_fd_set_t rfdset, wfdset, xfdset;
+ int count, counter;
+ pj_ioqueue_key_t *h;
+ struct event
+ {
+ pj_ioqueue_key_t *key;
+ enum ioqueue_event_type event_type;
+ } event[PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL];
+
+ PJ_ASSERT_RETURN(ioqueue, PJ_EINVAL);
+
+ /* Lock ioqueue before making fd_set copies */
+ pj_lock_acquire(ioqueue->lock);
+
+ /* We will only do select() when there are sockets to be polled.
+ * Otherwise select() will return error.
+ */
+ if (PJ_FD_COUNT(&ioqueue->rfdset)==0 &&
+ PJ_FD_COUNT(&ioqueue->wfdset)==0 &&
+ PJ_FD_COUNT(&ioqueue->xfdset)==0)
+ {
+ pj_lock_release(ioqueue->lock);
+ if (timeout)
+ pj_thread_sleep(PJ_TIME_VAL_MSEC(*timeout));
+ return 0;
+ }
+
+ /* Copy ioqueue's pj_fd_set_t to local variables. */
+ pj_memcpy(&rfdset, &ioqueue->rfdset, sizeof(pj_fd_set_t));
+ pj_memcpy(&wfdset, &ioqueue->wfdset, sizeof(pj_fd_set_t));
+#if PJ_HAS_TCP
+ pj_memcpy(&xfdset, &ioqueue->xfdset, sizeof(pj_fd_set_t));
+#else
+ PJ_FD_ZERO(&xfdset);
+#endif
+
+#if VALIDATE_FD_SET
+ validate_sets(ioqueue, &rfdset, &wfdset, &xfdset);
+#endif
+
+ /* Unlock ioqueue before select(). */
+ pj_lock_release(ioqueue->lock);
+
+ count = pj_sock_select(FD_SETSIZE, &rfdset, &wfdset, &xfdset, timeout);
+
+ if (count <= 0)
+ return count;
+ else if (count > PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL)
+ count = PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL;
+
+ /* Scan descriptor sets for event and add the events in the event
+ * array to be processed later in this function. We do this so that
+ * events can be processed in parallel without holding ioqueue lock.
+ */
+ pj_lock_acquire(ioqueue->lock);
+
+ counter = 0;
+
+ /* Scan for writable sockets first to handle piggy-back data
+ * coming with accept().
+ */
+ h = ioqueue->key_list.next;
+ for ( ; h!=&ioqueue->key_list && counter<count; h = h->next) {
+ if ( (key_has_pending_write(h) || key_has_pending_connect(h))
+ && PJ_FD_ISSET(h->fd, &wfdset))
+ {
+ event[counter].key = h;
+ event[counter].event_type = WRITEABLE_EVENT;
+ ++counter;
+ }
+
+ /* Scan for readable socket. */
+ if ((key_has_pending_read(h) || key_has_pending_accept(h))
+ && PJ_FD_ISSET(h->fd, &rfdset))
+ {
+ event[counter].key = h;
+ event[counter].event_type = READABLE_EVENT;
+ ++counter;
+ }
+
+#if PJ_HAS_TCP
+ if (key_has_pending_connect(h) && PJ_FD_ISSET(h->fd, &xfdset)) {
+ event[counter].key = h;
+ event[counter].event_type = EXCEPTION_EVENT;
+ ++counter;
+ }
+#endif
+ }
+
+ pj_lock_release(ioqueue->lock);
+
+ count = counter;
+
+ /* Now process all events. The dispatch functions will take care
+ * of locking in each of the key
+ */
+ for (counter=0; counter<count; ++counter) {
+ switch (event[counter].event_type) {
+ case READABLE_EVENT:
+ ioqueue_dispatch_read_event(ioqueue, event[counter].key);
+ break;
+ case WRITEABLE_EVENT:
+ ioqueue_dispatch_write_event(ioqueue, event[counter].key);
+ break;
+ case EXCEPTION_EVENT:
+ ioqueue_dispatch_exception_event(ioqueue, event[counter].key);
+ break;
+ case NO_EVENT:
+ pj_assert(!"Invalid event!");
+ break;
+ }
+ }
+
+ return count;
+}
+
diff --git a/pjlib/src/pj/ioqueue_winnt.c b/pjlib/src/pj/ioqueue_winnt.c
index 777cb6be..7e3e31b9 100644
--- a/pjlib/src/pj/ioqueue_winnt.c
+++ b/pjlib/src/pj/ioqueue_winnt.c
@@ -1,896 +1,917 @@
-/* $Id$
- */
-#include <pj/ioqueue.h>
-#include <pj/os.h>
-#include <pj/lock.h>
-#include <pj/pool.h>
-#include <pj/string.h>
-#include <pj/sock.h>
-#include <pj/array.h>
-#include <pj/log.h>
-#include <pj/assert.h>
-#include <pj/errno.h>
-
-
-#if defined(PJ_HAS_WINSOCK2_H) && PJ_HAS_WINSOCK2_H != 0
-# include <winsock2.h>
-#elif defined(PJ_HAS_WINSOCK_H) && PJ_HAS_WINSOCK_H != 0
-# include <winsock.h>
-#endif
-
-#if defined(PJ_HAS_MSWSOCK_H) && PJ_HAS_MSWSOCK_H != 0
-# include <mswsock.h>
-#endif
-
-
-/* The address specified in AcceptEx() must be 16 more than the size of
- * SOCKADDR (source: MSDN).
- */
-#define ACCEPT_ADDR_LEN (sizeof(pj_sockaddr_in)+16)
-
-typedef struct generic_overlapped
-{
- WSAOVERLAPPED overlapped;
- pj_ioqueue_operation_e operation;
-} generic_overlapped;
-
-/*
- * OVERLAPPPED structure for send and receive.
- */
-typedef struct ioqueue_overlapped
-{
- WSAOVERLAPPED overlapped;
- pj_ioqueue_operation_e operation;
- WSABUF wsabuf;
- pj_sockaddr_in dummy_addr;
- int dummy_addrlen;
-} ioqueue_overlapped;
-
-#if PJ_HAS_TCP
-/*
- * OVERLAP structure for accept.
- */
-typedef struct ioqueue_accept_rec
-{
- WSAOVERLAPPED overlapped;
- pj_ioqueue_operation_e operation;
- pj_sock_t newsock;
- pj_sock_t *newsock_ptr;
- int *addrlen;
- void *remote;
- void *local;
- char accept_buf[2 * ACCEPT_ADDR_LEN];
-} ioqueue_accept_rec;
-#endif
-
-/*
- * Structure to hold pending operation key.
- */
-union operation_key
-{
- generic_overlapped generic;
- ioqueue_overlapped overlapped;
-#if PJ_HAS_TCP
- ioqueue_accept_rec accept;
-#endif
-};
-
-/* Type of handle in the key. */
-enum handle_type
-{
- HND_IS_UNKNOWN,
- HND_IS_FILE,
- HND_IS_SOCKET,
-};
-
-/*
- * Structure for individual socket.
- */
-struct pj_ioqueue_key_t
-{
- pj_ioqueue_t *ioqueue;
- HANDLE hnd;
- void *user_data;
- enum handle_type hnd_type;
-#if PJ_HAS_TCP
- int connecting;
-#endif
- pj_ioqueue_callback cb;
-};
-
-/*
- * IO Queue structure.
- */
-struct pj_ioqueue_t
-{
- HANDLE iocp;
- pj_lock_t *lock;
- pj_bool_t auto_delete_lock;
- unsigned event_count;
- HANDLE event_pool[MAXIMUM_WAIT_OBJECTS+1];
-#if PJ_HAS_TCP
- unsigned connecting_count;
- HANDLE connecting_handles[MAXIMUM_WAIT_OBJECTS+1];
- pj_ioqueue_key_t *connecting_keys[MAXIMUM_WAIT_OBJECTS+1];
-#endif
-};
-
-
-#if PJ_HAS_TCP
-/*
- * Process the socket when the overlapped accept() completed.
- */
-static void ioqueue_on_accept_complete(ioqueue_accept_rec *accept_overlapped)
-{
- struct sockaddr *local;
- struct sockaddr *remote;
- int locallen, remotelen;
-
- PJ_CHECK_STACK();
-
- /* Operation complete immediately. */
- GetAcceptExSockaddrs( accept_overlapped->accept_buf,
- 0,
- ACCEPT_ADDR_LEN,
- ACCEPT_ADDR_LEN,
- &local,
- &locallen,
- &remote,
- &remotelen);
- if (*accept_overlapped->addrlen > locallen) {
- pj_memcpy(accept_overlapped->local, local, locallen);
- pj_memcpy(accept_overlapped->remote, remote, locallen);
- } else {
- pj_memset(accept_overlapped->local, 0, *accept_overlapped->addrlen);
- pj_memset(accept_overlapped->remote, 0, *accept_overlapped->addrlen);
- }
- *accept_overlapped->addrlen = locallen;
- if (accept_overlapped->newsock_ptr)
- *accept_overlapped->newsock_ptr = accept_overlapped->newsock;
- accept_overlapped->operation = 0;
- accept_overlapped->newsock = PJ_INVALID_SOCKET;
-}
-
-static void erase_connecting_socket( pj_ioqueue_t *ioqueue, unsigned pos)
-{
- pj_ioqueue_key_t *key = ioqueue->connecting_keys[pos];
- HANDLE hEvent = ioqueue->connecting_handles[pos];
-
- /* Remove key from array of connecting handles. */
- pj_array_erase(ioqueue->connecting_keys, sizeof(key),
- ioqueue->connecting_count, pos);
- pj_array_erase(ioqueue->connecting_handles, sizeof(HANDLE),
- ioqueue->connecting_count, pos);
- --ioqueue->connecting_count;
-
- /* Disassociate the socket from the event. */
- WSAEventSelect((pj_sock_t)key->hnd, hEvent, 0);
-
- /* Put event object to pool. */
- if (ioqueue->event_count < MAXIMUM_WAIT_OBJECTS) {
- ioqueue->event_pool[ioqueue->event_count++] = hEvent;
- } else {
- /* Shouldn't happen. There should be no more pending connections
- * than max.
- */
- pj_assert(0);
- CloseHandle(hEvent);
- }
-
-}
-
-/*
- * Poll for the completion of non-blocking connect().
- * If there's a completion, the function return the key of the completed
- * socket, and 'result' argument contains the connect() result. If connect()
- * succeeded, 'result' will have value zero, otherwise will have the error
- * code.
- */
-static pj_ioqueue_key_t *check_connecting( pj_ioqueue_t *ioqueue,
- pj_ssize_t *connect_err )
-{
- pj_ioqueue_key_t *key = NULL;
-
- if (ioqueue->connecting_count) {
- DWORD result;
-
- pj_lock_acquire(ioqueue->lock);
- result = WaitForMultipleObjects(ioqueue->connecting_count,
- ioqueue->connecting_handles,
- FALSE, 0);
- if (result >= WAIT_OBJECT_0 &&
- result < WAIT_OBJECT_0+ioqueue->connecting_count)
- {
- WSANETWORKEVENTS net_events;
-
- /* Got completed connect(). */
- unsigned pos = result - WAIT_OBJECT_0;
- key = ioqueue->connecting_keys[pos];
-
- /* See whether connect has succeeded. */
- WSAEnumNetworkEvents((pj_sock_t)key->hnd,
- ioqueue->connecting_handles[pos],
- &net_events);
- *connect_err =
- PJ_STATUS_FROM_OS(net_events.iErrorCode[FD_CONNECT_BIT]);
-
- /* Erase socket from pending connect. */
- erase_connecting_socket(ioqueue, pos);
- }
- pj_lock_release(ioqueue->lock);
- }
- return key;
-}
-#endif
-
-/*
- * pj_ioqueue_name()
- */
-PJ_DEF(const char*) pj_ioqueue_name(void)
-{
- return "iocp";
-}
-
-/*
- * pj_ioqueue_create()
- */
-PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool,
- pj_size_t max_fd,
- pj_ioqueue_t **p_ioqueue)
-{
- pj_ioqueue_t *ioqueue;
- pj_status_t rc;
-
- PJ_UNUSED_ARG(max_fd);
- PJ_ASSERT_RETURN(pool && p_ioqueue, PJ_EINVAL);
-
- rc = sizeof(union operation_key);
-
- /* Check that sizeof(pj_ioqueue_op_key_t) makes sense. */
- PJ_ASSERT_RETURN(sizeof(pj_ioqueue_op_key_t)-sizeof(void*) >=
- sizeof(union operation_key), PJ_EBUG);
-
- ioqueue = pj_pool_zalloc(pool, sizeof(*ioqueue));
- ioqueue->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
- if (ioqueue->iocp == NULL)
- return PJ_RETURN_OS_ERROR(GetLastError());
-
- rc = pj_lock_create_simple_mutex(pool, NULL, &ioqueue->lock);
- if (rc != PJ_SUCCESS) {
- CloseHandle(ioqueue->iocp);
- return rc;
- }
-
- ioqueue->auto_delete_lock = PJ_TRUE;
-
- *p_ioqueue = ioqueue;
-
- PJ_LOG(4, ("pjlib", "WinNT IOCP I/O Queue created (%p)", ioqueue));
- return PJ_SUCCESS;
-}
-
-/*
- * pj_ioqueue_destroy()
- */
-PJ_DEF(pj_status_t) pj_ioqueue_destroy( pj_ioqueue_t *ioqueue )
-{
- unsigned i;
-
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(ioqueue, PJ_EINVAL);
-
- /* Destroy events in the pool */
- for (i=0; i<ioqueue->event_count; ++i) {
- CloseHandle(ioqueue->event_pool[i]);
- }
- ioqueue->event_count = 0;
-
- if (CloseHandle(ioqueue->iocp) != TRUE)
- return PJ_RETURN_OS_ERROR(GetLastError());
-
- if (ioqueue->auto_delete_lock)
- pj_lock_destroy(ioqueue->lock);
-
- return PJ_SUCCESS;
-}
-
-/*
- * pj_ioqueue_set_lock()
- */
-PJ_DEF(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioqueue,
- pj_lock_t *lock,
- pj_bool_t auto_delete )
-{
- PJ_ASSERT_RETURN(ioqueue && lock, PJ_EINVAL);
-
- if (ioqueue->auto_delete_lock) {
- pj_lock_destroy(ioqueue->lock);
- }
-
- ioqueue->lock = lock;
- ioqueue->auto_delete_lock = auto_delete;
-
- return PJ_SUCCESS;
-}
-
-/*
- * pj_ioqueue_register_sock()
- */
-PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,
- pj_ioqueue_t *ioqueue,
- pj_sock_t sock,
- void *user_data,
- const pj_ioqueue_callback *cb,
- pj_ioqueue_key_t **key )
-{
- HANDLE hioq;
- pj_ioqueue_key_t *rec;
- u_long value;
- int rc;
-
- PJ_ASSERT_RETURN(pool && ioqueue && cb && key, PJ_EINVAL);
-
- /* Build the key for this socket. */
- rec = pj_pool_zalloc(pool, sizeof(pj_ioqueue_key_t));
- rec->ioqueue = ioqueue;
- rec->hnd = (HANDLE)sock;
- rec->hnd_type = HND_IS_SOCKET;
- rec->user_data = user_data;
- pj_memcpy(&rec->cb, cb, sizeof(pj_ioqueue_callback));
-
- /* Set socket to nonblocking. */
- value = 1;
- rc = ioctlsocket(sock, FIONBIO, &value);
- if (rc != 0) {
- return PJ_RETURN_OS_ERROR(WSAGetLastError());
- }
-
- /* Associate with IOCP */
- hioq = CreateIoCompletionPort((HANDLE)sock, ioqueue->iocp, (DWORD)rec, 0);
- if (!hioq) {
- return PJ_RETURN_OS_ERROR(GetLastError());
- }
-
- *key = rec;
- return PJ_SUCCESS;
-}
-
-/*
- * pj_ioqueue_unregister()
- */
-PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key )
-{
- PJ_ASSERT_RETURN(key, PJ_EINVAL);
-
-#if PJ_HAS_TCP
- if (key->connecting) {
- unsigned pos;
- pj_ioqueue_t *ioqueue;
-
- ioqueue = key->ioqueue;
-
- /* Erase from connecting_handles */
- pj_lock_acquire(ioqueue->lock);
- for (pos=0; pos < ioqueue->connecting_count; ++pos) {
- if (ioqueue->connecting_keys[pos] == key) {
- erase_connecting_socket(ioqueue, pos);
- break;
- }
- }
- key->connecting = 0;
- pj_lock_release(ioqueue->lock);
- }
-#endif
- if (key->hnd_type == HND_IS_FILE) {
- CloseHandle(key->hnd);
- }
- return PJ_SUCCESS;
-}
-
-/*
- * pj_ioqueue_get_user_data()
- */
-PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key )
-{
- PJ_ASSERT_RETURN(key, NULL);
- return key->user_data;
-}
-
-/*
- * pj_ioqueue_set_user_data()
- */
-PJ_DEF(pj_status_t) pj_ioqueue_set_user_data( pj_ioqueue_key_t *key,
- void *user_data,
- void **old_data )
-{
- PJ_ASSERT_RETURN(key, PJ_EINVAL);
-
- if (old_data)
- *old_data = key->user_data;
-
- key->user_data = user_data;
- return PJ_SUCCESS;
-}
-
-/*
- * pj_ioqueue_poll()
- *
- * Poll for events.
- */
-PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioqueue, const pj_time_val *timeout)
-{
- DWORD dwMsec, dwBytesTransfered, dwKey;
- generic_overlapped *pOv;
- pj_ioqueue_key_t *key;
- pj_ssize_t size_status;
- BOOL rc;
-
- PJ_ASSERT_RETURN(ioqueue, -PJ_EINVAL);
-
- /* Check the connecting array. */
-#if PJ_HAS_TCP
- key = check_connecting(ioqueue, &size_status);
- if (key != NULL) {
- key->cb.on_connect_complete(key, (int)size_status);
- return 1;
- }
-#endif
-
- /* Calculate miliseconds timeout for GetQueuedCompletionStatus */
- dwMsec = timeout ? timeout->sec*1000 + timeout->msec : INFINITE;
-
- /* Poll for completion status. */
- rc = GetQueuedCompletionStatus(ioqueue->iocp, &dwBytesTransfered, &dwKey,
- (OVERLAPPED**)&pOv, dwMsec);
-
- /* The return value is:
- * - nonzero if event was dequeued.
- * - zero and pOv==NULL if no event was dequeued.
- * - zero and pOv!=NULL if event for failed I/O was dequeued.
- */
- if (pOv) {
- /* Event was dequeued for either successfull or failed I/O */
- key = (pj_ioqueue_key_t*)dwKey;
- size_status = dwBytesTransfered;
- switch (pOv->operation) {
- case PJ_IOQUEUE_OP_READ:
- case PJ_IOQUEUE_OP_RECV:
- case PJ_IOQUEUE_OP_RECV_FROM:
- pOv->operation = 0;
- if (key->cb.on_read_complete)
- key->cb.on_read_complete(key, (pj_ioqueue_op_key_t*)pOv,
- size_status);
- break;
- case PJ_IOQUEUE_OP_WRITE:
- case PJ_IOQUEUE_OP_SEND:
- case PJ_IOQUEUE_OP_SEND_TO:
- pOv->operation = 0;
- if (key->cb.on_write_complete)
- key->cb.on_write_complete(key, (pj_ioqueue_op_key_t*)pOv,
- size_status);
- break;
-#if PJ_HAS_TCP
- case PJ_IOQUEUE_OP_ACCEPT:
- /* special case for accept. */
- ioqueue_on_accept_complete((ioqueue_accept_rec*)pOv);
- if (key->cb.on_accept_complete) {
- ioqueue_accept_rec *accept_rec = (ioqueue_accept_rec*)pOv;
- key->cb.on_accept_complete(key,
- (pj_ioqueue_op_key_t*)pOv,
- accept_rec->newsock,
- PJ_SUCCESS);
- }
- break;
- case PJ_IOQUEUE_OP_CONNECT:
-#endif
- case PJ_IOQUEUE_OP_NONE:
- pj_assert(0);
- break;
- }
- return 1;
- }
-
- if (GetLastError()==WAIT_TIMEOUT) {
- /* Check the connecting array (again). */
-#if PJ_HAS_TCP
- key = check_connecting(ioqueue, &size_status);
- if (key != NULL) {
- key->cb.on_connect_complete(key, (int)size_status);
- return 1;
- }
-#endif
- return 0;
- }
- return -1;
-}
-
-/*
- * pj_ioqueue_recv()
- *
- * Initiate overlapped WSARecv() operation.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_recv( pj_ioqueue_key_t *key,
- pj_ioqueue_op_key_t *op_key,
- void *buffer,
- pj_ssize_t *length,
- unsigned flags )
-{
- /*
- * Ideally we should just call pj_ioqueue_recvfrom() with NULL addr and
- * addrlen here. But unfortunately it generates EINVAL... :-(
- * -bennylp
- */
- int rc;
- DWORD bytesRead;
- DWORD dwFlags = 0;
- union operation_key *op_key_rec;
-
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(key && op_key && buffer && length, PJ_EINVAL);
-
- op_key_rec = (union operation_key*)op_key->internal__;
- op_key_rec->overlapped.wsabuf.buf = buffer;
- op_key_rec->overlapped.wsabuf.len = *length;
-
- dwFlags = flags;
-
- /* Try non-overlapped received first to see if data is
- * immediately available.
- */
- rc = WSARecv((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1,
- &bytesRead, &dwFlags, NULL, NULL);
- if (rc == 0) {
- *length = bytesRead;
- return PJ_SUCCESS;
- } else {
- DWORD dwError = WSAGetLastError();
- if (dwError != WSAEWOULDBLOCK) {
- *length = -1;
- return PJ_RETURN_OS_ERROR(dwError);
- }
- }
-
- /*
- * No immediate data available.
- * Register overlapped Recv() operation.
- */
- pj_memset(&op_key_rec->overlapped.overlapped, 0,
- sizeof(op_key_rec->overlapped.overlapped));
- op_key_rec->overlapped.operation = PJ_IOQUEUE_OP_RECV;
-
- rc = WSARecv((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1,
- &bytesRead, &dwFlags,
- &op_key_rec->overlapped.overlapped, NULL);
- if (rc == SOCKET_ERROR) {
- DWORD dwStatus = WSAGetLastError();
- if (dwStatus!=WSA_IO_PENDING) {
- *length = -1;
- return PJ_STATUS_FROM_OS(dwStatus);
- }
- }
-
- /* Pending operation has been scheduled. */
- return PJ_EPENDING;
-}
-
-/*
- * pj_ioqueue_recvfrom()
- *
- * Initiate overlapped RecvFrom() operation.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_key_t *key,
- pj_ioqueue_op_key_t *op_key,
- void *buffer,
- pj_ssize_t *length,
- unsigned flags,
- pj_sockaddr_t *addr,
- int *addrlen)
-{
- int rc;
- DWORD bytesRead;
- DWORD dwFlags = 0;
- union operation_key *op_key_rec;
-
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(key && op_key && buffer, PJ_EINVAL);
-
- op_key_rec = (union operation_key*)op_key->internal__;
- op_key_rec->overlapped.wsabuf.buf = buffer;
- op_key_rec->overlapped.wsabuf.len = *length;
-
- dwFlags = flags;
-
- /* Try non-overlapped received first to see if data is
- * immediately available.
- */
- rc = WSARecvFrom((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1,
- &bytesRead, &dwFlags, addr, addrlen, NULL, NULL);
- if (rc == 0) {
- *length = bytesRead;
- return PJ_SUCCESS;
- } else {
- DWORD dwError = WSAGetLastError();
- if (dwError != WSAEWOULDBLOCK) {
- *length = -1;
- return PJ_RETURN_OS_ERROR(dwError);
- }
- }
-
- /*
- * No immediate data available.
- * Register overlapped Recv() operation.
- */
- pj_memset(&op_key_rec->overlapped.overlapped, 0,
- sizeof(op_key_rec->overlapped.overlapped));
- op_key_rec->overlapped.operation = PJ_IOQUEUE_OP_RECV;
-
- rc = WSARecvFrom((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1,
- &bytesRead, &dwFlags, addr, addrlen,
- &op_key_rec->overlapped.overlapped, NULL);
- if (rc == SOCKET_ERROR) {
- DWORD dwStatus = WSAGetLastError();
- if (dwStatus!=WSA_IO_PENDING) {
- *length = -1;
- return PJ_STATUS_FROM_OS(dwStatus);
- }
- }
-
- /* Pending operation has been scheduled. */
- return PJ_EPENDING;
-}
-
-/*
- * pj_ioqueue_send()
- *
- * Initiate overlapped Send operation.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_send( pj_ioqueue_key_t *key,
- pj_ioqueue_op_key_t *op_key,
- const void *data,
- pj_ssize_t *length,
- unsigned flags )
-{
- return pj_ioqueue_sendto(key, op_key, data, length, flags, NULL, 0);
-}
-
-
-/*
- * pj_ioqueue_sendto()
- *
- * Initiate overlapped SendTo operation.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_key_t *key,
- pj_ioqueue_op_key_t *op_key,
- const void *data,
- pj_ssize_t *length,
- unsigned flags,
- const pj_sockaddr_t *addr,
- int addrlen)
-{
- int rc;
- DWORD bytesWritten;
- DWORD dwFlags;
- union operation_key *op_key_rec;
-
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(key && op_key && data, PJ_EINVAL);
-
- op_key_rec = (union operation_key*)op_key->internal__;
-
- dwFlags = flags;
-
- /*
- * First try blocking write.
- */
- op_key_rec->overlapped.wsabuf.buf = (void*)data;
- op_key_rec->overlapped.wsabuf.len = *length;
-
- rc = WSASendTo((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1,
- &bytesWritten, dwFlags, addr, addrlen,
- NULL, NULL);
- if (rc == 0) {
- *length = bytesWritten;
- return PJ_SUCCESS;
- } else {
- DWORD dwStatus = WSAGetLastError();
- if (dwStatus != WSAEWOULDBLOCK) {
- *length = -1;
- return PJ_RETURN_OS_ERROR(dwStatus);
- }
- }
-
- /*
- * Data can't be sent immediately.
- * Schedule asynchronous WSASend().
- */
- pj_memset(&op_key_rec->overlapped.overlapped, 0,
- sizeof(op_key_rec->overlapped.overlapped));
- op_key_rec->overlapped.operation = PJ_IOQUEUE_OP_SEND;
-
- rc = WSASendTo((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1,
- &bytesWritten, dwFlags, addr, addrlen,
- &op_key_rec->overlapped.overlapped, NULL);
- if (rc == SOCKET_ERROR) {
- DWORD dwStatus = WSAGetLastError();
- if (dwStatus!=WSA_IO_PENDING)
- return PJ_STATUS_FROM_OS(dwStatus);
- }
-
- /* Asynchronous operation successfully submitted. */
- return PJ_EPENDING;
-}
-
-#if PJ_HAS_TCP
-
-/*
- * pj_ioqueue_accept()
- *
- * Initiate overlapped accept() operation.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_accept( pj_ioqueue_key_t *key,
- pj_ioqueue_op_key_t *op_key,
- pj_sock_t *new_sock,
- pj_sockaddr_t *local,
- pj_sockaddr_t *remote,
- int *addrlen)
-{
- BOOL rc;
- DWORD bytesReceived;
- pj_status_t status;
- union operation_key *op_key_rec;
- SOCKET sock;
-
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(key && op_key && new_sock, PJ_EINVAL);
-
- /*
- * See if there is a new connection immediately available.
- */
- sock = WSAAccept((SOCKET)key->hnd, remote, addrlen, NULL, 0);
- if (sock != INVALID_SOCKET) {
- /* Yes! New socket is available! */
- int status;
-
- status = getsockname(sock, local, addrlen);
- if (status != 0) {
- DWORD dwError = WSAGetLastError();
- closesocket(sock);
- return PJ_RETURN_OS_ERROR(dwError);
- }
-
- *new_sock = sock;
- return PJ_SUCCESS;
-
- } else {
- DWORD dwError = WSAGetLastError();
- if (dwError != WSAEWOULDBLOCK) {
- return PJ_RETURN_OS_ERROR(dwError);
- }
- }
-
- /*
- * No connection is immediately available.
- * Must schedule an asynchronous operation.
- */
- op_key_rec = (union operation_key*)op_key->internal__;
-
- status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, 0,
- &op_key_rec->accept.newsock);
- if (status != PJ_SUCCESS)
- return status;
-
- /* On WinXP or later, use SO_UPDATE_ACCEPT_CONTEXT so that socket
- * addresses can be obtained with getsockname() and getpeername().
- */
- status = setsockopt(op_key_rec->accept.newsock, SOL_SOCKET,
- SO_UPDATE_ACCEPT_CONTEXT,
- (char*)&key->hnd, sizeof(SOCKET));
- /* SO_UPDATE_ACCEPT_CONTEXT is for WinXP or later.
- * So ignore the error status.
- */
-
- op_key_rec->accept.operation = PJ_IOQUEUE_OP_ACCEPT;
- op_key_rec->accept.addrlen = addrlen;
- op_key_rec->accept.local = local;
- op_key_rec->accept.remote = remote;
- op_key_rec->accept.newsock_ptr = new_sock;
- pj_memset(&op_key_rec->accept.overlapped, 0,
- sizeof(op_key_rec->accept.overlapped));
-
- rc = AcceptEx( (SOCKET)key->hnd, (SOCKET)op_key_rec->accept.newsock,
- op_key_rec->accept.accept_buf,
- 0, ACCEPT_ADDR_LEN, ACCEPT_ADDR_LEN,
- &bytesReceived,
- &op_key_rec->accept.overlapped );
-
- if (rc == TRUE) {
- ioqueue_on_accept_complete(&op_key_rec->accept);
- return PJ_SUCCESS;
- } else {
- DWORD dwStatus = WSAGetLastError();
- if (dwStatus!=WSA_IO_PENDING)
- return PJ_STATUS_FROM_OS(dwStatus);
- }
-
- /* Asynchronous Accept() has been submitted. */
- return PJ_EPENDING;
-}
-
-
-/*
- * pj_ioqueue_connect()
- *
- * Initiate overlapped connect() operation (well, it's non-blocking actually,
- * since there's no overlapped version of connect()).
- */
-PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_key_t *key,
- const pj_sockaddr_t *addr,
- int addrlen )
-{
- HANDLE hEvent;
- pj_ioqueue_t *ioqueue;
-
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(key && addr && addrlen, PJ_EINVAL);
-
- /* Initiate connect() */
- if (connect((pj_sock_t)key->hnd, addr, addrlen) != 0) {
- DWORD dwStatus;
- dwStatus = WSAGetLastError();
- if (dwStatus != WSAEWOULDBLOCK) {
- return PJ_RETURN_OS_ERROR(dwStatus);
- }
- } else {
- /* Connect has completed immediately! */
- return PJ_SUCCESS;
- }
-
- ioqueue = key->ioqueue;
-
- /* Add to the array of connecting socket to be polled */
- pj_lock_acquire(ioqueue->lock);
-
- if (ioqueue->connecting_count >= MAXIMUM_WAIT_OBJECTS) {
- pj_lock_release(ioqueue->lock);
- return PJ_ETOOMANYCONN;
- }
-
- /* Get or create event object. */
- if (ioqueue->event_count) {
- hEvent = ioqueue->event_pool[ioqueue->event_count - 1];
- --ioqueue->event_count;
- } else {
- hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
- if (hEvent == NULL) {
- DWORD dwStatus = GetLastError();
- pj_lock_release(ioqueue->lock);
- return PJ_STATUS_FROM_OS(dwStatus);
- }
- }
-
- /* Mark key as connecting.
- * We can't use array index since key can be removed dynamically.
- */
- key->connecting = 1;
-
- /* Associate socket events to the event object. */
- if (WSAEventSelect((pj_sock_t)key->hnd, hEvent, FD_CONNECT) != 0) {
- CloseHandle(hEvent);
- pj_lock_release(ioqueue->lock);
- return PJ_RETURN_OS_ERROR(WSAGetLastError());
- }
-
- /* Add to array. */
- ioqueue->connecting_keys[ ioqueue->connecting_count ] = key;
- ioqueue->connecting_handles[ ioqueue->connecting_count ] = hEvent;
- ioqueue->connecting_count++;
-
- pj_lock_release(ioqueue->lock);
-
- return PJ_EPENDING;
-}
-#endif /* #if PJ_HAS_TCP */
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/ioqueue.h>
+#include <pj/os.h>
+#include <pj/lock.h>
+#include <pj/pool.h>
+#include <pj/string.h>
+#include <pj/sock.h>
+#include <pj/array.h>
+#include <pj/log.h>
+#include <pj/assert.h>
+#include <pj/errno.h>
+
+
+#if defined(PJ_HAS_WINSOCK2_H) && PJ_HAS_WINSOCK2_H != 0
+# include <winsock2.h>
+#elif defined(PJ_HAS_WINSOCK_H) && PJ_HAS_WINSOCK_H != 0
+# include <winsock.h>
+#endif
+
+#if defined(PJ_HAS_MSWSOCK_H) && PJ_HAS_MSWSOCK_H != 0
+# include <mswsock.h>
+#endif
+
+
+/* The address specified in AcceptEx() must be 16 more than the size of
+ * SOCKADDR (source: MSDN).
+ */
+#define ACCEPT_ADDR_LEN (sizeof(pj_sockaddr_in)+16)
+
+typedef struct generic_overlapped
+{
+ WSAOVERLAPPED overlapped;
+ pj_ioqueue_operation_e operation;
+} generic_overlapped;
+
+/*
+ * OVERLAPPPED structure for send and receive.
+ */
+typedef struct ioqueue_overlapped
+{
+ WSAOVERLAPPED overlapped;
+ pj_ioqueue_operation_e operation;
+ WSABUF wsabuf;
+ pj_sockaddr_in dummy_addr;
+ int dummy_addrlen;
+} ioqueue_overlapped;
+
+#if PJ_HAS_TCP
+/*
+ * OVERLAP structure for accept.
+ */
+typedef struct ioqueue_accept_rec
+{
+ WSAOVERLAPPED overlapped;
+ pj_ioqueue_operation_e operation;
+ pj_sock_t newsock;
+ pj_sock_t *newsock_ptr;
+ int *addrlen;
+ void *remote;
+ void *local;
+ char accept_buf[2 * ACCEPT_ADDR_LEN];
+} ioqueue_accept_rec;
+#endif
+
+/*
+ * Structure to hold pending operation key.
+ */
+union operation_key
+{
+ generic_overlapped generic;
+ ioqueue_overlapped overlapped;
+#if PJ_HAS_TCP
+ ioqueue_accept_rec accept;
+#endif
+};
+
+/* Type of handle in the key. */
+enum handle_type
+{
+ HND_IS_UNKNOWN,
+ HND_IS_FILE,
+ HND_IS_SOCKET,
+};
+
+/*
+ * Structure for individual socket.
+ */
+struct pj_ioqueue_key_t
+{
+ pj_ioqueue_t *ioqueue;
+ HANDLE hnd;
+ void *user_data;
+ enum handle_type hnd_type;
+#if PJ_HAS_TCP
+ int connecting;
+#endif
+ pj_ioqueue_callback cb;
+};
+
+/*
+ * IO Queue structure.
+ */
+struct pj_ioqueue_t
+{
+ HANDLE iocp;
+ pj_lock_t *lock;
+ pj_bool_t auto_delete_lock;
+ unsigned event_count;
+ HANDLE event_pool[MAXIMUM_WAIT_OBJECTS+1];
+#if PJ_HAS_TCP
+ unsigned connecting_count;
+ HANDLE connecting_handles[MAXIMUM_WAIT_OBJECTS+1];
+ pj_ioqueue_key_t *connecting_keys[MAXIMUM_WAIT_OBJECTS+1];
+#endif
+};
+
+
+#if PJ_HAS_TCP
+/*
+ * Process the socket when the overlapped accept() completed.
+ */
+static void ioqueue_on_accept_complete(ioqueue_accept_rec *accept_overlapped)
+{
+ struct sockaddr *local;
+ struct sockaddr *remote;
+ int locallen, remotelen;
+
+ PJ_CHECK_STACK();
+
+ /* Operation complete immediately. */
+ GetAcceptExSockaddrs( accept_overlapped->accept_buf,
+ 0,
+ ACCEPT_ADDR_LEN,
+ ACCEPT_ADDR_LEN,
+ &local,
+ &locallen,
+ &remote,
+ &remotelen);
+ if (*accept_overlapped->addrlen > locallen) {
+ pj_memcpy(accept_overlapped->local, local, locallen);
+ pj_memcpy(accept_overlapped->remote, remote, locallen);
+ } else {
+ pj_memset(accept_overlapped->local, 0, *accept_overlapped->addrlen);
+ pj_memset(accept_overlapped->remote, 0, *accept_overlapped->addrlen);
+ }
+ *accept_overlapped->addrlen = locallen;
+ if (accept_overlapped->newsock_ptr)
+ *accept_overlapped->newsock_ptr = accept_overlapped->newsock;
+ accept_overlapped->operation = 0;
+ accept_overlapped->newsock = PJ_INVALID_SOCKET;
+}
+
+static void erase_connecting_socket( pj_ioqueue_t *ioqueue, unsigned pos)
+{
+ pj_ioqueue_key_t *key = ioqueue->connecting_keys[pos];
+ HANDLE hEvent = ioqueue->connecting_handles[pos];
+
+ /* Remove key from array of connecting handles. */
+ pj_array_erase(ioqueue->connecting_keys, sizeof(key),
+ ioqueue->connecting_count, pos);
+ pj_array_erase(ioqueue->connecting_handles, sizeof(HANDLE),
+ ioqueue->connecting_count, pos);
+ --ioqueue->connecting_count;
+
+ /* Disassociate the socket from the event. */
+ WSAEventSelect((pj_sock_t)key->hnd, hEvent, 0);
+
+ /* Put event object to pool. */
+ if (ioqueue->event_count < MAXIMUM_WAIT_OBJECTS) {
+ ioqueue->event_pool[ioqueue->event_count++] = hEvent;
+ } else {
+ /* Shouldn't happen. There should be no more pending connections
+ * than max.
+ */
+ pj_assert(0);
+ CloseHandle(hEvent);
+ }
+
+}
+
+/*
+ * Poll for the completion of non-blocking connect().
+ * If there's a completion, the function return the key of the completed
+ * socket, and 'result' argument contains the connect() result. If connect()
+ * succeeded, 'result' will have value zero, otherwise will have the error
+ * code.
+ */
+static pj_ioqueue_key_t *check_connecting( pj_ioqueue_t *ioqueue,
+ pj_ssize_t *connect_err )
+{
+ pj_ioqueue_key_t *key = NULL;
+
+ if (ioqueue->connecting_count) {
+ DWORD result;
+
+ pj_lock_acquire(ioqueue->lock);
+ result = WaitForMultipleObjects(ioqueue->connecting_count,
+ ioqueue->connecting_handles,
+ FALSE, 0);
+ if (result >= WAIT_OBJECT_0 &&
+ result < WAIT_OBJECT_0+ioqueue->connecting_count)
+ {
+ WSANETWORKEVENTS net_events;
+
+ /* Got completed connect(). */
+ unsigned pos = result - WAIT_OBJECT_0;
+ key = ioqueue->connecting_keys[pos];
+
+ /* See whether connect has succeeded. */
+ WSAEnumNetworkEvents((pj_sock_t)key->hnd,
+ ioqueue->connecting_handles[pos],
+ &net_events);
+ *connect_err =
+ PJ_STATUS_FROM_OS(net_events.iErrorCode[FD_CONNECT_BIT]);
+
+ /* Erase socket from pending connect. */
+ erase_connecting_socket(ioqueue, pos);
+ }
+ pj_lock_release(ioqueue->lock);
+ }
+ return key;
+}
+#endif
+
+/*
+ * pj_ioqueue_name()
+ */
+PJ_DEF(const char*) pj_ioqueue_name(void)
+{
+ return "iocp";
+}
+
+/*
+ * pj_ioqueue_create()
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool,
+ pj_size_t max_fd,
+ pj_ioqueue_t **p_ioqueue)
+{
+ pj_ioqueue_t *ioqueue;
+ pj_status_t rc;
+
+ PJ_UNUSED_ARG(max_fd);
+ PJ_ASSERT_RETURN(pool && p_ioqueue, PJ_EINVAL);
+
+ rc = sizeof(union operation_key);
+
+ /* Check that sizeof(pj_ioqueue_op_key_t) makes sense. */
+ PJ_ASSERT_RETURN(sizeof(pj_ioqueue_op_key_t)-sizeof(void*) >=
+ sizeof(union operation_key), PJ_EBUG);
+
+ ioqueue = pj_pool_zalloc(pool, sizeof(*ioqueue));
+ ioqueue->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
+ if (ioqueue->iocp == NULL)
+ return PJ_RETURN_OS_ERROR(GetLastError());
+
+ rc = pj_lock_create_simple_mutex(pool, NULL, &ioqueue->lock);
+ if (rc != PJ_SUCCESS) {
+ CloseHandle(ioqueue->iocp);
+ return rc;
+ }
+
+ ioqueue->auto_delete_lock = PJ_TRUE;
+
+ *p_ioqueue = ioqueue;
+
+ PJ_LOG(4, ("pjlib", "WinNT IOCP I/O Queue created (%p)", ioqueue));
+ return PJ_SUCCESS;
+}
+
+/*
+ * pj_ioqueue_destroy()
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_destroy( pj_ioqueue_t *ioqueue )
+{
+ unsigned i;
+
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(ioqueue, PJ_EINVAL);
+
+ /* Destroy events in the pool */
+ for (i=0; i<ioqueue->event_count; ++i) {
+ CloseHandle(ioqueue->event_pool[i]);
+ }
+ ioqueue->event_count = 0;
+
+ if (CloseHandle(ioqueue->iocp) != TRUE)
+ return PJ_RETURN_OS_ERROR(GetLastError());
+
+ if (ioqueue->auto_delete_lock)
+ pj_lock_destroy(ioqueue->lock);
+
+ return PJ_SUCCESS;
+}
+
+/*
+ * pj_ioqueue_set_lock()
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioqueue,
+ pj_lock_t *lock,
+ pj_bool_t auto_delete )
+{
+ PJ_ASSERT_RETURN(ioqueue && lock, PJ_EINVAL);
+
+ if (ioqueue->auto_delete_lock) {
+ pj_lock_destroy(ioqueue->lock);
+ }
+
+ ioqueue->lock = lock;
+ ioqueue->auto_delete_lock = auto_delete;
+
+ return PJ_SUCCESS;
+}
+
+/*
+ * pj_ioqueue_register_sock()
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,
+ pj_ioqueue_t *ioqueue,
+ pj_sock_t sock,
+ void *user_data,
+ const pj_ioqueue_callback *cb,
+ pj_ioqueue_key_t **key )
+{
+ HANDLE hioq;
+ pj_ioqueue_key_t *rec;
+ u_long value;
+ int rc;
+
+ PJ_ASSERT_RETURN(pool && ioqueue && cb && key, PJ_EINVAL);
+
+ /* Build the key for this socket. */
+ rec = pj_pool_zalloc(pool, sizeof(pj_ioqueue_key_t));
+ rec->ioqueue = ioqueue;
+ rec->hnd = (HANDLE)sock;
+ rec->hnd_type = HND_IS_SOCKET;
+ rec->user_data = user_data;
+ pj_memcpy(&rec->cb, cb, sizeof(pj_ioqueue_callback));
+
+ /* Set socket to nonblocking. */
+ value = 1;
+ rc = ioctlsocket(sock, FIONBIO, &value);
+ if (rc != 0) {
+ return PJ_RETURN_OS_ERROR(WSAGetLastError());
+ }
+
+ /* Associate with IOCP */
+ hioq = CreateIoCompletionPort((HANDLE)sock, ioqueue->iocp, (DWORD)rec, 0);
+ if (!hioq) {
+ return PJ_RETURN_OS_ERROR(GetLastError());
+ }
+
+ *key = rec;
+ return PJ_SUCCESS;
+}
+
+/*
+ * pj_ioqueue_unregister()
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key )
+{
+ PJ_ASSERT_RETURN(key, PJ_EINVAL);
+
+#if PJ_HAS_TCP
+ if (key->connecting) {
+ unsigned pos;
+ pj_ioqueue_t *ioqueue;
+
+ ioqueue = key->ioqueue;
+
+ /* Erase from connecting_handles */
+ pj_lock_acquire(ioqueue->lock);
+ for (pos=0; pos < ioqueue->connecting_count; ++pos) {
+ if (ioqueue->connecting_keys[pos] == key) {
+ erase_connecting_socket(ioqueue, pos);
+ break;
+ }
+ }
+ key->connecting = 0;
+ pj_lock_release(ioqueue->lock);
+ }
+#endif
+ if (key->hnd_type == HND_IS_FILE) {
+ CloseHandle(key->hnd);
+ }
+ return PJ_SUCCESS;
+}
+
+/*
+ * pj_ioqueue_get_user_data()
+ */
+PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key )
+{
+ PJ_ASSERT_RETURN(key, NULL);
+ return key->user_data;
+}
+
+/*
+ * pj_ioqueue_set_user_data()
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_set_user_data( pj_ioqueue_key_t *key,
+ void *user_data,
+ void **old_data )
+{
+ PJ_ASSERT_RETURN(key, PJ_EINVAL);
+
+ if (old_data)
+ *old_data = key->user_data;
+
+ key->user_data = user_data;
+ return PJ_SUCCESS;
+}
+
+/*
+ * pj_ioqueue_poll()
+ *
+ * Poll for events.
+ */
+PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioqueue, const pj_time_val *timeout)
+{
+ DWORD dwMsec, dwBytesTransfered, dwKey;
+ generic_overlapped *pOv;
+ pj_ioqueue_key_t *key;
+ pj_ssize_t size_status;
+ BOOL rc;
+
+ PJ_ASSERT_RETURN(ioqueue, -PJ_EINVAL);
+
+ /* Check the connecting array. */
+#if PJ_HAS_TCP
+ key = check_connecting(ioqueue, &size_status);
+ if (key != NULL) {
+ key->cb.on_connect_complete(key, (int)size_status);
+ return 1;
+ }
+#endif
+
+ /* Calculate miliseconds timeout for GetQueuedCompletionStatus */
+ dwMsec = timeout ? timeout->sec*1000 + timeout->msec : INFINITE;
+
+ /* Poll for completion status. */
+ rc = GetQueuedCompletionStatus(ioqueue->iocp, &dwBytesTransfered, &dwKey,
+ (OVERLAPPED**)&pOv, dwMsec);
+
+ /* The return value is:
+ * - nonzero if event was dequeued.
+ * - zero and pOv==NULL if no event was dequeued.
+ * - zero and pOv!=NULL if event for failed I/O was dequeued.
+ */
+ if (pOv) {
+ /* Event was dequeued for either successfull or failed I/O */
+ key = (pj_ioqueue_key_t*)dwKey;
+ size_status = dwBytesTransfered;
+ switch (pOv->operation) {
+ case PJ_IOQUEUE_OP_READ:
+ case PJ_IOQUEUE_OP_RECV:
+ case PJ_IOQUEUE_OP_RECV_FROM:
+ pOv->operation = 0;
+ if (key->cb.on_read_complete)
+ key->cb.on_read_complete(key, (pj_ioqueue_op_key_t*)pOv,
+ size_status);
+ break;
+ case PJ_IOQUEUE_OP_WRITE:
+ case PJ_IOQUEUE_OP_SEND:
+ case PJ_IOQUEUE_OP_SEND_TO:
+ pOv->operation = 0;
+ if (key->cb.on_write_complete)
+ key->cb.on_write_complete(key, (pj_ioqueue_op_key_t*)pOv,
+ size_status);
+ break;
+#if PJ_HAS_TCP
+ case PJ_IOQUEUE_OP_ACCEPT:
+ /* special case for accept. */
+ ioqueue_on_accept_complete((ioqueue_accept_rec*)pOv);
+ if (key->cb.on_accept_complete) {
+ ioqueue_accept_rec *accept_rec = (ioqueue_accept_rec*)pOv;
+ key->cb.on_accept_complete(key,
+ (pj_ioqueue_op_key_t*)pOv,
+ accept_rec->newsock,
+ PJ_SUCCESS);
+ }
+ break;
+ case PJ_IOQUEUE_OP_CONNECT:
+#endif
+ case PJ_IOQUEUE_OP_NONE:
+ pj_assert(0);
+ break;
+ }
+ return 1;
+ }
+
+ if (GetLastError()==WAIT_TIMEOUT) {
+ /* Check the connecting array (again). */
+#if PJ_HAS_TCP
+ key = check_connecting(ioqueue, &size_status);
+ if (key != NULL) {
+ key->cb.on_connect_complete(key, (int)size_status);
+ return 1;
+ }
+#endif
+ return 0;
+ }
+ return -1;
+}
+
+/*
+ * pj_ioqueue_recv()
+ *
+ * Initiate overlapped WSARecv() operation.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_recv( pj_ioqueue_key_t *key,
+ pj_ioqueue_op_key_t *op_key,
+ void *buffer,
+ pj_ssize_t *length,
+ unsigned flags )
+{
+ /*
+ * Ideally we should just call pj_ioqueue_recvfrom() with NULL addr and
+ * addrlen here. But unfortunately it generates EINVAL... :-(
+ * -bennylp
+ */
+ int rc;
+ DWORD bytesRead;
+ DWORD dwFlags = 0;
+ union operation_key *op_key_rec;
+
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(key && op_key && buffer && length, PJ_EINVAL);
+
+ op_key_rec = (union operation_key*)op_key->internal__;
+ op_key_rec->overlapped.wsabuf.buf = buffer;
+ op_key_rec->overlapped.wsabuf.len = *length;
+
+ dwFlags = flags;
+
+ /* Try non-overlapped received first to see if data is
+ * immediately available.
+ */
+ rc = WSARecv((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1,
+ &bytesRead, &dwFlags, NULL, NULL);
+ if (rc == 0) {
+ *length = bytesRead;
+ return PJ_SUCCESS;
+ } else {
+ DWORD dwError = WSAGetLastError();
+ if (dwError != WSAEWOULDBLOCK) {
+ *length = -1;
+ return PJ_RETURN_OS_ERROR(dwError);
+ }
+ }
+
+ /*
+ * No immediate data available.
+ * Register overlapped Recv() operation.
+ */
+ pj_memset(&op_key_rec->overlapped.overlapped, 0,
+ sizeof(op_key_rec->overlapped.overlapped));
+ op_key_rec->overlapped.operation = PJ_IOQUEUE_OP_RECV;
+
+ rc = WSARecv((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1,
+ &bytesRead, &dwFlags,
+ &op_key_rec->overlapped.overlapped, NULL);
+ if (rc == SOCKET_ERROR) {
+ DWORD dwStatus = WSAGetLastError();
+ if (dwStatus!=WSA_IO_PENDING) {
+ *length = -1;
+ return PJ_STATUS_FROM_OS(dwStatus);
+ }
+ }
+
+ /* Pending operation has been scheduled. */
+ return PJ_EPENDING;
+}
+
+/*
+ * pj_ioqueue_recvfrom()
+ *
+ * Initiate overlapped RecvFrom() operation.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_key_t *key,
+ pj_ioqueue_op_key_t *op_key,
+ void *buffer,
+ pj_ssize_t *length,
+ unsigned flags,
+ pj_sockaddr_t *addr,
+ int *addrlen)
+{
+ int rc;
+ DWORD bytesRead;
+ DWORD dwFlags = 0;
+ union operation_key *op_key_rec;
+
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(key && op_key && buffer, PJ_EINVAL);
+
+ op_key_rec = (union operation_key*)op_key->internal__;
+ op_key_rec->overlapped.wsabuf.buf = buffer;
+ op_key_rec->overlapped.wsabuf.len = *length;
+
+ dwFlags = flags;
+
+ /* Try non-overlapped received first to see if data is
+ * immediately available.
+ */
+ rc = WSARecvFrom((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1,
+ &bytesRead, &dwFlags, addr, addrlen, NULL, NULL);
+ if (rc == 0) {
+ *length = bytesRead;
+ return PJ_SUCCESS;
+ } else {
+ DWORD dwError = WSAGetLastError();
+ if (dwError != WSAEWOULDBLOCK) {
+ *length = -1;
+ return PJ_RETURN_OS_ERROR(dwError);
+ }
+ }
+
+ /*
+ * No immediate data available.
+ * Register overlapped Recv() operation.
+ */
+ pj_memset(&op_key_rec->overlapped.overlapped, 0,
+ sizeof(op_key_rec->overlapped.overlapped));
+ op_key_rec->overlapped.operation = PJ_IOQUEUE_OP_RECV;
+
+ rc = WSARecvFrom((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1,
+ &bytesRead, &dwFlags, addr, addrlen,
+ &op_key_rec->overlapped.overlapped, NULL);
+ if (rc == SOCKET_ERROR) {
+ DWORD dwStatus = WSAGetLastError();
+ if (dwStatus!=WSA_IO_PENDING) {
+ *length = -1;
+ return PJ_STATUS_FROM_OS(dwStatus);
+ }
+ }
+
+ /* Pending operation has been scheduled. */
+ return PJ_EPENDING;
+}
+
+/*
+ * pj_ioqueue_send()
+ *
+ * Initiate overlapped Send operation.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_send( pj_ioqueue_key_t *key,
+ pj_ioqueue_op_key_t *op_key,
+ const void *data,
+ pj_ssize_t *length,
+ unsigned flags )
+{
+ return pj_ioqueue_sendto(key, op_key, data, length, flags, NULL, 0);
+}
+
+
+/*
+ * pj_ioqueue_sendto()
+ *
+ * Initiate overlapped SendTo operation.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_key_t *key,
+ pj_ioqueue_op_key_t *op_key,
+ const void *data,
+ pj_ssize_t *length,
+ unsigned flags,
+ const pj_sockaddr_t *addr,
+ int addrlen)
+{
+ int rc;
+ DWORD bytesWritten;
+ DWORD dwFlags;
+ union operation_key *op_key_rec;
+
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(key && op_key && data, PJ_EINVAL);
+
+ op_key_rec = (union operation_key*)op_key->internal__;
+
+ dwFlags = flags;
+
+ /*
+ * First try blocking write.
+ */
+ op_key_rec->overlapped.wsabuf.buf = (void*)data;
+ op_key_rec->overlapped.wsabuf.len = *length;
+
+ rc = WSASendTo((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1,
+ &bytesWritten, dwFlags, addr, addrlen,
+ NULL, NULL);
+ if (rc == 0) {
+ *length = bytesWritten;
+ return PJ_SUCCESS;
+ } else {
+ DWORD dwStatus = WSAGetLastError();
+ if (dwStatus != WSAEWOULDBLOCK) {
+ *length = -1;
+ return PJ_RETURN_OS_ERROR(dwStatus);
+ }
+ }
+
+ /*
+ * Data can't be sent immediately.
+ * Schedule asynchronous WSASend().
+ */
+ pj_memset(&op_key_rec->overlapped.overlapped, 0,
+ sizeof(op_key_rec->overlapped.overlapped));
+ op_key_rec->overlapped.operation = PJ_IOQUEUE_OP_SEND;
+
+ rc = WSASendTo((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1,
+ &bytesWritten, dwFlags, addr, addrlen,
+ &op_key_rec->overlapped.overlapped, NULL);
+ if (rc == SOCKET_ERROR) {
+ DWORD dwStatus = WSAGetLastError();
+ if (dwStatus!=WSA_IO_PENDING)
+ return PJ_STATUS_FROM_OS(dwStatus);
+ }
+
+ /* Asynchronous operation successfully submitted. */
+ return PJ_EPENDING;
+}
+
+#if PJ_HAS_TCP
+
+/*
+ * pj_ioqueue_accept()
+ *
+ * Initiate overlapped accept() operation.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_accept( pj_ioqueue_key_t *key,
+ pj_ioqueue_op_key_t *op_key,
+ pj_sock_t *new_sock,
+ pj_sockaddr_t *local,
+ pj_sockaddr_t *remote,
+ int *addrlen)
+{
+ BOOL rc;
+ DWORD bytesReceived;
+ pj_status_t status;
+ union operation_key *op_key_rec;
+ SOCKET sock;
+
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(key && op_key && new_sock, PJ_EINVAL);
+
+ /*
+ * See if there is a new connection immediately available.
+ */
+ sock = WSAAccept((SOCKET)key->hnd, remote, addrlen, NULL, 0);
+ if (sock != INVALID_SOCKET) {
+ /* Yes! New socket is available! */
+ int status;
+
+ status = getsockname(sock, local, addrlen);
+ if (status != 0) {
+ DWORD dwError = WSAGetLastError();
+ closesocket(sock);
+ return PJ_RETURN_OS_ERROR(dwError);
+ }
+
+ *new_sock = sock;
+ return PJ_SUCCESS;
+
+ } else {
+ DWORD dwError = WSAGetLastError();
+ if (dwError != WSAEWOULDBLOCK) {
+ return PJ_RETURN_OS_ERROR(dwError);
+ }
+ }
+
+ /*
+ * No connection is immediately available.
+ * Must schedule an asynchronous operation.
+ */
+ op_key_rec = (union operation_key*)op_key->internal__;
+
+ status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, 0,
+ &op_key_rec->accept.newsock);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ /* On WinXP or later, use SO_UPDATE_ACCEPT_CONTEXT so that socket
+ * addresses can be obtained with getsockname() and getpeername().
+ */
+ status = setsockopt(op_key_rec->accept.newsock, SOL_SOCKET,
+ SO_UPDATE_ACCEPT_CONTEXT,
+ (char*)&key->hnd, sizeof(SOCKET));
+ /* SO_UPDATE_ACCEPT_CONTEXT is for WinXP or later.
+ * So ignore the error status.
+ */
+
+ op_key_rec->accept.operation = PJ_IOQUEUE_OP_ACCEPT;
+ op_key_rec->accept.addrlen = addrlen;
+ op_key_rec->accept.local = local;
+ op_key_rec->accept.remote = remote;
+ op_key_rec->accept.newsock_ptr = new_sock;
+ pj_memset(&op_key_rec->accept.overlapped, 0,
+ sizeof(op_key_rec->accept.overlapped));
+
+ rc = AcceptEx( (SOCKET)key->hnd, (SOCKET)op_key_rec->accept.newsock,
+ op_key_rec->accept.accept_buf,
+ 0, ACCEPT_ADDR_LEN, ACCEPT_ADDR_LEN,
+ &bytesReceived,
+ &op_key_rec->accept.overlapped );
+
+ if (rc == TRUE) {
+ ioqueue_on_accept_complete(&op_key_rec->accept);
+ return PJ_SUCCESS;
+ } else {
+ DWORD dwStatus = WSAGetLastError();
+ if (dwStatus!=WSA_IO_PENDING)
+ return PJ_STATUS_FROM_OS(dwStatus);
+ }
+
+ /* Asynchronous Accept() has been submitted. */
+ return PJ_EPENDING;
+}
+
+
+/*
+ * pj_ioqueue_connect()
+ *
+ * Initiate overlapped connect() operation (well, it's non-blocking actually,
+ * since there's no overlapped version of connect()).
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_key_t *key,
+ const pj_sockaddr_t *addr,
+ int addrlen )
+{
+ HANDLE hEvent;
+ pj_ioqueue_t *ioqueue;
+
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(key && addr && addrlen, PJ_EINVAL);
+
+ /* Initiate connect() */
+ if (connect((pj_sock_t)key->hnd, addr, addrlen) != 0) {
+ DWORD dwStatus;
+ dwStatus = WSAGetLastError();
+ if (dwStatus != WSAEWOULDBLOCK) {
+ return PJ_RETURN_OS_ERROR(dwStatus);
+ }
+ } else {
+ /* Connect has completed immediately! */
+ return PJ_SUCCESS;
+ }
+
+ ioqueue = key->ioqueue;
+
+ /* Add to the array of connecting socket to be polled */
+ pj_lock_acquire(ioqueue->lock);
+
+ if (ioqueue->connecting_count >= MAXIMUM_WAIT_OBJECTS) {
+ pj_lock_release(ioqueue->lock);
+ return PJ_ETOOMANYCONN;
+ }
+
+ /* Get or create event object. */
+ if (ioqueue->event_count) {
+ hEvent = ioqueue->event_pool[ioqueue->event_count - 1];
+ --ioqueue->event_count;
+ } else {
+ hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (hEvent == NULL) {
+ DWORD dwStatus = GetLastError();
+ pj_lock_release(ioqueue->lock);
+ return PJ_STATUS_FROM_OS(dwStatus);
+ }
+ }
+
+ /* Mark key as connecting.
+ * We can't use array index since key can be removed dynamically.
+ */
+ key->connecting = 1;
+
+ /* Associate socket events to the event object. */
+ if (WSAEventSelect((pj_sock_t)key->hnd, hEvent, FD_CONNECT) != 0) {
+ CloseHandle(hEvent);
+ pj_lock_release(ioqueue->lock);
+ return PJ_RETURN_OS_ERROR(WSAGetLastError());
+ }
+
+ /* Add to array. */
+ ioqueue->connecting_keys[ ioqueue->connecting_count ] = key;
+ ioqueue->connecting_handles[ ioqueue->connecting_count ] = hEvent;
+ ioqueue->connecting_count++;
+
+ pj_lock_release(ioqueue->lock);
+
+ return PJ_EPENDING;
+}
+#endif /* #if PJ_HAS_TCP */
+
PJ_DEF(void) pj_ioqueue_op_key_init( pj_ioqueue_op_key_t *op_key,
pj_size_t size )
diff --git a/pjlib/src/pj/list.c b/pjlib/src/pj/list.c
index a85108c0..3ffbfdca 100644
--- a/pjlib/src/pj/list.c
+++ b/pjlib/src/pj/list.c
@@ -1,9 +1,30 @@
-/* $Id$
- */
-#include <pj/list.h>
-
-#if !PJ_FUNCTIONS_ARE_INLINED
-# include <pj/list_i.h>
-#endif
-
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/list.h>
+
+#if !PJ_FUNCTIONS_ARE_INLINED
+# include <pj/list_i.h>
+#endif
+
+
diff --git a/pjlib/src/pj/lock.c b/pjlib/src/pj/lock.c
index a81e1325..ff6236af 100644
--- a/pjlib/src/pj/lock.c
+++ b/pjlib/src/pj/lock.c
@@ -1,178 +1,199 @@
-/* $Id$
- */
-#include <pj/lock.h>
-#include <pj/os.h>
-#include <pj/assert.h>
-#include <pj/pool.h>
-#include <pj/string.h>
-#include <pj/errno.h>
-
-
-typedef void LOCK_OBJ;
-
-/*
- * Lock structure.
- */
-struct pj_lock_t
-{
- LOCK_OBJ *lock_object;
-
- pj_status_t (*acquire) (LOCK_OBJ*);
- pj_status_t (*tryacquire) (LOCK_OBJ*);
- pj_status_t (*release) (LOCK_OBJ*);
- pj_status_t (*destroy) (LOCK_OBJ*);
-};
-
-typedef pj_status_t (*FPTR)(LOCK_OBJ*);
-
-/******************************************************************************
- * Implementation of lock object with mutex.
- */
-static pj_lock_t mutex_lock_template =
-{
- NULL,
- (FPTR) &pj_mutex_lock,
- (FPTR) &pj_mutex_trylock,
- (FPTR) &pj_mutex_unlock,
- (FPTR) &pj_mutex_destroy
-};
-
-static pj_status_t create_mutex_lock( pj_pool_t *pool,
- const char *name,
- int type,
- pj_lock_t **lock )
-{
- pj_lock_t *p_lock;
- pj_status_t rc;
-
- PJ_ASSERT_RETURN(pool && lock, PJ_EINVAL);
-
- p_lock = pj_pool_alloc(pool, sizeof(pj_lock_t));
- if (!p_lock)
- return PJ_ENOMEM;
-
- pj_memcpy(p_lock, &mutex_lock_template, sizeof(pj_lock_t));
- rc = pj_mutex_create(pool, name, type, (pj_mutex_t**)&p_lock->lock_object);
- if (rc != PJ_SUCCESS)
- return rc;
-
- *lock = p_lock;
- return PJ_SUCCESS;
-}
-
-
-PJ_DEF(pj_status_t) pj_lock_create_simple_mutex( pj_pool_t *pool,
- const char *name,
- pj_lock_t **lock )
-{
- return create_mutex_lock(pool, name, PJ_MUTEX_SIMPLE, lock);
-}
-
-PJ_DEF(pj_status_t) pj_lock_create_recursive_mutex( pj_pool_t *pool,
- const char *name,
- pj_lock_t **lock )
-{
- return create_mutex_lock(pool, name, PJ_MUTEX_RECURSE, lock);
-}
-
-
-/******************************************************************************
- * Implementation of NULL lock object.
- */
-static pj_status_t null_op(void *arg)
-{
- PJ_UNUSED_ARG(arg);
- return PJ_SUCCESS;
-}
-
-static pj_lock_t null_lock_template =
-{
- NULL,
- &null_op,
- &null_op,
- &null_op,
- &null_op
-};
-
-PJ_DEF(pj_status_t) pj_lock_create_null_mutex( pj_pool_t *pool,
- const char *name,
- pj_lock_t **lock )
-{
- PJ_UNUSED_ARG(name);
- PJ_UNUSED_ARG(pool);
-
- PJ_ASSERT_RETURN(lock, PJ_EINVAL);
-
- *lock = &null_lock_template;
- return PJ_SUCCESS;
-}
-
-
-/******************************************************************************
- * Implementation of semaphore lock object.
- */
-#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
-
-static pj_lock_t sem_lock_template =
-{
- NULL,
- (FPTR) &pj_sem_wait,
- (FPTR) &pj_sem_trywait,
- (FPTR) &pj_sem_post,
- (FPTR) &pj_sem_destroy
-};
-
-PJ_DEF(pj_status_t) pj_lock_create_semaphore( pj_pool_t *pool,
- const char *name,
- unsigned initial,
- unsigned max,
- pj_lock_t **lock )
-{
- pj_lock_t *p_lock;
- pj_status_t rc;
-
- PJ_ASSERT_RETURN(pool && lock, PJ_EINVAL);
-
- p_lock = pj_pool_alloc(pool, sizeof(pj_lock_t));
- if (!p_lock)
- return PJ_ENOMEM;
-
- pj_memcpy(p_lock, &sem_lock_template, sizeof(pj_lock_t));
- rc = pj_sem_create( pool, name, initial, max,
- (pj_sem_t**)&p_lock->lock_object);
- if (rc != PJ_SUCCESS)
- return rc;
-
- *lock = p_lock;
-
- return PJ_SUCCESS;
-}
-
-
-#endif /* PJ_HAS_SEMAPHORE */
-
-
-PJ_DEF(pj_status_t) pj_lock_acquire( pj_lock_t *lock )
-{
- PJ_ASSERT_RETURN(lock != NULL, PJ_EINVAL);
- return (*lock->acquire)(lock->lock_object);
-}
-
-PJ_DEF(pj_status_t) pj_lock_tryacquire( pj_lock_t *lock )
-{
- PJ_ASSERT_RETURN(lock != NULL, PJ_EINVAL);
- return (*lock->tryacquire)(lock->lock_object);
-}
-
-PJ_DEF(pj_status_t) pj_lock_release( pj_lock_t *lock )
-{
- PJ_ASSERT_RETURN(lock != NULL, PJ_EINVAL);
- return (*lock->release)(lock->lock_object);
-}
-
-PJ_DEF(pj_status_t) pj_lock_destroy( pj_lock_t *lock )
-{
- PJ_ASSERT_RETURN(lock != NULL, PJ_EINVAL);
- return (*lock->destroy)(lock->lock_object);
-}
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/lock.h>
+#include <pj/os.h>
+#include <pj/assert.h>
+#include <pj/pool.h>
+#include <pj/string.h>
+#include <pj/errno.h>
+
+
+typedef void LOCK_OBJ;
+
+/*
+ * Lock structure.
+ */
+struct pj_lock_t
+{
+ LOCK_OBJ *lock_object;
+
+ pj_status_t (*acquire) (LOCK_OBJ*);
+ pj_status_t (*tryacquire) (LOCK_OBJ*);
+ pj_status_t (*release) (LOCK_OBJ*);
+ pj_status_t (*destroy) (LOCK_OBJ*);
+};
+
+typedef pj_status_t (*FPTR)(LOCK_OBJ*);
+
+/******************************************************************************
+ * Implementation of lock object with mutex.
+ */
+static pj_lock_t mutex_lock_template =
+{
+ NULL,
+ (FPTR) &pj_mutex_lock,
+ (FPTR) &pj_mutex_trylock,
+ (FPTR) &pj_mutex_unlock,
+ (FPTR) &pj_mutex_destroy
+};
+
+static pj_status_t create_mutex_lock( pj_pool_t *pool,
+ const char *name,
+ int type,
+ pj_lock_t **lock )
+{
+ pj_lock_t *p_lock;
+ pj_status_t rc;
+
+ PJ_ASSERT_RETURN(pool && lock, PJ_EINVAL);
+
+ p_lock = pj_pool_alloc(pool, sizeof(pj_lock_t));
+ if (!p_lock)
+ return PJ_ENOMEM;
+
+ pj_memcpy(p_lock, &mutex_lock_template, sizeof(pj_lock_t));
+ rc = pj_mutex_create(pool, name, type, (pj_mutex_t**)&p_lock->lock_object);
+ if (rc != PJ_SUCCESS)
+ return rc;
+
+ *lock = p_lock;
+ return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pj_lock_create_simple_mutex( pj_pool_t *pool,
+ const char *name,
+ pj_lock_t **lock )
+{
+ return create_mutex_lock(pool, name, PJ_MUTEX_SIMPLE, lock);
+}
+
+PJ_DEF(pj_status_t) pj_lock_create_recursive_mutex( pj_pool_t *pool,
+ const char *name,
+ pj_lock_t **lock )
+{
+ return create_mutex_lock(pool, name, PJ_MUTEX_RECURSE, lock);
+}
+
+
+/******************************************************************************
+ * Implementation of NULL lock object.
+ */
+static pj_status_t null_op(void *arg)
+{
+ PJ_UNUSED_ARG(arg);
+ return PJ_SUCCESS;
+}
+
+static pj_lock_t null_lock_template =
+{
+ NULL,
+ &null_op,
+ &null_op,
+ &null_op,
+ &null_op
+};
+
+PJ_DEF(pj_status_t) pj_lock_create_null_mutex( pj_pool_t *pool,
+ const char *name,
+ pj_lock_t **lock )
+{
+ PJ_UNUSED_ARG(name);
+ PJ_UNUSED_ARG(pool);
+
+ PJ_ASSERT_RETURN(lock, PJ_EINVAL);
+
+ *lock = &null_lock_template;
+ return PJ_SUCCESS;
+}
+
+
+/******************************************************************************
+ * Implementation of semaphore lock object.
+ */
+#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
+
+static pj_lock_t sem_lock_template =
+{
+ NULL,
+ (FPTR) &pj_sem_wait,
+ (FPTR) &pj_sem_trywait,
+ (FPTR) &pj_sem_post,
+ (FPTR) &pj_sem_destroy
+};
+
+PJ_DEF(pj_status_t) pj_lock_create_semaphore( pj_pool_t *pool,
+ const char *name,
+ unsigned initial,
+ unsigned max,
+ pj_lock_t **lock )
+{
+ pj_lock_t *p_lock;
+ pj_status_t rc;
+
+ PJ_ASSERT_RETURN(pool && lock, PJ_EINVAL);
+
+ p_lock = pj_pool_alloc(pool, sizeof(pj_lock_t));
+ if (!p_lock)
+ return PJ_ENOMEM;
+
+ pj_memcpy(p_lock, &sem_lock_template, sizeof(pj_lock_t));
+ rc = pj_sem_create( pool, name, initial, max,
+ (pj_sem_t**)&p_lock->lock_object);
+ if (rc != PJ_SUCCESS)
+ return rc;
+
+ *lock = p_lock;
+
+ return PJ_SUCCESS;
+}
+
+
+#endif /* PJ_HAS_SEMAPHORE */
+
+
+PJ_DEF(pj_status_t) pj_lock_acquire( pj_lock_t *lock )
+{
+ PJ_ASSERT_RETURN(lock != NULL, PJ_EINVAL);
+ return (*lock->acquire)(lock->lock_object);
+}
+
+PJ_DEF(pj_status_t) pj_lock_tryacquire( pj_lock_t *lock )
+{
+ PJ_ASSERT_RETURN(lock != NULL, PJ_EINVAL);
+ return (*lock->tryacquire)(lock->lock_object);
+}
+
+PJ_DEF(pj_status_t) pj_lock_release( pj_lock_t *lock )
+{
+ PJ_ASSERT_RETURN(lock != NULL, PJ_EINVAL);
+ return (*lock->release)(lock->lock_object);
+}
+
+PJ_DEF(pj_status_t) pj_lock_destroy( pj_lock_t *lock )
+{
+ PJ_ASSERT_RETURN(lock != NULL, PJ_EINVAL);
+ return (*lock->destroy)(lock->lock_object);
+}
+
diff --git a/pjlib/src/pj/log.c b/pjlib/src/pj/log.c
index adbf98f6..92802ee3 100644
--- a/pjlib/src/pj/log.c
+++ b/pjlib/src/pj/log.c
@@ -1,208 +1,229 @@
-/* $Id$
- */
-#include <pj/types.h>
-#include <pj/log.h>
-#include <pj/string.h>
-#include <pj/os.h>
-#include <pj/compat/vsprintf.h>
-#include <pj/compat/stdarg.h>
-
-#if PJ_LOG_MAX_LEVEL >= 1
-
-static int log_max_level = PJ_LOG_MAX_LEVEL;
-static pj_log_func *log_writer = &pj_log_write;
-static unsigned log_decor = PJ_LOG_HAS_TIME | PJ_LOG_HAS_MICRO_SEC |
- PJ_LOG_HAS_SENDER | PJ_LOG_HAS_NEWLINE;
-
-#if PJ_LOG_USE_STACK_BUFFER==0
-static char log_buffer[PJ_LOG_MAX_SIZE];
-#endif
-
-PJ_DEF(void) pj_log_set_decor(unsigned decor)
-{
- log_decor = decor;
-}
-
-PJ_DEF(unsigned) pj_log_get_decor(void)
-{
- return log_decor;
-}
-
-PJ_DEF(void) pj_log_set_level(int level)
-{
- log_max_level = level;
-}
-
-PJ_DEF(int) pj_log_get_level(void)
-{
- return log_max_level;
-}
-
-PJ_DEF(void) pj_log_set_log_func( pj_log_func *func )
-{
- log_writer = func;
-}
-
-PJ_DEF(pj_log_func*) pj_log_get_log_func(void)
-{
- return log_writer;
-}
-
-static void pj_log(const char *sender, int level,
- const char *format, va_list marker)
-{
- pj_time_val now;
- pj_parsed_time ptime;
- char *pre;
-#if PJ_LOG_USE_STACK_BUFFER
- char log_buffer[PJ_LOG_MAX_SIZE];
-#endif
- int len;
-
- PJ_CHECK_STACK();
-
- if (level > log_max_level)
- return;
-
- /* Get current date/time. */
- pj_gettimeofday(&now);
- pj_time_decode(&now, &ptime);
-
- pre = log_buffer;
- if (log_decor & PJ_LOG_HAS_DAY_NAME) {
- static const char *wdays[] = { "Sun", "Mon", "Tue", "Wed",
- "Thu", "Fri", "Sat"};
- strcpy(pre, wdays[ptime.wday]);
- pre += 3;
- }
- if (log_decor & PJ_LOG_HAS_YEAR) {
- *pre++ = ' ';
- pre += pj_utoa(ptime.year, pre);
- }
- if (log_decor & PJ_LOG_HAS_MONTH) {
- *pre++ = '-';
- pre += pj_utoa_pad(ptime.mon, pre, 2, '0');
- }
- if (log_decor & PJ_LOG_HAS_DAY_OF_MON) {
- *pre++ = ' ';
- pre += pj_utoa_pad(ptime.day, pre, 2, '0');
- }
- if (log_decor & PJ_LOG_HAS_TIME) {
- *pre++ = ' ';
- pre += pj_utoa_pad(ptime.hour, pre, 2, '0');
- *pre++ = ':';
- pre += pj_utoa_pad(ptime.min, pre, 2, '0');
- *pre++ = ':';
- pre += pj_utoa_pad(ptime.sec, pre, 2, '0');
- }
- if (log_decor & PJ_LOG_HAS_MICRO_SEC) {
- *pre++ = '.';
- pre += pj_utoa_pad(ptime.msec, pre, 3, '0');
- }
- if (log_decor & PJ_LOG_HAS_SENDER) {
- enum { SENDER_WIDTH = 12 };
- int sender_len = strlen(sender);
- *pre++ = ' ';
- if (sender_len <= SENDER_WIDTH) {
- while (sender_len < SENDER_WIDTH)
- *pre++ = ' ', ++sender_len;
- while (*sender)
- *pre++ = *sender++;
- } else {
- int i;
- for (i=0; i<SENDER_WIDTH; ++i)
- *pre++ = *sender++;
- }
- }
-
- if (log_decor != 0 && log_decor != PJ_LOG_HAS_NEWLINE)
- *pre++ = ' ';
-
- len = pre - log_buffer;
-
- /* Print the whole message to the string log_buffer. */
- len = len + vsnprintf(pre, sizeof(log_buffer)-len, format, marker);
- if (len > 0 && len < sizeof(log_buffer)-1) {
- if (log_decor & PJ_LOG_HAS_NEWLINE) {
- log_buffer[len++] = '\n';
- }
- log_buffer[len++] = '\0';
- } else {
- len = sizeof(log_buffer)-1;
- if (log_decor & PJ_LOG_HAS_NEWLINE) {
- log_buffer[sizeof(log_buffer)-2] = '\n';
- }
- log_buffer[sizeof(log_buffer)-1] = '\0';
- }
-
- if (log_writer)
- (*log_writer)(level, log_buffer, len);
-}
-
-PJ_DEF(void) pj_log_0(const char *obj, const char *format, ...)
-{
- va_list arg;
- va_start(arg, format);
- pj_log(obj, 0, format, arg);
- va_end(arg);
-}
-
-PJ_DEF(void) pj_log_1(const char *obj, const char *format, ...)
-{
- va_list arg;
- va_start(arg, format);
- pj_log(obj, 1, format, arg);
- va_end(arg);
-}
-#endif /* PJ_LOG_MAX_LEVEL >= 1 */
-
-#if PJ_LOG_MAX_LEVEL >= 2
-PJ_DEF(void) pj_log_2(const char *obj, const char *format, ...)
-{
- va_list arg;
- va_start(arg, format);
- pj_log(obj, 2, format, arg);
- va_end(arg);
-}
-#endif
-
-#if PJ_LOG_MAX_LEVEL >= 3
-PJ_DEF(void) pj_log_3(const char *obj, const char *format, ...)
-{
- va_list arg;
- va_start(arg, format);
- pj_log(obj, 3, format, arg);
- va_end(arg);
-}
-#endif
-
-#if PJ_LOG_MAX_LEVEL >= 4
-PJ_DEF(void) pj_log_4(const char *obj, const char *format, ...)
-{
- va_list arg;
- va_start(arg, format);
- pj_log(obj, 4, format, arg);
- va_end(arg);
-}
-#endif
-
-#if PJ_LOG_MAX_LEVEL >= 5
-PJ_DEF(void) pj_log_5(const char *obj, const char *format, ...)
-{
- va_list arg;
- va_start(arg, format);
- pj_log(obj, 5, format, arg);
- va_end(arg);
-}
-#endif
-
-#if PJ_LOG_MAX_LEVEL >= 6
-PJ_DEF(void) pj_log_6(const char *obj, const char *format, ...)
-{
- va_list arg;
- va_start(arg, format);
- pj_log(obj, 6, format, arg);
- va_end(arg);
-}
-#endif
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/types.h>
+#include <pj/log.h>
+#include <pj/string.h>
+#include <pj/os.h>
+#include <pj/compat/vsprintf.h>
+#include <pj/compat/stdarg.h>
+
+#if PJ_LOG_MAX_LEVEL >= 1
+
+static int log_max_level = PJ_LOG_MAX_LEVEL;
+static pj_log_func *log_writer = &pj_log_write;
+static unsigned log_decor = PJ_LOG_HAS_TIME | PJ_LOG_HAS_MICRO_SEC |
+ PJ_LOG_HAS_SENDER | PJ_LOG_HAS_NEWLINE;
+
+#if PJ_LOG_USE_STACK_BUFFER==0
+static char log_buffer[PJ_LOG_MAX_SIZE];
+#endif
+
+PJ_DEF(void) pj_log_set_decor(unsigned decor)
+{
+ log_decor = decor;
+}
+
+PJ_DEF(unsigned) pj_log_get_decor(void)
+{
+ return log_decor;
+}
+
+PJ_DEF(void) pj_log_set_level(int level)
+{
+ log_max_level = level;
+}
+
+PJ_DEF(int) pj_log_get_level(void)
+{
+ return log_max_level;
+}
+
+PJ_DEF(void) pj_log_set_log_func( pj_log_func *func )
+{
+ log_writer = func;
+}
+
+PJ_DEF(pj_log_func*) pj_log_get_log_func(void)
+{
+ return log_writer;
+}
+
+static void pj_log(const char *sender, int level,
+ const char *format, va_list marker)
+{
+ pj_time_val now;
+ pj_parsed_time ptime;
+ char *pre;
+#if PJ_LOG_USE_STACK_BUFFER
+ char log_buffer[PJ_LOG_MAX_SIZE];
+#endif
+ int len;
+
+ PJ_CHECK_STACK();
+
+ if (level > log_max_level)
+ return;
+
+ /* Get current date/time. */
+ pj_gettimeofday(&now);
+ pj_time_decode(&now, &ptime);
+
+ pre = log_buffer;
+ if (log_decor & PJ_LOG_HAS_DAY_NAME) {
+ static const char *wdays[] = { "Sun", "Mon", "Tue", "Wed",
+ "Thu", "Fri", "Sat"};
+ strcpy(pre, wdays[ptime.wday]);
+ pre += 3;
+ }
+ if (log_decor & PJ_LOG_HAS_YEAR) {
+ *pre++ = ' ';
+ pre += pj_utoa(ptime.year, pre);
+ }
+ if (log_decor & PJ_LOG_HAS_MONTH) {
+ *pre++ = '-';
+ pre += pj_utoa_pad(ptime.mon, pre, 2, '0');
+ }
+ if (log_decor & PJ_LOG_HAS_DAY_OF_MON) {
+ *pre++ = ' ';
+ pre += pj_utoa_pad(ptime.day, pre, 2, '0');
+ }
+ if (log_decor & PJ_LOG_HAS_TIME) {
+ *pre++ = ' ';
+ pre += pj_utoa_pad(ptime.hour, pre, 2, '0');
+ *pre++ = ':';
+ pre += pj_utoa_pad(ptime.min, pre, 2, '0');
+ *pre++ = ':';
+ pre += pj_utoa_pad(ptime.sec, pre, 2, '0');
+ }
+ if (log_decor & PJ_LOG_HAS_MICRO_SEC) {
+ *pre++ = '.';
+ pre += pj_utoa_pad(ptime.msec, pre, 3, '0');
+ }
+ if (log_decor & PJ_LOG_HAS_SENDER) {
+ enum { SENDER_WIDTH = 12 };
+ int sender_len = strlen(sender);
+ *pre++ = ' ';
+ if (sender_len <= SENDER_WIDTH) {
+ while (sender_len < SENDER_WIDTH)
+ *pre++ = ' ', ++sender_len;
+ while (*sender)
+ *pre++ = *sender++;
+ } else {
+ int i;
+ for (i=0; i<SENDER_WIDTH; ++i)
+ *pre++ = *sender++;
+ }
+ }
+
+ if (log_decor != 0 && log_decor != PJ_LOG_HAS_NEWLINE)
+ *pre++ = ' ';
+
+ len = pre - log_buffer;
+
+ /* Print the whole message to the string log_buffer. */
+ len = len + vsnprintf(pre, sizeof(log_buffer)-len, format, marker);
+ if (len > 0 && len < sizeof(log_buffer)-1) {
+ if (log_decor & PJ_LOG_HAS_NEWLINE) {
+ log_buffer[len++] = '\n';
+ }
+ log_buffer[len++] = '\0';
+ } else {
+ len = sizeof(log_buffer)-1;
+ if (log_decor & PJ_LOG_HAS_NEWLINE) {
+ log_buffer[sizeof(log_buffer)-2] = '\n';
+ }
+ log_buffer[sizeof(log_buffer)-1] = '\0';
+ }
+
+ if (log_writer)
+ (*log_writer)(level, log_buffer, len);
+}
+
+PJ_DEF(void) pj_log_0(const char *obj, const char *format, ...)
+{
+ va_list arg;
+ va_start(arg, format);
+ pj_log(obj, 0, format, arg);
+ va_end(arg);
+}
+
+PJ_DEF(void) pj_log_1(const char *obj, const char *format, ...)
+{
+ va_list arg;
+ va_start(arg, format);
+ pj_log(obj, 1, format, arg);
+ va_end(arg);
+}
+#endif /* PJ_LOG_MAX_LEVEL >= 1 */
+
+#if PJ_LOG_MAX_LEVEL >= 2
+PJ_DEF(void) pj_log_2(const char *obj, const char *format, ...)
+{
+ va_list arg;
+ va_start(arg, format);
+ pj_log(obj, 2, format, arg);
+ va_end(arg);
+}
+#endif
+
+#if PJ_LOG_MAX_LEVEL >= 3
+PJ_DEF(void) pj_log_3(const char *obj, const char *format, ...)
+{
+ va_list arg;
+ va_start(arg, format);
+ pj_log(obj, 3, format, arg);
+ va_end(arg);
+}
+#endif
+
+#if PJ_LOG_MAX_LEVEL >= 4
+PJ_DEF(void) pj_log_4(const char *obj, const char *format, ...)
+{
+ va_list arg;
+ va_start(arg, format);
+ pj_log(obj, 4, format, arg);
+ va_end(arg);
+}
+#endif
+
+#if PJ_LOG_MAX_LEVEL >= 5
+PJ_DEF(void) pj_log_5(const char *obj, const char *format, ...)
+{
+ va_list arg;
+ va_start(arg, format);
+ pj_log(obj, 5, format, arg);
+ va_end(arg);
+}
+#endif
+
+#if PJ_LOG_MAX_LEVEL >= 6
+PJ_DEF(void) pj_log_6(const char *obj, const char *format, ...)
+{
+ va_list arg;
+ va_start(arg, format);
+ pj_log(obj, 6, format, arg);
+ va_end(arg);
+}
+#endif
+
diff --git a/pjlib/src/pj/log_writer_printk.c b/pjlib/src/pj/log_writer_printk.c
index 2581ef25..da205981 100644
--- a/pjlib/src/pj/log_writer_printk.c
+++ b/pjlib/src/pj/log_writer_printk.c
@@ -1,12 +1,33 @@
-/* $Id$
- *
- */
-#include <pj/log.h>
-#include <pj/os.h>
-
-PJ_DEF(void) pj_log_write(int level, const char *buffer, int len)
-{
- PJ_CHECK_STACK();
- printk(KERN_INFO "%s", buffer);
-}
-
+/* $Id$
+ *
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/log.h>
+#include <pj/os.h>
+
+PJ_DEF(void) pj_log_write(int level, const char *buffer, int len)
+{
+ PJ_CHECK_STACK();
+ printk(KERN_INFO "%s", buffer);
+}
+
diff --git a/pjlib/src/pj/log_writer_stdout.c b/pjlib/src/pj/log_writer_stdout.c
index 196f1c3b..d3010022 100644
--- a/pjlib/src/pj/log_writer_stdout.c
+++ b/pjlib/src/pj/log_writer_stdout.c
@@ -1,54 +1,75 @@
-/* $Id$
- */
-#include <pj/log.h>
-#include <pj/os.h>
-#include <pj/compat/stdfileio.h>
-
-#define CLR_FATAL (PJ_TERM_COLOR_BRIGHT | PJ_TERM_COLOR_R)
-#define CLR_WARNING (PJ_TERM_COLOR_BRIGHT | PJ_TERM_COLOR_R | PJ_TERM_COLOR_G)
-#define CLR_INFO (PJ_TERM_COLOR_BRIGHT | PJ_TERM_COLOR_R | PJ_TERM_COLOR_G | \
- PJ_TERM_COLOR_B)
-#define CLR_DEFAULT (PJ_TERM_COLOR_R | PJ_TERM_COLOR_G | PJ_TERM_COLOR_B)
-
-static void term_set_color(int level)
-{
-#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0
- unsigned attr = 0;
- switch (level) {
- case 0:
- case 1: attr = CLR_FATAL;
- break;
- case 2: attr = CLR_WARNING;
- break;
- case 3: attr = CLR_INFO;
- break;
- default:
- attr = CLR_DEFAULT;
- break;
- }
-
- pj_term_set_color(attr);
-#endif
-}
-
-static void term_restore_color(void)
-{
-#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0
- pj_term_set_color(CLR_DEFAULT);
-#endif
-}
-
-
-PJ_DEF(void) pj_log_write(int level, const char *buffer, int len)
-{
- PJ_CHECK_STACK();
- PJ_UNUSED_ARG(len);
-
- /* Copy to terminal/file. */
- term_set_color(level);
- fputs(buffer, stdout);
- term_restore_color();
-
- fflush(stdout);
-}
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/log.h>
+#include <pj/os.h>
+#include <pj/compat/stdfileio.h>
+
+#define CLR_FATAL (PJ_TERM_COLOR_BRIGHT | PJ_TERM_COLOR_R)
+#define CLR_WARNING (PJ_TERM_COLOR_BRIGHT | PJ_TERM_COLOR_R | PJ_TERM_COLOR_G)
+#define CLR_INFO (PJ_TERM_COLOR_BRIGHT | PJ_TERM_COLOR_R | PJ_TERM_COLOR_G | \
+ PJ_TERM_COLOR_B)
+#define CLR_DEFAULT (PJ_TERM_COLOR_R | PJ_TERM_COLOR_G | PJ_TERM_COLOR_B)
+
+static void term_set_color(int level)
+{
+#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0
+ unsigned attr = 0;
+ switch (level) {
+ case 0:
+ case 1: attr = CLR_FATAL;
+ break;
+ case 2: attr = CLR_WARNING;
+ break;
+ case 3: attr = CLR_INFO;
+ break;
+ default:
+ attr = CLR_DEFAULT;
+ break;
+ }
+
+ pj_term_set_color(attr);
+#endif
+}
+
+static void term_restore_color(void)
+{
+#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0
+ pj_term_set_color(CLR_DEFAULT);
+#endif
+}
+
+
+PJ_DEF(void) pj_log_write(int level, const char *buffer, int len)
+{
+ PJ_CHECK_STACK();
+ PJ_UNUSED_ARG(len);
+
+ /* Copy to terminal/file. */
+ term_set_color(level);
+ fputs(buffer, stdout);
+ term_restore_color();
+
+ fflush(stdout);
+}
+
diff --git a/pjlib/src/pj/os_core_linux_kernel.c b/pjlib/src/pj/os_core_linux_kernel.c
index 14337087..2bb2acfd 100644
--- a/pjlib/src/pj/os_core_linux_kernel.c
+++ b/pjlib/src/pj/os_core_linux_kernel.c
@@ -1,674 +1,695 @@
-/* $Id$
- *
- */
-#include <pj/os.h>
-#include <pj/assert.h>
-#include <pj/pool.h>
-#include <pj/log.h>
-#include <pj/except.h>
-#include <pj/errno.h>
-#include <pj/string.h>
-#include <pj/compat/high_precision.h>
-#include <pj/compat/sprintf.h>
-
-#include <linux/config.h>
-#include <linux/version.h>
-#if defined(MODVERSIONS)
-#include <linux/modversions.h>
-#endif
-#include <linux/kernel.h>
-#include <linux/sched.h>
-//#include <linux/tqueue.h>
-#include <linux/wait.h>
-#include <linux/signal.h>
-
-#include <asm/atomic.h>
-#include <asm/unistd.h>
-#include <asm/semaphore.h>
-
-#define THIS_FILE "oslinuxkern"
-
-struct pj_thread_t
-{
- /** Thread's name. */
- char obj_name[PJ_MAX_OBJ_NAME];
-
- /** Linux task structure for thread. */
- struct task_struct *thread;
-
- /** Flags (specified in pj_thread_create) */
- unsigned flags;
-
- /** Task queue needed to launch thread. */
- //struct tq_struct tq;
-
- /** Semaphore needed to control thread startup. */
- struct semaphore startstop_sem;
-
- /** Semaphore to suspend thread during startup. */
- struct semaphore suspend_sem;
-
- /** Queue thread is waiting on. Gets initialized by
- thread_initialize, can be used by thread itself.
- */
- wait_queue_head_t queue;
-
- /** Flag to tell thread whether to die or not.
- When the thread receives a signal, it must check
- the value of terminate and call thread_deinitialize and terminate
- if set.
- */
- int terminate;
-
- /** Thread's entry. */
- pj_thread_proc *func;
-
- /** Argument. */
- void *arg;
-};
-
-struct pj_atomic_t
-{
- atomic_t atom;
-};
-
-struct pj_mutex_t
-{
- struct semaphore sem;
- pj_bool_t recursive;
- pj_thread_t *owner;
- int own_count;
-};
-
-struct pj_sem_t
-{
- struct semaphore sem;
-};
-
-/*
- * Static global variables.
- */
-#define MAX_TLS_ID 32
-static void *tls_values[MAX_TLS_ID];
-static int tls_id;
-static long thread_tls_id;
-static spinlock_t critical_section = SPIN_LOCK_UNLOCKED;
-static unsigned long spinlock_flags;
-static pj_thread_t main_thread;
-
-/* private functions */
-//#define TRACE_(expr) PJ_LOG(3,expr)
-#define TRACE_(x)
-
-
-/* This must be called in the context of the new thread. */
-static void thread_initialize( pj_thread_t *thread )
-{
- TRACE_((THIS_FILE, "---new thread initializing..."));
-
- /* Set TLS */
- pj_thread_local_set(thread_tls_id, thread);
-
- /* fill in thread structure */
- thread->thread = current;
- pj_assert(thread->thread != NULL);
-
- /* set signal mask to what we want to respond */
- siginitsetinv(&current->blocked,
- sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM));
-
- /* initialise wait queue */
- init_waitqueue_head(&thread->queue);
-
- /* initialise termination flag */
- thread->terminate = 0;
-
- /* set name of this process (max 15 chars + 0 !) */
- thread->obj_name[15] = '\0';
- sprintf(current->comm, thread->obj_name);
-
- /* tell the creator that we are ready and let him continue */
- up(&thread->startstop_sem);
-}
-
-/* cleanup of thread. Called by the exiting thread. */
-static void thread_deinitialize(pj_thread_t *thread)
-{
- /* we are terminating */
-
- /* lock the kernel, the exit will unlock it */
- thread->thread = NULL;
- mb();
-
- /* notify the stop_kthread() routine that we are terminating. */
- up(&thread->startstop_sem);
-
- /* the kernel_thread that called clone() does a do_exit here. */
-
- /* there is no race here between execution of the "killer" and
- real termination of the thread (race window between up and do_exit),
- since both the thread and the "killer" function are running with
- the kernel lock held.
- The kernel lock will be freed after the thread exited, so the code
- is really not executed anymore as soon as the unload functions gets
- the kernel lock back.
- The init process may not have made the cleanup of the process here,
- but the cleanup can be done safely with the module unloaded.
- */
-
-}
-
-static int thread_proc(void *arg)
-{
- pj_thread_t *thread = arg;
-
- TRACE_((THIS_FILE, "---new thread starting!"));
-
- /* Initialize thread. */
- thread_initialize( thread );
-
- /* Wait if created suspended. */
- if (thread->flags & PJ_THREAD_SUSPENDED) {
- TRACE_((THIS_FILE, "---new thread suspended..."));
- down(&thread->suspend_sem);
- }
-
- TRACE_((THIS_FILE, "---new thread running..."));
-
- pj_assert(thread->func != NULL);
-
- /* Call thread's entry. */
- (*thread->func)(thread->arg);
-
- TRACE_((THIS_FILE, "---thread exiting..."));
-
- /* Cleanup thread. */
- thread_deinitialize(thread);
-
- return 0;
-}
-
-/* The very task entry. */
-static void kthread_launcher(void *arg)
-{
- TRACE_((THIS_FILE, "...launching thread!..."));
- kernel_thread(&thread_proc, arg, 0);
-}
-
-PJ_DEF(pj_status_t) pj_init(void)
-{
- pj_status_t rc;
-
- PJ_LOG(5, ("pj_init", "Initializing PJ Library.."));
-
- rc = pj_thread_init();
- if (rc != PJ_SUCCESS)
- return rc;
-
- /* Initialize exception ID for the pool.
- * Must do so after critical section is configured.
- */
- rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION);
- if (rc != PJ_SUCCESS)
- return rc;
-
- return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_uint32_t) pj_getpid(void)
-{
- return 1;
-}
-
-PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name,
- pj_thread_desc desc,
- pj_thread_t **ptr_thread)
-{
- char stack_ptr;
- pj_thread_t *thread = (pj_thread_t *)desc;
- pj_str_t thread_name = pj_str((char*)cstr_thread_name);
-
- /* Size sanity check. */
- if (sizeof(pj_thread_desc) < sizeof(pj_thread_t)) {
- pj_assert(!"Not enough pj_thread_desc size!");
- return PJ_EBUG;
- }
-
- /* If a thread descriptor has been registered before, just return it. */
- if (pj_thread_local_get (thread_tls_id) != 0) {
- *ptr_thread = (pj_thread_t*)pj_thread_local_get (thread_tls_id);
- return PJ_SUCCESS;
- }
-
- /* Initialize and set the thread entry. */
- pj_memset(desc, 0, sizeof(struct pj_thread_t));
-
- if(cstr_thread_name && pj_strlen(&thread_name) < sizeof(thread->obj_name)-1)
- pj_sprintf(thread->obj_name, cstr_thread_name, thread->thread);
- else
- pj_sprintf(thread->obj_name, "thr%p", (void*)thread->thread);
-
- /* Initialize. */
- thread_initialize(thread);
-
- /* Eat semaphore. */
- down(&thread->startstop_sem);
-
-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
- thread->stk_start = &stack_ptr;
- thread->stk_size = 0xFFFFFFFFUL;
- thread->stk_max_usage = 0;
-#else
- stack_ptr = '\0';
-#endif
-
- *ptr_thread = thread;
- return PJ_SUCCESS;
-}
-
-
-pj_status_t pj_thread_init(void)
-{
- pj_status_t rc;
- pj_thread_t *dummy;
-
- rc = pj_thread_local_alloc(&thread_tls_id);
- if (rc != PJ_SUCCESS)
- return rc;
-
- return pj_thread_register("pjlib-main", (long*)&main_thread, &dummy);
-}
-
-PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool, const char *thread_name,
- pj_thread_proc *proc, void *arg,
- pj_size_t stack_size, unsigned flags,
- pj_thread_t **ptr_thread)
-{
- pj_thread_t *thread;
-
- TRACE_((THIS_FILE, "pj_thread_create()"));
-
- PJ_ASSERT_RETURN(pool && proc && ptr_thread, PJ_EINVAL);
-
- thread = pj_pool_zalloc(pool, sizeof(pj_thread_t));
- if (!thread)
- return PJ_ENOMEM;
-
- PJ_UNUSED_ARG(stack_size);
-
- /* Thread name. */
- if (!thread_name)
- thread_name = "thr%p";
-
- if (strchr(thread_name, '%')) {
- pj_snprintf(thread->obj_name, PJ_MAX_OBJ_NAME, thread_name, thread);
- } else {
- strncpy(thread->obj_name, thread_name, PJ_MAX_OBJ_NAME);
- thread->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
- }
-
- /* Init thread's semaphore. */
- TRACE_((THIS_FILE, "...init semaphores..."));
- init_MUTEX_LOCKED(&thread->startstop_sem);
- init_MUTEX_LOCKED(&thread->suspend_sem);
-
- thread->flags = flags;
-
- if ((flags & PJ_THREAD_SUSPENDED) == 0) {
- up(&thread->suspend_sem);
- }
-
- /* Store the functions and argument. */
- thread->func = proc;
- thread->arg = arg;
-
- /* Save return value. */
- *ptr_thread = thread;
-
- /* Create the new thread by running a task through keventd. */
-
-#if 0
- /* Initialize the task queue struct. */
- thread->tq.sync = 0;
- INIT_LIST_HEAD(&thread->tq.list);
- thread->tq.routine = kthread_launcher;
- thread->tq.data = thread;
-
- /* and schedule it for execution. */
- schedule_task(&thread->tq);
-#endif
- kthread_launcher(thread);
-
- /* Wait until thread has reached the setup_thread routine. */
- TRACE_((THIS_FILE, "...wait for the new thread..."));
- down(&thread->startstop_sem);
-
- TRACE_((THIS_FILE, "...main thread resumed..."));
- return PJ_SUCCESS;
-}
-
-PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *thread)
-{
- return thread->obj_name;
-}
-
-PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *thread)
-{
- up(&thread->suspend_sem);
- return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_thread_t*) pj_thread_this(void)
-{
- return (pj_thread_t*)pj_thread_local_get(thread_tls_id);
-}
-
-PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p)
-{
- TRACE_((THIS_FILE, "pj_thread_join()"));
- down(&p->startstop_sem);
- TRACE_((THIS_FILE, " joined!"));
- return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *thread)
-{
- PJ_ASSERT_RETURN(thread != NULL, PJ_EINVALIDOP);
- return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec)
-{
- pj_highprec_t ticks;
- pj_thread_t *thread = pj_thread_this();
-
- PJ_ASSERT_RETURN(thread != NULL, PJ_EBUG);
-
- /* Use high precision calculation to make sure we don't
- * crop values:
- *
- * ticks = HZ * msec / 1000
- */
- ticks = HZ;
- pj_highprec_mul(ticks, msec);
- pj_highprec_div(ticks, 1000);
-
- TRACE_((THIS_FILE, "this thread will sleep for %u ticks", ticks));
- interruptible_sleep_on_timeout( &thread->queue, ticks);
- return PJ_SUCCESS;
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool,
- pj_atomic_value_t value,
- pj_atomic_t **ptr_var)
-{
- pj_atomic_t *t = pj_pool_calloc(pool, 1, sizeof(pj_atomic_t));
- if (!t) return PJ_ENOMEM;
-
- atomic_set(&t->atom, value);
- *ptr_var = t;
-
- return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *var )
-{
- return PJ_SUCCESS;
-}
-
-PJ_DEF(void) pj_atomic_set(pj_atomic_t *var, pj_atomic_value_t value)
-{
- atomic_set(&var->atom, value);
-}
-
-PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *var)
-{
- return atomic_read(&var->atom);
-}
-
-PJ_DEF(void) pj_atomic_inc(pj_atomic_t *var)
-{
- atomic_inc(&var->atom);
-}
-
-PJ_DEF(void) pj_atomic_dec(pj_atomic_t *var)
-{
- atomic_dec(&var->atom);
-}
-
-PJ_DEF(void) pj_atomic_add( pj_atomic_t *var, pj_atomic_value_t value )
-{
- atomic_add(value, &var->atom);
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-PJ_DEF(pj_status_t) pj_thread_local_alloc(long *index)
-{
- if (tls_id >= MAX_TLS_ID)
- return PJ_ETOOMANY;
-
- *index = tls_id++;
-
- return PJ_SUCCESS;
-}
-
-PJ_DEF(void) pj_thread_local_free(long index)
-{
- pj_assert(index >= 0 && index < MAX_TLS_ID);
-}
-
-PJ_DEF(pj_status_t) pj_thread_local_set(long index, void *value)
-{
- pj_assert(index >= 0 && index < MAX_TLS_ID);
- tls_values[index] = value;
- return PJ_SUCCESS;
-}
-
-PJ_DEF(void*) pj_thread_local_get(long index)
-{
- pj_assert(index >= 0 && index < MAX_TLS_ID);
- return tls_values[index];
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-PJ_DEF(void) pj_enter_critical_section(void)
-{
- spin_lock_irqsave(&critical_section, spinlock_flags);
-}
-
-PJ_DEF(void) pj_leave_critical_section(void)
-{
- spin_unlock_irqrestore(&critical_section, spinlock_flags);
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-PJ_DEF(pj_status_t) pj_mutex_create( pj_pool_t *pool,
- const char *name,
- int type,
- pj_mutex_t **ptr_mutex)
-{
- pj_mutex_t *mutex;
-
- PJ_UNUSED_ARG(name);
-
- mutex = pj_pool_alloc(pool, sizeof(pj_mutex_t));
- if (!mutex)
- return PJ_ENOMEM;
-
- init_MUTEX(&mutex->sem);
-
- mutex->recursive = (type == PJ_MUTEX_RECURSE);
- mutex->owner = NULL;
- mutex->own_count = 0;
-
- /* Done. */
- *ptr_mutex = mutex;
- return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool, const char *name,
- pj_mutex_t **mutex )
-{
- return pj_mutex_create(pool, name, PJ_MUTEX_SIMPLE, mutex);
-}
-
-PJ_DEF(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool,
- const char *name,
- pj_mutex_t **mutex )
-{
- return pj_mutex_create( pool, name, PJ_MUTEX_RECURSE, mutex);
-}
-
-PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex)
-{
- PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
-
- if (mutex->recursive) {
- pj_thread_t *this_thread = pj_thread_this();
- if (mutex->owner == this_thread) {
- ++mutex->own_count;
- } else {
- down(&mutex->sem);
- pj_assert(mutex->own_count == 0);
- mutex->owner = this_thread;
- mutex->own_count = 1;
- }
- } else {
- down(&mutex->sem);
- }
- return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex)
-{
- long rc;
-
- PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
-
- if (mutex->recursive) {
- pj_thread_t *this_thread = pj_thread_this();
- if (mutex->owner == this_thread) {
- ++mutex->own_count;
- } else {
- rc = down_interruptible(&mutex->sem);
- if (rc != 0)
- return PJ_RETURN_OS_ERROR(-rc);
- pj_assert(mutex->own_count == 0);
- mutex->owner = this_thread;
- mutex->own_count = 1;
- }
- } else {
- int rc = down_trylock(&mutex->sem);
- if (rc != 0)
- return PJ_RETURN_OS_ERROR(-rc);
- }
- return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex)
-{
- PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
-
- if (mutex->recursive) {
- pj_thread_t *this_thread = pj_thread_this();
- if (mutex->owner == this_thread) {
- pj_assert(mutex->own_count > 0);
- --mutex->own_count;
- if (mutex->own_count == 0) {
- mutex->owner = NULL;
- up(&mutex->sem);
- }
- } else {
- pj_assert(!"Not owner!");
- return PJ_EINVALIDOP;
- }
- } else {
- up(&mutex->sem);
- }
- return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex)
-{
- PJ_ASSERT_RETURN(mutex != NULL, PJ_EINVAL);
-
- return PJ_SUCCESS;
-}
-
-#if defined(PJ_DEBUG) && PJ_DEBUG != 0
-PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex)
-{
- if (mutex->recursive)
- return mutex->owner == pj_thread_this();
- else
- return 1;
-}
-#endif /* PJ_DEBUG */
-
-
-#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
-
-PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool,
- const char *name,
- unsigned initial,
- unsigned max,
- pj_sem_t **sem)
-{
- pj_sem_t *sem;
-
- PJ_UNUSED_ARG(max);
-
- PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
-
- sem = pj_pool_alloc(pool, sizeof(pj_sem_t));
- sema_init(&sem->sem, initial);
- return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem)
-{
- PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
-
- down(&sem->sem);
- return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem)
-{
- int rc;
-
- PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
-
- rc = down_trylock(&sem->sem);
- if (rc != 0) {
- return PJ_RETURN_OS_ERROR(-rc);
- } else {
- return PJ_SUCCESS;
- }
-}
-
-PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem)
-{
- PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
-
- up(&sem->sem);
- return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem)
-{
- PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
-
- return PJ_SUCCESS;
-}
-
-#endif /* PJ_HAS_SEMAPHORE */
-
-
-
-
+/* $Id$
+ *
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/os.h>
+#include <pj/assert.h>
+#include <pj/pool.h>
+#include <pj/log.h>
+#include <pj/except.h>
+#include <pj/errno.h>
+#include <pj/string.h>
+#include <pj/compat/high_precision.h>
+#include <pj/compat/sprintf.h>
+
+#include <linux/config.h>
+#include <linux/version.h>
+#if defined(MODVERSIONS)
+#include <linux/modversions.h>
+#endif
+#include <linux/kernel.h>
+#include <linux/sched.h>
+//#include <linux/tqueue.h>
+#include <linux/wait.h>
+#include <linux/signal.h>
+
+#include <asm/atomic.h>
+#include <asm/unistd.h>
+#include <asm/semaphore.h>
+
+#define THIS_FILE "oslinuxkern"
+
+struct pj_thread_t
+{
+ /** Thread's name. */
+ char obj_name[PJ_MAX_OBJ_NAME];
+
+ /** Linux task structure for thread. */
+ struct task_struct *thread;
+
+ /** Flags (specified in pj_thread_create) */
+ unsigned flags;
+
+ /** Task queue needed to launch thread. */
+ //struct tq_struct tq;
+
+ /** Semaphore needed to control thread startup. */
+ struct semaphore startstop_sem;
+
+ /** Semaphore to suspend thread during startup. */
+ struct semaphore suspend_sem;
+
+ /** Queue thread is waiting on. Gets initialized by
+ thread_initialize, can be used by thread itself.
+ */
+ wait_queue_head_t queue;
+
+ /** Flag to tell thread whether to die or not.
+ When the thread receives a signal, it must check
+ the value of terminate and call thread_deinitialize and terminate
+ if set.
+ */
+ int terminate;
+
+ /** Thread's entry. */
+ pj_thread_proc *func;
+
+ /** Argument. */
+ void *arg;
+};
+
+struct pj_atomic_t
+{
+ atomic_t atom;
+};
+
+struct pj_mutex_t
+{
+ struct semaphore sem;
+ pj_bool_t recursive;
+ pj_thread_t *owner;
+ int own_count;
+};
+
+struct pj_sem_t
+{
+ struct semaphore sem;
+};
+
+/*
+ * Static global variables.
+ */
+#define MAX_TLS_ID 32
+static void *tls_values[MAX_TLS_ID];
+static int tls_id;
+static long thread_tls_id;
+static spinlock_t critical_section = SPIN_LOCK_UNLOCKED;
+static unsigned long spinlock_flags;
+static pj_thread_t main_thread;
+
+/* private functions */
+//#define TRACE_(expr) PJ_LOG(3,expr)
+#define TRACE_(x)
+
+
+/* This must be called in the context of the new thread. */
+static void thread_initialize( pj_thread_t *thread )
+{
+ TRACE_((THIS_FILE, "---new thread initializing..."));
+
+ /* Set TLS */
+ pj_thread_local_set(thread_tls_id, thread);
+
+ /* fill in thread structure */
+ thread->thread = current;
+ pj_assert(thread->thread != NULL);
+
+ /* set signal mask to what we want to respond */
+ siginitsetinv(&current->blocked,
+ sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM));
+
+ /* initialise wait queue */
+ init_waitqueue_head(&thread->queue);
+
+ /* initialise termination flag */
+ thread->terminate = 0;
+
+ /* set name of this process (max 15 chars + 0 !) */
+ thread->obj_name[15] = '\0';
+ sprintf(current->comm, thread->obj_name);
+
+ /* tell the creator that we are ready and let him continue */
+ up(&thread->startstop_sem);
+}
+
+/* cleanup of thread. Called by the exiting thread. */
+static void thread_deinitialize(pj_thread_t *thread)
+{
+ /* we are terminating */
+
+ /* lock the kernel, the exit will unlock it */
+ thread->thread = NULL;
+ mb();
+
+ /* notify the stop_kthread() routine that we are terminating. */
+ up(&thread->startstop_sem);
+
+ /* the kernel_thread that called clone() does a do_exit here. */
+
+ /* there is no race here between execution of the "killer" and
+ real termination of the thread (race window between up and do_exit),
+ since both the thread and the "killer" function are running with
+ the kernel lock held.
+ The kernel lock will be freed after the thread exited, so the code
+ is really not executed anymore as soon as the unload functions gets
+ the kernel lock back.
+ The init process may not have made the cleanup of the process here,
+ but the cleanup can be done safely with the module unloaded.
+ */
+
+}
+
+static int thread_proc(void *arg)
+{
+ pj_thread_t *thread = arg;
+
+ TRACE_((THIS_FILE, "---new thread starting!"));
+
+ /* Initialize thread. */
+ thread_initialize( thread );
+
+ /* Wait if created suspended. */
+ if (thread->flags & PJ_THREAD_SUSPENDED) {
+ TRACE_((THIS_FILE, "---new thread suspended..."));
+ down(&thread->suspend_sem);
+ }
+
+ TRACE_((THIS_FILE, "---new thread running..."));
+
+ pj_assert(thread->func != NULL);
+
+ /* Call thread's entry. */
+ (*thread->func)(thread->arg);
+
+ TRACE_((THIS_FILE, "---thread exiting..."));
+
+ /* Cleanup thread. */
+ thread_deinitialize(thread);
+
+ return 0;
+}
+
+/* The very task entry. */
+static void kthread_launcher(void *arg)
+{
+ TRACE_((THIS_FILE, "...launching thread!..."));
+ kernel_thread(&thread_proc, arg, 0);
+}
+
+PJ_DEF(pj_status_t) pj_init(void)
+{
+ pj_status_t rc;
+
+ PJ_LOG(5, ("pj_init", "Initializing PJ Library.."));
+
+ rc = pj_thread_init();
+ if (rc != PJ_SUCCESS)
+ return rc;
+
+ /* Initialize exception ID for the pool.
+ * Must do so after critical section is configured.
+ */
+ rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION);
+ if (rc != PJ_SUCCESS)
+ return rc;
+
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_uint32_t) pj_getpid(void)
+{
+ return 1;
+}
+
+PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name,
+ pj_thread_desc desc,
+ pj_thread_t **ptr_thread)
+{
+ char stack_ptr;
+ pj_thread_t *thread = (pj_thread_t *)desc;
+ pj_str_t thread_name = pj_str((char*)cstr_thread_name);
+
+ /* Size sanity check. */
+ if (sizeof(pj_thread_desc) < sizeof(pj_thread_t)) {
+ pj_assert(!"Not enough pj_thread_desc size!");
+ return PJ_EBUG;
+ }
+
+ /* If a thread descriptor has been registered before, just return it. */
+ if (pj_thread_local_get (thread_tls_id) != 0) {
+ *ptr_thread = (pj_thread_t*)pj_thread_local_get (thread_tls_id);
+ return PJ_SUCCESS;
+ }
+
+ /* Initialize and set the thread entry. */
+ pj_memset(desc, 0, sizeof(struct pj_thread_t));
+
+ if(cstr_thread_name && pj_strlen(&thread_name) < sizeof(thread->obj_name)-1)
+ pj_sprintf(thread->obj_name, cstr_thread_name, thread->thread);
+ else
+ pj_sprintf(thread->obj_name, "thr%p", (void*)thread->thread);
+
+ /* Initialize. */
+ thread_initialize(thread);
+
+ /* Eat semaphore. */
+ down(&thread->startstop_sem);
+
+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
+ thread->stk_start = &stack_ptr;
+ thread->stk_size = 0xFFFFFFFFUL;
+ thread->stk_max_usage = 0;
+#else
+ stack_ptr = '\0';
+#endif
+
+ *ptr_thread = thread;
+ return PJ_SUCCESS;
+}
+
+
+pj_status_t pj_thread_init(void)
+{
+ pj_status_t rc;
+ pj_thread_t *dummy;
+
+ rc = pj_thread_local_alloc(&thread_tls_id);
+ if (rc != PJ_SUCCESS)
+ return rc;
+
+ return pj_thread_register("pjlib-main", (long*)&main_thread, &dummy);
+}
+
+PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool, const char *thread_name,
+ pj_thread_proc *proc, void *arg,
+ pj_size_t stack_size, unsigned flags,
+ pj_thread_t **ptr_thread)
+{
+ pj_thread_t *thread;
+
+ TRACE_((THIS_FILE, "pj_thread_create()"));
+
+ PJ_ASSERT_RETURN(pool && proc && ptr_thread, PJ_EINVAL);
+
+ thread = pj_pool_zalloc(pool, sizeof(pj_thread_t));
+ if (!thread)
+ return PJ_ENOMEM;
+
+ PJ_UNUSED_ARG(stack_size);
+
+ /* Thread name. */
+ if (!thread_name)
+ thread_name = "thr%p";
+
+ if (strchr(thread_name, '%')) {
+ pj_snprintf(thread->obj_name, PJ_MAX_OBJ_NAME, thread_name, thread);
+ } else {
+ strncpy(thread->obj_name, thread_name, PJ_MAX_OBJ_NAME);
+ thread->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
+ }
+
+ /* Init thread's semaphore. */
+ TRACE_((THIS_FILE, "...init semaphores..."));
+ init_MUTEX_LOCKED(&thread->startstop_sem);
+ init_MUTEX_LOCKED(&thread->suspend_sem);
+
+ thread->flags = flags;
+
+ if ((flags & PJ_THREAD_SUSPENDED) == 0) {
+ up(&thread->suspend_sem);
+ }
+
+ /* Store the functions and argument. */
+ thread->func = proc;
+ thread->arg = arg;
+
+ /* Save return value. */
+ *ptr_thread = thread;
+
+ /* Create the new thread by running a task through keventd. */
+
+#if 0
+ /* Initialize the task queue struct. */
+ thread->tq.sync = 0;
+ INIT_LIST_HEAD(&thread->tq.list);
+ thread->tq.routine = kthread_launcher;
+ thread->tq.data = thread;
+
+ /* and schedule it for execution. */
+ schedule_task(&thread->tq);
+#endif
+ kthread_launcher(thread);
+
+ /* Wait until thread has reached the setup_thread routine. */
+ TRACE_((THIS_FILE, "...wait for the new thread..."));
+ down(&thread->startstop_sem);
+
+ TRACE_((THIS_FILE, "...main thread resumed..."));
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *thread)
+{
+ return thread->obj_name;
+}
+
+PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *thread)
+{
+ up(&thread->suspend_sem);
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_thread_t*) pj_thread_this(void)
+{
+ return (pj_thread_t*)pj_thread_local_get(thread_tls_id);
+}
+
+PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p)
+{
+ TRACE_((THIS_FILE, "pj_thread_join()"));
+ down(&p->startstop_sem);
+ TRACE_((THIS_FILE, " joined!"));
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *thread)
+{
+ PJ_ASSERT_RETURN(thread != NULL, PJ_EINVALIDOP);
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec)
+{
+ pj_highprec_t ticks;
+ pj_thread_t *thread = pj_thread_this();
+
+ PJ_ASSERT_RETURN(thread != NULL, PJ_EBUG);
+
+ /* Use high precision calculation to make sure we don't
+ * crop values:
+ *
+ * ticks = HZ * msec / 1000
+ */
+ ticks = HZ;
+ pj_highprec_mul(ticks, msec);
+ pj_highprec_div(ticks, 1000);
+
+ TRACE_((THIS_FILE, "this thread will sleep for %u ticks", ticks));
+ interruptible_sleep_on_timeout( &thread->queue, ticks);
+ return PJ_SUCCESS;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool,
+ pj_atomic_value_t value,
+ pj_atomic_t **ptr_var)
+{
+ pj_atomic_t *t = pj_pool_calloc(pool, 1, sizeof(pj_atomic_t));
+ if (!t) return PJ_ENOMEM;
+
+ atomic_set(&t->atom, value);
+ *ptr_var = t;
+
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *var )
+{
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(void) pj_atomic_set(pj_atomic_t *var, pj_atomic_value_t value)
+{
+ atomic_set(&var->atom, value);
+}
+
+PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *var)
+{
+ return atomic_read(&var->atom);
+}
+
+PJ_DEF(void) pj_atomic_inc(pj_atomic_t *var)
+{
+ atomic_inc(&var->atom);
+}
+
+PJ_DEF(void) pj_atomic_dec(pj_atomic_t *var)
+{
+ atomic_dec(&var->atom);
+}
+
+PJ_DEF(void) pj_atomic_add( pj_atomic_t *var, pj_atomic_value_t value )
+{
+ atomic_add(value, &var->atom);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+PJ_DEF(pj_status_t) pj_thread_local_alloc(long *index)
+{
+ if (tls_id >= MAX_TLS_ID)
+ return PJ_ETOOMANY;
+
+ *index = tls_id++;
+
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(void) pj_thread_local_free(long index)
+{
+ pj_assert(index >= 0 && index < MAX_TLS_ID);
+}
+
+PJ_DEF(pj_status_t) pj_thread_local_set(long index, void *value)
+{
+ pj_assert(index >= 0 && index < MAX_TLS_ID);
+ tls_values[index] = value;
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(void*) pj_thread_local_get(long index)
+{
+ pj_assert(index >= 0 && index < MAX_TLS_ID);
+ return tls_values[index];
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+PJ_DEF(void) pj_enter_critical_section(void)
+{
+ spin_lock_irqsave(&critical_section, spinlock_flags);
+}
+
+PJ_DEF(void) pj_leave_critical_section(void)
+{
+ spin_unlock_irqrestore(&critical_section, spinlock_flags);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+PJ_DEF(pj_status_t) pj_mutex_create( pj_pool_t *pool,
+ const char *name,
+ int type,
+ pj_mutex_t **ptr_mutex)
+{
+ pj_mutex_t *mutex;
+
+ PJ_UNUSED_ARG(name);
+
+ mutex = pj_pool_alloc(pool, sizeof(pj_mutex_t));
+ if (!mutex)
+ return PJ_ENOMEM;
+
+ init_MUTEX(&mutex->sem);
+
+ mutex->recursive = (type == PJ_MUTEX_RECURSE);
+ mutex->owner = NULL;
+ mutex->own_count = 0;
+
+ /* Done. */
+ *ptr_mutex = mutex;
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool, const char *name,
+ pj_mutex_t **mutex )
+{
+ return pj_mutex_create(pool, name, PJ_MUTEX_SIMPLE, mutex);
+}
+
+PJ_DEF(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool,
+ const char *name,
+ pj_mutex_t **mutex )
+{
+ return pj_mutex_create( pool, name, PJ_MUTEX_RECURSE, mutex);
+}
+
+PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex)
+{
+ PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
+
+ if (mutex->recursive) {
+ pj_thread_t *this_thread = pj_thread_this();
+ if (mutex->owner == this_thread) {
+ ++mutex->own_count;
+ } else {
+ down(&mutex->sem);
+ pj_assert(mutex->own_count == 0);
+ mutex->owner = this_thread;
+ mutex->own_count = 1;
+ }
+ } else {
+ down(&mutex->sem);
+ }
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex)
+{
+ long rc;
+
+ PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
+
+ if (mutex->recursive) {
+ pj_thread_t *this_thread = pj_thread_this();
+ if (mutex->owner == this_thread) {
+ ++mutex->own_count;
+ } else {
+ rc = down_interruptible(&mutex->sem);
+ if (rc != 0)
+ return PJ_RETURN_OS_ERROR(-rc);
+ pj_assert(mutex->own_count == 0);
+ mutex->owner = this_thread;
+ mutex->own_count = 1;
+ }
+ } else {
+ int rc = down_trylock(&mutex->sem);
+ if (rc != 0)
+ return PJ_RETURN_OS_ERROR(-rc);
+ }
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex)
+{
+ PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
+
+ if (mutex->recursive) {
+ pj_thread_t *this_thread = pj_thread_this();
+ if (mutex->owner == this_thread) {
+ pj_assert(mutex->own_count > 0);
+ --mutex->own_count;
+ if (mutex->own_count == 0) {
+ mutex->owner = NULL;
+ up(&mutex->sem);
+ }
+ } else {
+ pj_assert(!"Not owner!");
+ return PJ_EINVALIDOP;
+ }
+ } else {
+ up(&mutex->sem);
+ }
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex)
+{
+ PJ_ASSERT_RETURN(mutex != NULL, PJ_EINVAL);
+
+ return PJ_SUCCESS;
+}
+
+#if defined(PJ_DEBUG) && PJ_DEBUG != 0
+PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex)
+{
+ if (mutex->recursive)
+ return mutex->owner == pj_thread_this();
+ else
+ return 1;
+}
+#endif /* PJ_DEBUG */
+
+
+#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
+
+PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool,
+ const char *name,
+ unsigned initial,
+ unsigned max,
+ pj_sem_t **sem)
+{
+ pj_sem_t *sem;
+
+ PJ_UNUSED_ARG(max);
+
+ PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
+
+ sem = pj_pool_alloc(pool, sizeof(pj_sem_t));
+ sema_init(&sem->sem, initial);
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem)
+{
+ PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
+
+ down(&sem->sem);
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem)
+{
+ int rc;
+
+ PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
+
+ rc = down_trylock(&sem->sem);
+ if (rc != 0) {
+ return PJ_RETURN_OS_ERROR(-rc);
+ } else {
+ return PJ_SUCCESS;
+ }
+}
+
+PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem)
+{
+ PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
+
+ up(&sem->sem);
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem)
+{
+ PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
+
+ return PJ_SUCCESS;
+}
+
+#endif /* PJ_HAS_SEMAPHORE */
+
+
+
+
diff --git a/pjlib/src/pj/os_core_unix.c b/pjlib/src/pj/os_core_unix.c
index cc57aab2..5956adb6 100644
--- a/pjlib/src/pj/os_core_unix.c
+++ b/pjlib/src/pj/os_core_unix.c
@@ -1,563 +1,584 @@
-/* $Id$
- *
- */
-#include <pj/os.h>
-#include <pj/assert.h>
-#include <pj/pool.h>
-#include <pj/log.h>
-#include <pj/rand.h>
-#include <pj/string.h>
-#include <pj/guid.h>
-#include <pj/compat/sprintf.h>
-#include <pj/except.h>
-#include <pj/errno.h>
-
-#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
-# include <semaphore.h>
-#endif
-
-#include <unistd.h> // getpid()
-#include <errno.h> // errno
-
-#define __USE_GNU
-//uncomment this to get pthread_mutexattr_settype declaration.
-//unfortunately this causes syntax error in pthread.h! :(
-//#define __USE_UNIX98
-#include <pthread.h>
-
-#define THIS_FILE "osunix"
-
-struct pj_thread_t
-{
- char obj_name[PJ_MAX_OBJ_NAME];
- pthread_t thread;
- pj_thread_proc *proc;
- void *arg;
-
- pj_mutex_t *suspended_mutex;
-
-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
- pj_uint32_t stk_size;
- pj_uint32_t stk_max_usage;
- char *stk_start;
- const char *caller_file;
- int caller_line;
-#endif
-};
-
-struct pj_atomic_t
-{
- pj_mutex_t *mutex;
- pj_atomic_value_t value;
-};
-
-struct pj_mutex_t
-{
- pthread_mutex_t mutex;
- char obj_name[PJ_MAX_OBJ_NAME];
-#if PJ_DEBUG
- int nesting_level;
- pj_thread_t *owner;
-#endif
-};
-
-#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
-struct pj_sem_t
-{
- sem_t sem;
- char obj_name[PJ_MAX_OBJ_NAME];
-};
-#endif /* PJ_HAS_SEMAPHORE */
-
-#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0
-struct pj_event_t
-{
- char obj_name[PJ_MAX_OBJ_NAME];
-};
-#endif /* PJ_HAS_EVENT_OBJ */
-
-
-#if PJ_HAS_THREADS
- static pj_thread_t main_thread;
- static long thread_tls_id;
- static pj_mutex_t critical_section;
-#else
-# define MAX_THREADS 32
- static int tls_flag[MAX_THREADS];
- static void *tls[MAX_THREADS];
-#endif
-
-static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name, int type);
-
-/*
- * pj_init(void).
- * Init PJLIB!
- */
-PJ_DEF(pj_status_t) pj_init(void)
-{
- char dummy_guid[PJ_GUID_MAX_LENGTH];
- pj_str_t guid;
- pj_status_t rc;
-
- PJ_LOG(5, ("pj_init", "Initializing PJ Library.."));
-
-#if PJ_HAS_THREADS
- /* Init this thread's TLS. */
- if ((rc=pj_thread_init()) != 0) {
- return rc;
- }
-
- /* Critical section. */
- if ((rc=init_mutex(&critical_section, "critsec", PJ_MUTEX_SIMPLE)) != 0)
- return rc;
-
-#endif
-
- /* Initialize exception ID for the pool.
- * Must do so after critical section is configured.
- */
- rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION);
- if (rc != PJ_SUCCESS)
- return rc;
-
- /* Init random seed. */
- pj_srand( clock() );
-
- /* Startup GUID. */
- guid.ptr = dummy_guid;
- pj_generate_unique_string( &guid );
-
- /* Initialize exception ID for the pool.
- * Must do so after critical section is configured.
- */
- rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION);
- if (rc != PJ_SUCCESS)
- return rc;
-
- /* Startup timestamp */
-#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0
- {
- pj_timestamp dummy_ts;
- if ((rc=pj_get_timestamp(&dummy_ts)) != 0) {
- return rc;
- }
- }
-#endif
-
- return PJ_SUCCESS;
-}
-
-/*
- * pj_getpid(void)
- */
-PJ_DEF(pj_uint32_t) pj_getpid(void)
-{
- PJ_CHECK_STACK();
- return getpid();
-}
-
-/*
- * pj_thread_register(..)
- */
-PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name,
- pj_thread_desc desc,
- pj_thread_t **ptr_thread)
-{
-#if PJ_HAS_THREADS
- char stack_ptr;
- pj_status_t rc;
- pj_thread_t *thread = (pj_thread_t *)desc;
- pj_str_t thread_name = pj_str((char*)cstr_thread_name);
-
- /* Size sanity check. */
- if (sizeof(pj_thread_desc) < sizeof(pj_thread_t)) {
- pj_assert(!"Not enough pj_thread_desc size!");
- return PJ_EBUG;
- }
-
- /* If a thread descriptor has been registered before, just return it. */
- if (pj_thread_local_get (thread_tls_id) != 0) {
- *ptr_thread = (pj_thread_t*)pj_thread_local_get (thread_tls_id);
- return PJ_SUCCESS;
- }
-
- /* Initialize and set the thread entry. */
- pj_memset(desc, 0, sizeof(struct pj_thread_t));
- thread->thread = pthread_self();
-
- if(cstr_thread_name && pj_strlen(&thread_name) < sizeof(thread->obj_name)-1)
- pj_sprintf(thread->obj_name, cstr_thread_name, thread->thread);
- else
- pj_sprintf(thread->obj_name, "thr%p", (void*)thread->thread);
-
- rc = pj_thread_local_set(thread_tls_id, thread);
- if (rc != PJ_SUCCESS)
- return rc;
-
-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
- thread->stk_start = &stack_ptr;
- thread->stk_size = 0xFFFFFFFFUL;
- thread->stk_max_usage = 0;
-#else
- stack_ptr = '\0';
-#endif
-
- *ptr_thread = thread;
- return PJ_SUCCESS;
-#else
- pj_thread_t *thread = (pj_thread_t*)desc;
- *ptr_thread = thread;
- return PJ_SUCCESS;
-#endif
-}
-
-/*
- * pj_thread_init(void)
- */
-pj_status_t pj_thread_init(void)
-{
-#if PJ_HAS_THREADS
- pj_status_t rc;
- pj_thread_t *dummy;
-
- rc = pj_thread_local_alloc(&thread_tls_id );
- if (rc != PJ_SUCCESS) {
- return rc;
- }
- return pj_thread_register("thr%p", (long*)&main_thread, &dummy);
-#else
- PJ_LOG(2,(THIS_FILE, "Thread init error. Threading is not enabled!"));
- return PJ_EINVALIDOP;
-#endif
-}
-
-#if PJ_HAS_THREADS
-/*
- * thread_main()
- *
- * This is the main entry for all threads.
- */
-static void *thread_main(void *param)
-{
- pj_thread_t *rec = param;
- void *result;
- pj_status_t rc;
-
-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
- rec->stk_start = (char*)&rec;
-#endif
-
- /* Set current thread id. */
- rc = pj_thread_local_set(thread_tls_id, rec);
- if (rc != PJ_SUCCESS) {
- pj_assert(!"Thread TLS ID is not set (pj_init() error?)");
- }
-
- /* Check if suspension is required. */
- if (rec->suspended_mutex)
- pj_mutex_lock(rec->suspended_mutex);
-
- PJ_LOG(6,(rec->obj_name, "Thread started"));
-
- /* Call user's entry! */
- result = (void*)(long)(*rec->proc)(rec->arg);
-
- /* Done. */
- PJ_LOG(6,(rec->obj_name, "Thread quitting"));
- return result;
-}
-#endif
-
-/*
- * pj_thread_create(...)
- */
-PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool,
- const char *thread_name,
- pj_thread_proc *proc,
- void *arg,
- pj_size_t stack_size,
- unsigned flags,
- pj_thread_t **ptr_thread)
-{
-#if PJ_HAS_THREADS
- pj_thread_t *rec;
- int rc;
-
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(pool && proc && ptr_thread, PJ_EINVAL);
-
- /* Create thread record and assign name for the thread */
- rec = (struct pj_thread_t*) pj_pool_zalloc(pool, sizeof(pj_thread_t));
- if (!rec)
- return PJ_ENOMEM;
-
- /* Set name. */
- if (!thread_name)
- thread_name = "thr%p";
-
- if (strchr(thread_name, '%')) {
- pj_snprintf(rec->obj_name, PJ_MAX_OBJ_NAME, thread_name, rec);
- } else {
- strncpy(rec->obj_name, thread_name, PJ_MAX_OBJ_NAME);
- rec->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
- }
-
-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
- rec->stk_size = stack_size ? stack_size : 0xFFFFFFFFUL;
- rec->stk_max_usage = 0;
-#endif
-
- /* Emulate suspended thread with mutex. */
- if (flags & PJ_THREAD_SUSPENDED) {
- rc = pj_mutex_create_simple(pool, NULL, &rec->suspended_mutex);
- if (rc != PJ_SUCCESS)
- return rc;
-
- pj_mutex_lock(rec->suspended_mutex);
- } else {
- pj_assert(rec->suspended_mutex == NULL);
- }
-
- PJ_LOG(6, (rec->obj_name, "Thread created"));
-
- /* Create the thread. */
- rec->proc = proc;
- rec->arg = arg;
- rc = pthread_create( &rec->thread, NULL, thread_main, rec);
- if (rc != 0)
- return PJ_RETURN_OS_ERROR(rc);
-
- *ptr_thread = rec;
- return PJ_SUCCESS;
-#else
- pj_assert(!"Threading is disabled!");
- return PJ_EINVALIDOP;
-#endif
-}
-
-/*
- * pj_thread-get_name()
- */
-PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *p)
-{
-#if PJ_HAS_THREADS
- pj_thread_t *rec = (pj_thread_t*)p;
-
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(p, "");
-
- return rec->obj_name;
-#else
- return "";
-#endif
-}
-
-/*
- * pj_thread_resume()
- */
-PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *p)
-{
- pj_status_t rc;
-
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(p, PJ_EINVAL);
-
- rc = pj_mutex_unlock(p->suspended_mutex);
-
- return rc;
-}
-
-/*
- * pj_thread_this()
- */
-PJ_DEF(pj_thread_t*) pj_thread_this(void)
-{
-#if PJ_HAS_THREADS
- pj_thread_t *rec = pj_thread_local_get(thread_tls_id);
- pj_assert(rec != NULL);
-
- /*
- * MUST NOT check stack because this function is called
- * by PJ_CHECK_STACK() itself!!!
- *
- */
-
- return rec;
-#else
- pj_assert(!"Threading is not enabled!");
- return NULL;
-#endif
-}
-
-/*
- * pj_thread_join()
- */
-PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p)
-{
-#if PJ_HAS_THREADS
- pj_thread_t *rec = (pj_thread_t *)p;
- void *ret;
- int result;
-
- PJ_CHECK_STACK();
-
- PJ_LOG(6, (pj_thread_this()->obj_name, "Joining thread %s", p->obj_name));
- result = pthread_join( rec->thread, &ret);
-
- if (result == 0)
- return PJ_SUCCESS;
- else
- return PJ_RETURN_OS_ERROR(result);
-#else
- PJ_CHECK_STACK();
- pj_assert(!"No multithreading support!");
- return PJ_EINVALIDOP;
-#endif
-}
-
-/*
- * pj_thread_destroy()
- */
-PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *p)
-{
- /* This function is used to destroy thread handle in other platforms.
- * I suppose there's nothing to do here..
- */
- PJ_CHECK_STACK();
- return PJ_SUCCESS;
-}
-
-/*
- * pj_thread_sleep()
- */
-PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec)
-{
- PJ_CHECK_STACK();
- return usleep(msec * 1000);
-}
-
-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
-/*
- * pj_thread_check_stack()
- * Implementation for PJ_CHECK_STACK()
- */
-PJ_DEF(void) pj_thread_check_stack(const char *file, int line)
-{
- char stk_ptr;
- pj_uint32_t usage;
- pj_thread_t *thread = pj_thread_this();
-
- /* Calculate current usage. */
- usage = (&stk_ptr > thread->stk_start) ? &stk_ptr - thread->stk_start :
- thread->stk_start - &stk_ptr;
-
- /* Assert if stack usage is dangerously high. */
- pj_assert("STACK OVERFLOW!! " && (usage <= thread->stk_size - 128));
-
- /* Keep statistic. */
- if (usage > thread->stk_max_usage) {
- thread->stk_max_usage = usage;
- thread->caller_file = file;
- thread->caller_line = line;
- }
-}
-
-/*
- * pj_thread_get_stack_max_usage()
- */
-PJ_DEF(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread)
-{
- return thread->stk_max_usage;
-}
-
-/*
- * pj_thread_get_stack_info()
- */
-PJ_DEF(pj_status_t) pj_thread_get_stack_info( pj_thread_t *thread,
- const char **file,
- int *line )
-{
- pj_assert(thread);
-
- *file = thread->caller_file;
- *line = thread->caller_line;
- return 0;
-}
-
-#endif /* PJ_OS_HAS_CHECK_STACK */
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * pj_atomic_create()
- */
-PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool,
- pj_atomic_value_t initial,
- pj_atomic_t **ptr_atomic)
-{
- pj_status_t rc;
- pj_atomic_t *atomic_var = pj_pool_calloc(pool, 1, sizeof(pj_atomic_t));
- if (!atomic_var)
- return PJ_ENOMEM;
-
-#if PJ_HAS_THREADS
- rc = pj_mutex_create(pool, "atm%p", PJ_MUTEX_SIMPLE, &atomic_var->mutex);
- if (rc != PJ_SUCCESS)
- return rc;
-#endif
- atomic_var->value = initial;
-
- *ptr_atomic = atomic_var;
- return PJ_SUCCESS;
-}
-
-/*
- * pj_atomic_destroy()
- */
-PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *atomic_var )
-{
- PJ_ASSERT_RETURN(atomic_var, PJ_EINVAL);
-#if PJ_HAS_THREADS
- return pj_mutex_destroy( atomic_var->mutex );
-#else
- return 0;
-#endif
-}
-
-/*
- * pj_atomic_set()
- */
-PJ_DEF(void) pj_atomic_set(pj_atomic_t *atomic_var, pj_atomic_value_t value)
-{
- PJ_CHECK_STACK();
-
-#if PJ_HAS_THREADS
- pj_mutex_lock( atomic_var->mutex );
-#endif
- atomic_var->value = value;
-#if PJ_HAS_THREADS
- pj_mutex_unlock( atomic_var->mutex);
-#endif
-}
-
-/*
- * pj_atomic_get()
- */
-PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var)
-{
- pj_atomic_value_t oldval;
-
- PJ_CHECK_STACK();
-
-#if PJ_HAS_THREADS
- pj_mutex_lock( atomic_var->mutex );
-#endif
- oldval = atomic_var->value;
-#if PJ_HAS_THREADS
- pj_mutex_unlock( atomic_var->mutex);
-#endif
- return oldval;
-}
-
+/* $Id$
+ *
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/os.h>
+#include <pj/assert.h>
+#include <pj/pool.h>
+#include <pj/log.h>
+#include <pj/rand.h>
+#include <pj/string.h>
+#include <pj/guid.h>
+#include <pj/compat/sprintf.h>
+#include <pj/except.h>
+#include <pj/errno.h>
+
+#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
+# include <semaphore.h>
+#endif
+
+#include <unistd.h> // getpid()
+#include <errno.h> // errno
+
+#define __USE_GNU
+//uncomment this to get pthread_mutexattr_settype declaration.
+//unfortunately this causes syntax error in pthread.h! :(
+//#define __USE_UNIX98
+#include <pthread.h>
+
+#define THIS_FILE "osunix"
+
+struct pj_thread_t
+{
+ char obj_name[PJ_MAX_OBJ_NAME];
+ pthread_t thread;
+ pj_thread_proc *proc;
+ void *arg;
+
+ pj_mutex_t *suspended_mutex;
+
+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
+ pj_uint32_t stk_size;
+ pj_uint32_t stk_max_usage;
+ char *stk_start;
+ const char *caller_file;
+ int caller_line;
+#endif
+};
+
+struct pj_atomic_t
+{
+ pj_mutex_t *mutex;
+ pj_atomic_value_t value;
+};
+
+struct pj_mutex_t
+{
+ pthread_mutex_t mutex;
+ char obj_name[PJ_MAX_OBJ_NAME];
+#if PJ_DEBUG
+ int nesting_level;
+ pj_thread_t *owner;
+#endif
+};
+
+#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
+struct pj_sem_t
+{
+ sem_t sem;
+ char obj_name[PJ_MAX_OBJ_NAME];
+};
+#endif /* PJ_HAS_SEMAPHORE */
+
+#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0
+struct pj_event_t
+{
+ char obj_name[PJ_MAX_OBJ_NAME];
+};
+#endif /* PJ_HAS_EVENT_OBJ */
+
+
+#if PJ_HAS_THREADS
+ static pj_thread_t main_thread;
+ static long thread_tls_id;
+ static pj_mutex_t critical_section;
+#else
+# define MAX_THREADS 32
+ static int tls_flag[MAX_THREADS];
+ static void *tls[MAX_THREADS];
+#endif
+
+static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name, int type);
+
+/*
+ * pj_init(void).
+ * Init PJLIB!
+ */
+PJ_DEF(pj_status_t) pj_init(void)
+{
+ char dummy_guid[PJ_GUID_MAX_LENGTH];
+ pj_str_t guid;
+ pj_status_t rc;
+
+ PJ_LOG(5, ("pj_init", "Initializing PJ Library.."));
+
+#if PJ_HAS_THREADS
+ /* Init this thread's TLS. */
+ if ((rc=pj_thread_init()) != 0) {
+ return rc;
+ }
+
+ /* Critical section. */
+ if ((rc=init_mutex(&critical_section, "critsec", PJ_MUTEX_SIMPLE)) != 0)
+ return rc;
+
+#endif
+
+ /* Initialize exception ID for the pool.
+ * Must do so after critical section is configured.
+ */
+ rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION);
+ if (rc != PJ_SUCCESS)
+ return rc;
+
+ /* Init random seed. */
+ pj_srand( clock() );
+
+ /* Startup GUID. */
+ guid.ptr = dummy_guid;
+ pj_generate_unique_string( &guid );
+
+ /* Initialize exception ID for the pool.
+ * Must do so after critical section is configured.
+ */
+ rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION);
+ if (rc != PJ_SUCCESS)
+ return rc;
+
+ /* Startup timestamp */
+#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0
+ {
+ pj_timestamp dummy_ts;
+ if ((rc=pj_get_timestamp(&dummy_ts)) != 0) {
+ return rc;
+ }
+ }
+#endif
+
+ return PJ_SUCCESS;
+}
+
+/*
+ * pj_getpid(void)
+ */
+PJ_DEF(pj_uint32_t) pj_getpid(void)
+{
+ PJ_CHECK_STACK();
+ return getpid();
+}
+
+/*
+ * pj_thread_register(..)
+ */
+PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name,
+ pj_thread_desc desc,
+ pj_thread_t **ptr_thread)
+{
+#if PJ_HAS_THREADS
+ char stack_ptr;
+ pj_status_t rc;
+ pj_thread_t *thread = (pj_thread_t *)desc;
+ pj_str_t thread_name = pj_str((char*)cstr_thread_name);
+
+ /* Size sanity check. */
+ if (sizeof(pj_thread_desc) < sizeof(pj_thread_t)) {
+ pj_assert(!"Not enough pj_thread_desc size!");
+ return PJ_EBUG;
+ }
+
+ /* If a thread descriptor has been registered before, just return it. */
+ if (pj_thread_local_get (thread_tls_id) != 0) {
+ *ptr_thread = (pj_thread_t*)pj_thread_local_get (thread_tls_id);
+ return PJ_SUCCESS;
+ }
+
+ /* Initialize and set the thread entry. */
+ pj_memset(desc, 0, sizeof(struct pj_thread_t));
+ thread->thread = pthread_self();
+
+ if(cstr_thread_name && pj_strlen(&thread_name) < sizeof(thread->obj_name)-1)
+ pj_sprintf(thread->obj_name, cstr_thread_name, thread->thread);
+ else
+ pj_sprintf(thread->obj_name, "thr%p", (void*)thread->thread);
+
+ rc = pj_thread_local_set(thread_tls_id, thread);
+ if (rc != PJ_SUCCESS)
+ return rc;
+
+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
+ thread->stk_start = &stack_ptr;
+ thread->stk_size = 0xFFFFFFFFUL;
+ thread->stk_max_usage = 0;
+#else
+ stack_ptr = '\0';
+#endif
+
+ *ptr_thread = thread;
+ return PJ_SUCCESS;
+#else
+ pj_thread_t *thread = (pj_thread_t*)desc;
+ *ptr_thread = thread;
+ return PJ_SUCCESS;
+#endif
+}
+
+/*
+ * pj_thread_init(void)
+ */
+pj_status_t pj_thread_init(void)
+{
+#if PJ_HAS_THREADS
+ pj_status_t rc;
+ pj_thread_t *dummy;
+
+ rc = pj_thread_local_alloc(&thread_tls_id );
+ if (rc != PJ_SUCCESS) {
+ return rc;
+ }
+ return pj_thread_register("thr%p", (long*)&main_thread, &dummy);
+#else
+ PJ_LOG(2,(THIS_FILE, "Thread init error. Threading is not enabled!"));
+ return PJ_EINVALIDOP;
+#endif
+}
+
+#if PJ_HAS_THREADS
+/*
+ * thread_main()
+ *
+ * This is the main entry for all threads.
+ */
+static void *thread_main(void *param)
+{
+ pj_thread_t *rec = param;
+ void *result;
+ pj_status_t rc;
+
+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
+ rec->stk_start = (char*)&rec;
+#endif
+
+ /* Set current thread id. */
+ rc = pj_thread_local_set(thread_tls_id, rec);
+ if (rc != PJ_SUCCESS) {
+ pj_assert(!"Thread TLS ID is not set (pj_init() error?)");
+ }
+
+ /* Check if suspension is required. */
+ if (rec->suspended_mutex)
+ pj_mutex_lock(rec->suspended_mutex);
+
+ PJ_LOG(6,(rec->obj_name, "Thread started"));
+
+ /* Call user's entry! */
+ result = (void*)(long)(*rec->proc)(rec->arg);
+
+ /* Done. */
+ PJ_LOG(6,(rec->obj_name, "Thread quitting"));
+ return result;
+}
+#endif
+
+/*
+ * pj_thread_create(...)
+ */
+PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool,
+ const char *thread_name,
+ pj_thread_proc *proc,
+ void *arg,
+ pj_size_t stack_size,
+ unsigned flags,
+ pj_thread_t **ptr_thread)
+{
+#if PJ_HAS_THREADS
+ pj_thread_t *rec;
+ int rc;
+
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(pool && proc && ptr_thread, PJ_EINVAL);
+
+ /* Create thread record and assign name for the thread */
+ rec = (struct pj_thread_t*) pj_pool_zalloc(pool, sizeof(pj_thread_t));
+ if (!rec)
+ return PJ_ENOMEM;
+
+ /* Set name. */
+ if (!thread_name)
+ thread_name = "thr%p";
+
+ if (strchr(thread_name, '%')) {
+ pj_snprintf(rec->obj_name, PJ_MAX_OBJ_NAME, thread_name, rec);
+ } else {
+ strncpy(rec->obj_name, thread_name, PJ_MAX_OBJ_NAME);
+ rec->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
+ }
+
+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
+ rec->stk_size = stack_size ? stack_size : 0xFFFFFFFFUL;
+ rec->stk_max_usage = 0;
+#endif
+
+ /* Emulate suspended thread with mutex. */
+ if (flags & PJ_THREAD_SUSPENDED) {
+ rc = pj_mutex_create_simple(pool, NULL, &rec->suspended_mutex);
+ if (rc != PJ_SUCCESS)
+ return rc;
+
+ pj_mutex_lock(rec->suspended_mutex);
+ } else {
+ pj_assert(rec->suspended_mutex == NULL);
+ }
+
+ PJ_LOG(6, (rec->obj_name, "Thread created"));
+
+ /* Create the thread. */
+ rec->proc = proc;
+ rec->arg = arg;
+ rc = pthread_create( &rec->thread, NULL, thread_main, rec);
+ if (rc != 0)
+ return PJ_RETURN_OS_ERROR(rc);
+
+ *ptr_thread = rec;
+ return PJ_SUCCESS;
+#else
+ pj_assert(!"Threading is disabled!");
+ return PJ_EINVALIDOP;
+#endif
+}
+
+/*
+ * pj_thread-get_name()
+ */
+PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *p)
+{
+#if PJ_HAS_THREADS
+ pj_thread_t *rec = (pj_thread_t*)p;
+
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(p, "");
+
+ return rec->obj_name;
+#else
+ return "";
+#endif
+}
+
+/*
+ * pj_thread_resume()
+ */
+PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *p)
+{
+ pj_status_t rc;
+
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(p, PJ_EINVAL);
+
+ rc = pj_mutex_unlock(p->suspended_mutex);
+
+ return rc;
+}
+
+/*
+ * pj_thread_this()
+ */
+PJ_DEF(pj_thread_t*) pj_thread_this(void)
+{
+#if PJ_HAS_THREADS
+ pj_thread_t *rec = pj_thread_local_get(thread_tls_id);
+ pj_assert(rec != NULL);
+
+ /*
+ * MUST NOT check stack because this function is called
+ * by PJ_CHECK_STACK() itself!!!
+ *
+ */
+
+ return rec;
+#else
+ pj_assert(!"Threading is not enabled!");
+ return NULL;
+#endif
+}
+
+/*
+ * pj_thread_join()
+ */
+PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p)
+{
+#if PJ_HAS_THREADS
+ pj_thread_t *rec = (pj_thread_t *)p;
+ void *ret;
+ int result;
+
+ PJ_CHECK_STACK();
+
+ PJ_LOG(6, (pj_thread_this()->obj_name, "Joining thread %s", p->obj_name));
+ result = pthread_join( rec->thread, &ret);
+
+ if (result == 0)
+ return PJ_SUCCESS;
+ else
+ return PJ_RETURN_OS_ERROR(result);
+#else
+ PJ_CHECK_STACK();
+ pj_assert(!"No multithreading support!");
+ return PJ_EINVALIDOP;
+#endif
+}
+
+/*
+ * pj_thread_destroy()
+ */
+PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *p)
+{
+ /* This function is used to destroy thread handle in other platforms.
+ * I suppose there's nothing to do here..
+ */
+ PJ_CHECK_STACK();
+ return PJ_SUCCESS;
+}
+
+/*
+ * pj_thread_sleep()
+ */
+PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec)
+{
+ PJ_CHECK_STACK();
+ return usleep(msec * 1000);
+}
+
+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
+/*
+ * pj_thread_check_stack()
+ * Implementation for PJ_CHECK_STACK()
+ */
+PJ_DEF(void) pj_thread_check_stack(const char *file, int line)
+{
+ char stk_ptr;
+ pj_uint32_t usage;
+ pj_thread_t *thread = pj_thread_this();
+
+ /* Calculate current usage. */
+ usage = (&stk_ptr > thread->stk_start) ? &stk_ptr - thread->stk_start :
+ thread->stk_start - &stk_ptr;
+
+ /* Assert if stack usage is dangerously high. */
+ pj_assert("STACK OVERFLOW!! " && (usage <= thread->stk_size - 128));
+
+ /* Keep statistic. */
+ if (usage > thread->stk_max_usage) {
+ thread->stk_max_usage = usage;
+ thread->caller_file = file;
+ thread->caller_line = line;
+ }
+}
+
+/*
+ * pj_thread_get_stack_max_usage()
+ */
+PJ_DEF(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread)
+{
+ return thread->stk_max_usage;
+}
+
+/*
+ * pj_thread_get_stack_info()
+ */
+PJ_DEF(pj_status_t) pj_thread_get_stack_info( pj_thread_t *thread,
+ const char **file,
+ int *line )
+{
+ pj_assert(thread);
+
+ *file = thread->caller_file;
+ *line = thread->caller_line;
+ return 0;
+}
+
+#endif /* PJ_OS_HAS_CHECK_STACK */
+
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * pj_atomic_create()
+ */
+PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool,
+ pj_atomic_value_t initial,
+ pj_atomic_t **ptr_atomic)
+{
+ pj_status_t rc;
+ pj_atomic_t *atomic_var = pj_pool_calloc(pool, 1, sizeof(pj_atomic_t));
+ if (!atomic_var)
+ return PJ_ENOMEM;
+
+#if PJ_HAS_THREADS
+ rc = pj_mutex_create(pool, "atm%p", PJ_MUTEX_SIMPLE, &atomic_var->mutex);
+ if (rc != PJ_SUCCESS)
+ return rc;
+#endif
+ atomic_var->value = initial;
+
+ *ptr_atomic = atomic_var;
+ return PJ_SUCCESS;
+}
+
+/*
+ * pj_atomic_destroy()
+ */
+PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *atomic_var )
+{
+ PJ_ASSERT_RETURN(atomic_var, PJ_EINVAL);
+#if PJ_HAS_THREADS
+ return pj_mutex_destroy( atomic_var->mutex );
+#else
+ return 0;
+#endif
+}
+
+/*
+ * pj_atomic_set()
+ */
+PJ_DEF(void) pj_atomic_set(pj_atomic_t *atomic_var, pj_atomic_value_t value)
+{
+ PJ_CHECK_STACK();
+
+#if PJ_HAS_THREADS
+ pj_mutex_lock( atomic_var->mutex );
+#endif
+ atomic_var->value = value;
+#if PJ_HAS_THREADS
+ pj_mutex_unlock( atomic_var->mutex);
+#endif
+}
+
+/*
+ * pj_atomic_get()
+ */
+PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var)
+{
+ pj_atomic_value_t oldval;
+
+ PJ_CHECK_STACK();
+
+#if PJ_HAS_THREADS
+ pj_mutex_lock( atomic_var->mutex );
+#endif
+ oldval = atomic_var->value;
+#if PJ_HAS_THREADS
+ pj_mutex_unlock( atomic_var->mutex);
+#endif
+ return oldval;
+}
+
/*
* pj_atomic_inc_and_get()
*/
@@ -577,33 +598,33 @@ PJ_DEF(pj_atomic_value_t) pj_atomic_inc_and_get(pj_atomic_t *atomic_var)
return new_value;
}
-/*
- * pj_atomic_inc()
- */
-PJ_DEF(void) pj_atomic_inc(pj_atomic_t *atomic_var)
-{
- pj_atomic_inc_and_get(atomic_var);
-}
-
-/*
- * pj_atomic_dec_and_get()
- */
-PJ_DEF(pj_atomic_value_t) pj_atomic_dec_and_get(pj_atomic_t *atomic_var)
+/*
+ * pj_atomic_inc()
+ */
+PJ_DEF(void) pj_atomic_inc(pj_atomic_t *atomic_var)
+{
+ pj_atomic_inc_and_get(atomic_var);
+}
+
+/*
+ * pj_atomic_dec_and_get()
+ */
+PJ_DEF(pj_atomic_value_t) pj_atomic_dec_and_get(pj_atomic_t *atomic_var)
{
pj_atomic_value_t new_value;
-
- PJ_CHECK_STACK();
-
-#if PJ_HAS_THREADS
- pj_mutex_lock( atomic_var->mutex );
-#endif
- new_value = --atomic_var->value;
-#if PJ_HAS_THREADS
- pj_mutex_unlock( atomic_var->mutex);
+
+ PJ_CHECK_STACK();
+
+#if PJ_HAS_THREADS
+ pj_mutex_lock( atomic_var->mutex );
+#endif
+ new_value = --atomic_var->value;
+#if PJ_HAS_THREADS
+ pj_mutex_unlock( atomic_var->mutex);
#endif
- return new_value;
-}
+ return new_value;
+}
/*
* pj_atomic_dec()
@@ -612,29 +633,29 @@ PJ_DEF(void) pj_atomic_dec(pj_atomic_t *atomic_var)
{
pj_atomic_dec_and_get(atomic_var);
}
-
-/*
- * pj_atomic_add_and_get()
- */
+
+/*
+ * pj_atomic_add_and_get()
+ */
PJ_DEF(pj_atomic_value_t) pj_atomic_add_and_get( pj_atomic_t *atomic_var,
- pj_atomic_value_t value )
+ pj_atomic_value_t value )
{
pj_atomic_value_t new_value;
-
-#if PJ_HAS_THREADS
- pj_mutex_lock(atomic_var->mutex);
-#endif
-
+
+#if PJ_HAS_THREADS
+ pj_mutex_lock(atomic_var->mutex);
+#endif
+
atomic_var->value += value;
- new_value = atomic_var->value;
-
-#if PJ_HAS_THREADS
- pj_mutex_unlock(atomic_var->mutex);
+ new_value = atomic_var->value;
+
+#if PJ_HAS_THREADS
+ pj_mutex_unlock(atomic_var->mutex);
#endif
- return new_value;
-}
-
+ return new_value;
+}
+
/*
* pj_atomic_add()
*/
@@ -643,598 +664,598 @@ PJ_DEF(void) pj_atomic_add( pj_atomic_t *atomic_var,
{
pj_atomic_add_and_get(atomic_var, value);
}
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * pj_thread_local_alloc()
- */
-PJ_DEF(pj_status_t) pj_thread_local_alloc(long *p_index)
-{
-#if PJ_HAS_THREADS
- pthread_key_t key;
- int rc;
-
- PJ_ASSERT_RETURN(p_index != NULL, PJ_EINVAL);
-
- pj_assert( sizeof(pthread_key_t) <= sizeof(long));
- if ((rc=pthread_key_create(&key, NULL)) != 0)
- return PJ_RETURN_OS_ERROR(rc);
-
- *p_index = key;
- return PJ_SUCCESS;
-#else
- int i;
- for (i=0; i<MAX_THREADS; ++i) {
- if (tls_flag[i] == 0)
- break;
- }
- if (i == MAX_THREADS)
- return PJ_ETOOMANY;
-
- tls_flag[i] = 1;
- tls[i] = NULL;
-
- *p_index = i;
- return PJ_SUCCESS;
-#endif
-}
-
-/*
- * pj_thread_local_free()
- */
-PJ_DEF(void) pj_thread_local_free(long index)
-{
- PJ_CHECK_STACK();
-#if PJ_HAS_THREADS
- pthread_key_delete(index);
-#else
- tls_flag[index] = 0;
-#endif
-}
-
-/*
- * pj_thread_local_set()
- */
-PJ_DEF(pj_status_t) pj_thread_local_set(long index, void *value)
-{
- //Can't check stack because this function is called in the
- //beginning before main thread is initialized.
- //PJ_CHECK_STACK();
-#if PJ_HAS_THREADS
- int rc=pthread_setspecific(index, value);
- return rc==0 ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(rc);
-#else
- pj_assert(index >= 0 && index < MAX_THREADS);
- tls[index] = value;
- return PJ_SUCCESS;
-#endif
-}
-
-PJ_DEF(void*) pj_thread_local_get(long index)
-{
- //Can't check stack because this function is called
- //by PJ_CHECK_STACK() itself!!!
- //PJ_CHECK_STACK();
-#if PJ_HAS_THREADS
- return pthread_getspecific(index);
-#else
- pj_assert(index >= 0 && index < MAX_THREADS);
- return tls[index];
-#endif
-}
-
-///////////////////////////////////////////////////////////////////////////////
-PJ_DEF(void) pj_enter_critical_section(void)
-{
-#if PJ_HAS_THREADS
- pj_mutex_lock(&critical_section);
-#endif
-}
-
-PJ_DEF(void) pj_leave_critical_section(void)
-{
-#if PJ_HAS_THREADS
- pj_mutex_unlock(&critical_section);
-#endif
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name, int type)
-{
-#if PJ_HAS_THREADS
- pthread_mutexattr_t attr;
- int rc;
-
- PJ_CHECK_STACK();
-
- pthread_mutexattr_init(&attr);
-
- if (type == PJ_MUTEX_SIMPLE) {
-#if defined(PJ_LINUX) && PJ_LINUX!=0
- extern int pthread_mutexattr_settype(pthread_mutexattr_t*,int);
- rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_FAST_NP);
-#else
- rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
-#endif
- } else {
-#if defined(PJ_LINUX) && PJ_LINUX!=0
- extern int pthread_mutexattr_settype(pthread_mutexattr_t*,int);
- rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
-#else
- rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
-#endif
- }
-
- if (rc != 0) {
- return PJ_RETURN_OS_ERROR(rc);
- }
-
- rc = pthread_mutex_init(&mutex->mutex, &attr);
- if (rc != 0) {
- return PJ_RETURN_OS_ERROR(rc);
- }
-
-#if PJ_DEBUG
- /* Set owner. */
- mutex->nesting_level = 0;
- mutex->owner = NULL;
-#endif
-
- /* Set name. */
- if (!name) {
- name = "mtx%p";
- }
- if (strchr(name, '%')) {
- pj_snprintf(mutex->obj_name, PJ_MAX_OBJ_NAME, name, mutex);
- } else {
- strncpy(mutex->obj_name, name, PJ_MAX_OBJ_NAME);
- mutex->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
- }
-
- PJ_LOG(6, (mutex->obj_name, "Mutex created"));
- return PJ_SUCCESS;
-#else /* PJ_HAS_THREADS */
- return PJ_SUCCESS;
-#endif
-}
-
-/*
- * pj_mutex_create()
- */
-PJ_DEF(pj_status_t) pj_mutex_create(pj_pool_t *pool,
- const char *name,
- int type,
- pj_mutex_t **ptr_mutex)
-{
-#if PJ_HAS_THREADS
- pj_status_t rc;
- pj_mutex_t *mutex;
-
- PJ_ASSERT_RETURN(pool && ptr_mutex, PJ_EINVAL);
-
- mutex = pj_pool_alloc(pool, sizeof(*mutex));
- if (!mutex) return PJ_ENOMEM;
-
- if ((rc=init_mutex(mutex, name, type)) != PJ_SUCCESS)
- return rc;
-
- *ptr_mutex = mutex;
- return PJ_SUCCESS;
-#else /* PJ_HAS_THREADS */
- return (pj_mutex_t*)1;
-#endif
-}
-
-/*
- * pj_mutex_create_simple()
- */
-PJ_DEF(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool,
- const char *name,
- pj_mutex_t **mutex )
-{
- return pj_mutex_create(pool, name, PJ_MUTEX_SIMPLE, mutex);
-}
-
-/*
- * pj_mutex_create_recursive()
- */
-PJ_DEF(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool,
- const char *name,
- pj_mutex_t **mutex )
-{
- return pj_mutex_create(pool, name, PJ_MUTEX_RECURSE, mutex);
-}
-
-/*
- * pj_mutex_lock()
- */
-PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex)
-{
-#if PJ_HAS_THREADS
- pj_status_t status;
-
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
-
- PJ_LOG(6,(mutex->obj_name, "Mutex: thread %s is waiting",
- pj_thread_this()->obj_name));
-
- status = pthread_mutex_lock( &mutex->mutex );
-
- PJ_LOG(6,(mutex->obj_name,
- (status==0 ? "Mutex acquired by thread %s" : "FAILED by %s"),
- pj_thread_this()->obj_name));
-
-#if PJ_DEBUG
- if (status == PJ_SUCCESS) {
- mutex->owner = pj_thread_this();
- ++mutex->nesting_level;
- }
-#endif
-
- if (status == 0)
- return PJ_SUCCESS;
- else
- return PJ_RETURN_OS_ERROR(status);
-#else /* PJ_HAS_THREADS */
- pj_assert( mutex == (pj_mutex_t*)1 );
- return PJ_SUCCESS;
-#endif
-}
-
-/*
- * pj_mutex_unlock()
- */
-PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex)
-{
-#if PJ_HAS_THREADS
- pj_status_t status;
-
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
-
-#if PJ_DEBUG
- pj_assert(mutex->owner == pj_thread_this());
- if (--mutex->nesting_level == 0) {
- mutex->owner = NULL;
- }
-#endif
-
- PJ_LOG(6,(mutex->obj_name, "Mutex released by thread %s",
- pj_thread_this()->obj_name));
-
- status = pthread_mutex_unlock( &mutex->mutex );
- if (status == 0)
- return PJ_SUCCESS;
- else
- return PJ_RETURN_OS_ERROR(status);
-
-#else /* PJ_HAS_THREADS */
- pj_assert( mutex == (pj_mutex_t*)1 );
- return PJ_SUCCESS;
-#endif
-}
-
-/*
- * pj_mutex_trylock()
- */
-PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex)
-{
-#if PJ_HAS_THREADS
- int status;
-
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
-
- status = pthread_mutex_trylock( &mutex->mutex );
-
- if (status==0) {
- PJ_LOG(6,(mutex->obj_name, "Mutex acquired by thread %s",
- pj_thread_this()->obj_name));
-
-#if PJ_DEBUG
- mutex->owner = pj_thread_this();
- ++mutex->nesting_level;
-#endif
- }
-
- if (status==0)
- return PJ_SUCCESS;
- else
- return PJ_RETURN_OS_ERROR(status);
-#else /* PJ_HAS_THREADS */
- pj_assert( mutex == (pj_mutex_t*)1);
- return PJ_SUCCESS;
-#endif
-}
-
-/*
- * pj_mutex_destroy()
- */
-PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex)
-{
- int status;
-
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
-
-#if PJ_HAS_THREADS
- PJ_LOG(6,(mutex->obj_name, "Mutex destroyed"));
- status = pthread_mutex_destroy( &mutex->mutex );
- if (status == 0)
- return PJ_SUCCESS;
- else
- return PJ_RETURN_OS_ERROR(status);
-#else
- pj_assert( mutex == (pj_mutex_t*)1 );
- status = PJ_SUCCESS;
- return status;
-#endif
-}
-
-#if PJ_DEBUG
-PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex)
-{
-#if PJ_HAS_THREADS
- return mutex->owner == pj_thread_this();
-#else
- return 1;
-#endif
-}
-#endif
-
-///////////////////////////////////////////////////////////////////////////////
-#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
-
-/*
- * pj_sem_create()
- */
-PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool,
- const char *name,
- unsigned initial,
- unsigned max,
- pj_sem_t **ptr_sem)
-{
-#if PJ_HAS_THREADS
- pj_sem_t *sem;
-
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(pool != NULL && ptr_sem != NULL, PJ_EINVAL);
-
- sem = pj_pool_alloc(pool, sizeof(*sem));
- if (!sem) return PJ_ENOMEM;
-
- if (sem_init( &sem->sem, 0, initial) != 0)
- return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
-
- /* Set name. */
- if (!name) {
- name = "sem%p";
- }
- if (strchr(name, '%')) {
- pj_snprintf(sem->obj_name, PJ_MAX_OBJ_NAME, name, sem);
- } else {
- strncpy(sem->obj_name, name, PJ_MAX_OBJ_NAME);
- sem->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
- }
-
- PJ_LOG(6, (sem->obj_name, "Semaphore created"));
-
- *ptr_sem = sem;
- return PJ_SUCCESS;
-#else
- *ptr_sem = (pj_sem_t*)1;
- return PJ_SUCCESS;
-#endif
-}
-
-/*
- * pj_sem_wait()
- */
-PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem)
-{
-#if PJ_HAS_THREADS
- int result;
-
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(sem, PJ_EINVAL);
-
- PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s is waiting",
- pj_thread_this()->obj_name));
-
- result = sem_wait( &sem->sem );
-
- if (result == 0) {
- PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s",
- pj_thread_this()->obj_name));
- } else {
- PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s FAILED to acquire",
- pj_thread_this()->obj_name));
- }
-
- if (result == 0)
- return PJ_SUCCESS;
- else
- return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
-#else
- pj_assert( sem == (pj_sem_t*) 1 );
- return PJ_SUCCESS;
-#endif
-}
-
-/*
- * pj_sem_trywait()
- */
-PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem)
-{
-#if PJ_HAS_THREADS
- int result;
-
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(sem, PJ_EINVAL);
-
- result = sem_trywait( &sem->sem );
-
- if (result == 0) {
- PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s",
- pj_thread_this()->obj_name));
- }
- if (result == 0)
- return PJ_SUCCESS;
- else
- return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
-#else
- pj_assert( sem == (pj_sem_t*)1 );
- return PJ_SUCCESS;
-#endif
-}
-
-/*
- * pj_sem_post()
- */
-PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem)
-{
-#if PJ_HAS_THREADS
- int result;
- PJ_LOG(6, (sem->obj_name, "Semaphore released by thread %s",
- pj_thread_this()->obj_name));
- result = sem_post( &sem->sem );
-
- if (result == 0)
- return PJ_SUCCESS;
- else
- return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
-#else
- pj_assert( sem == (pj_sem_t*) 1);
- return PJ_SUCCESS;
-#endif
-}
-
-/*
- * pj_sem_destroy()
- */
-PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem)
-{
-#if PJ_HAS_THREADS
- int result;
-
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(sem, PJ_EINVAL);
-
- PJ_LOG(6, (sem->obj_name, "Semaphore destroyed by thread %s",
- pj_thread_this()->obj_name));
- result = sem_destroy( &sem->sem );
-
- if (result == 0)
- return PJ_SUCCESS;
- else
- return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
-#else
- pj_assert( sem == (pj_sem_t*) 1 );
- return PJ_SUCCESS;
-#endif
-}
-
-#endif /* PJ_HAS_SEMAPHORE */
-
-///////////////////////////////////////////////////////////////////////////////
-#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0
-
-/*
- * pj_event_create()
- */
-PJ_DEF(pj_status_t) pj_event_create(pj_pool_t *pool, const char *name,
- pj_bool_t manual_reset, pj_bool_t initial,
- pj_event_t **ptr_event)
-{
- pj_assert(!"Not supported!");
- PJ_UNUSED_ARG(pool);
- PJ_UNUSED_ARG(name);
- PJ_UNUSED_ARG(manual_reset);
- PJ_UNUSED_ARG(initial);
- PJ_UNUSED_ARG(ptr_event);
- return PJ_EINVALIDOP;
-}
-
-/*
- * pj_event_wait()
- */
-PJ_DEF(pj_status_t) pj_event_wait(pj_event_t *event)
-{
- PJ_UNUSED_ARG(event);
- return PJ_EINVALIDOP;
-}
-
-/*
- * pj_event_trywait()
- */
-PJ_DEF(pj_status_t) pj_event_trywait(pj_event_t *event)
-{
- PJ_UNUSED_ARG(event);
- return PJ_EINVALIDOP;
-}
-
-/*
- * pj_event_set()
- */
-PJ_DEF(pj_status_t) pj_event_set(pj_event_t *event)
-{
- PJ_UNUSED_ARG(event);
- return PJ_EINVALIDOP;
-}
-
-/*
- * pj_event_pulse()
- */
-PJ_DEF(pj_status_t) pj_event_pulse(pj_event_t *event)
-{
- PJ_UNUSED_ARG(event);
- return PJ_EINVALIDOP;
-}
-
-/*
- * pj_event_reset()
- */
-PJ_DEF(pj_status_t) pj_event_reset(pj_event_t *event)
-{
- PJ_UNUSED_ARG(event);
- return PJ_EINVALIDOP;
-}
-
-/*
- * pj_event_destroy()
- */
-PJ_DEF(pj_status_t) pj_event_destroy(pj_event_t *event)
-{
- PJ_UNUSED_ARG(event);
- return PJ_EINVALIDOP;
-}
-
-#endif /* PJ_HAS_EVENT_OBJ */
-
-///////////////////////////////////////////////////////////////////////////////
-#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0
-/*
- * Terminal
- */
-
-/**
- * Set terminal color.
- */
-PJ_DEF(pj_status_t) pj_term_set_color(pj_color_t color)
-{
- PJ_UNUSED_ARG(color);
- return PJ_EINVALIDOP;
-}
-
-/**
- * Get current terminal foreground color.
- */
-PJ_DEF(pj_color_t) pj_term_get_color(void)
-{
- return 0;
-}
-
-#endif /* PJ_TERM_HAS_COLOR */
-
+
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * pj_thread_local_alloc()
+ */
+PJ_DEF(pj_status_t) pj_thread_local_alloc(long *p_index)
+{
+#if PJ_HAS_THREADS
+ pthread_key_t key;
+ int rc;
+
+ PJ_ASSERT_RETURN(p_index != NULL, PJ_EINVAL);
+
+ pj_assert( sizeof(pthread_key_t) <= sizeof(long));
+ if ((rc=pthread_key_create(&key, NULL)) != 0)
+ return PJ_RETURN_OS_ERROR(rc);
+
+ *p_index = key;
+ return PJ_SUCCESS;
+#else
+ int i;
+ for (i=0; i<MAX_THREADS; ++i) {
+ if (tls_flag[i] == 0)
+ break;
+ }
+ if (i == MAX_THREADS)
+ return PJ_ETOOMANY;
+
+ tls_flag[i] = 1;
+ tls[i] = NULL;
+
+ *p_index = i;
+ return PJ_SUCCESS;
+#endif
+}
+
+/*
+ * pj_thread_local_free()
+ */
+PJ_DEF(void) pj_thread_local_free(long index)
+{
+ PJ_CHECK_STACK();
+#if PJ_HAS_THREADS
+ pthread_key_delete(index);
+#else
+ tls_flag[index] = 0;
+#endif
+}
+
+/*
+ * pj_thread_local_set()
+ */
+PJ_DEF(pj_status_t) pj_thread_local_set(long index, void *value)
+{
+ //Can't check stack because this function is called in the
+ //beginning before main thread is initialized.
+ //PJ_CHECK_STACK();
+#if PJ_HAS_THREADS
+ int rc=pthread_setspecific(index, value);
+ return rc==0 ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(rc);
+#else
+ pj_assert(index >= 0 && index < MAX_THREADS);
+ tls[index] = value;
+ return PJ_SUCCESS;
+#endif
+}
+
+PJ_DEF(void*) pj_thread_local_get(long index)
+{
+ //Can't check stack because this function is called
+ //by PJ_CHECK_STACK() itself!!!
+ //PJ_CHECK_STACK();
+#if PJ_HAS_THREADS
+ return pthread_getspecific(index);
+#else
+ pj_assert(index >= 0 && index < MAX_THREADS);
+ return tls[index];
+#endif
+}
+
+///////////////////////////////////////////////////////////////////////////////
+PJ_DEF(void) pj_enter_critical_section(void)
+{
+#if PJ_HAS_THREADS
+ pj_mutex_lock(&critical_section);
+#endif
+}
+
+PJ_DEF(void) pj_leave_critical_section(void)
+{
+#if PJ_HAS_THREADS
+ pj_mutex_unlock(&critical_section);
+#endif
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name, int type)
+{
+#if PJ_HAS_THREADS
+ pthread_mutexattr_t attr;
+ int rc;
+
+ PJ_CHECK_STACK();
+
+ pthread_mutexattr_init(&attr);
+
+ if (type == PJ_MUTEX_SIMPLE) {
+#if defined(PJ_LINUX) && PJ_LINUX!=0
+ extern int pthread_mutexattr_settype(pthread_mutexattr_t*,int);
+ rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_FAST_NP);
+#else
+ rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
+#endif
+ } else {
+#if defined(PJ_LINUX) && PJ_LINUX!=0
+ extern int pthread_mutexattr_settype(pthread_mutexattr_t*,int);
+ rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
+#else
+ rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+#endif
+ }
+
+ if (rc != 0) {
+ return PJ_RETURN_OS_ERROR(rc);
+ }
+
+ rc = pthread_mutex_init(&mutex->mutex, &attr);
+ if (rc != 0) {
+ return PJ_RETURN_OS_ERROR(rc);
+ }
+
+#if PJ_DEBUG
+ /* Set owner. */
+ mutex->nesting_level = 0;
+ mutex->owner = NULL;
+#endif
+
+ /* Set name. */
+ if (!name) {
+ name = "mtx%p";
+ }
+ if (strchr(name, '%')) {
+ pj_snprintf(mutex->obj_name, PJ_MAX_OBJ_NAME, name, mutex);
+ } else {
+ strncpy(mutex->obj_name, name, PJ_MAX_OBJ_NAME);
+ mutex->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
+ }
+
+ PJ_LOG(6, (mutex->obj_name, "Mutex created"));
+ return PJ_SUCCESS;
+#else /* PJ_HAS_THREADS */
+ return PJ_SUCCESS;
+#endif
+}
+
+/*
+ * pj_mutex_create()
+ */
+PJ_DEF(pj_status_t) pj_mutex_create(pj_pool_t *pool,
+ const char *name,
+ int type,
+ pj_mutex_t **ptr_mutex)
+{
+#if PJ_HAS_THREADS
+ pj_status_t rc;
+ pj_mutex_t *mutex;
+
+ PJ_ASSERT_RETURN(pool && ptr_mutex, PJ_EINVAL);
+
+ mutex = pj_pool_alloc(pool, sizeof(*mutex));
+ if (!mutex) return PJ_ENOMEM;
+
+ if ((rc=init_mutex(mutex, name, type)) != PJ_SUCCESS)
+ return rc;
+
+ *ptr_mutex = mutex;
+ return PJ_SUCCESS;
+#else /* PJ_HAS_THREADS */
+ return (pj_mutex_t*)1;
+#endif
+}
+
+/*
+ * pj_mutex_create_simple()
+ */
+PJ_DEF(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool,
+ const char *name,
+ pj_mutex_t **mutex )
+{
+ return pj_mutex_create(pool, name, PJ_MUTEX_SIMPLE, mutex);
+}
+
+/*
+ * pj_mutex_create_recursive()
+ */
+PJ_DEF(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool,
+ const char *name,
+ pj_mutex_t **mutex )
+{
+ return pj_mutex_create(pool, name, PJ_MUTEX_RECURSE, mutex);
+}
+
+/*
+ * pj_mutex_lock()
+ */
+PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex)
+{
+#if PJ_HAS_THREADS
+ pj_status_t status;
+
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
+
+ PJ_LOG(6,(mutex->obj_name, "Mutex: thread %s is waiting",
+ pj_thread_this()->obj_name));
+
+ status = pthread_mutex_lock( &mutex->mutex );
+
+ PJ_LOG(6,(mutex->obj_name,
+ (status==0 ? "Mutex acquired by thread %s" : "FAILED by %s"),
+ pj_thread_this()->obj_name));
+
+#if PJ_DEBUG
+ if (status == PJ_SUCCESS) {
+ mutex->owner = pj_thread_this();
+ ++mutex->nesting_level;
+ }
+#endif
+
+ if (status == 0)
+ return PJ_SUCCESS;
+ else
+ return PJ_RETURN_OS_ERROR(status);
+#else /* PJ_HAS_THREADS */
+ pj_assert( mutex == (pj_mutex_t*)1 );
+ return PJ_SUCCESS;
+#endif
+}
+
+/*
+ * pj_mutex_unlock()
+ */
+PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex)
+{
+#if PJ_HAS_THREADS
+ pj_status_t status;
+
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
+
+#if PJ_DEBUG
+ pj_assert(mutex->owner == pj_thread_this());
+ if (--mutex->nesting_level == 0) {
+ mutex->owner = NULL;
+ }
+#endif
+
+ PJ_LOG(6,(mutex->obj_name, "Mutex released by thread %s",
+ pj_thread_this()->obj_name));
+
+ status = pthread_mutex_unlock( &mutex->mutex );
+ if (status == 0)
+ return PJ_SUCCESS;
+ else
+ return PJ_RETURN_OS_ERROR(status);
+
+#else /* PJ_HAS_THREADS */
+ pj_assert( mutex == (pj_mutex_t*)1 );
+ return PJ_SUCCESS;
+#endif
+}
+
+/*
+ * pj_mutex_trylock()
+ */
+PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex)
+{
+#if PJ_HAS_THREADS
+ int status;
+
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
+
+ status = pthread_mutex_trylock( &mutex->mutex );
+
+ if (status==0) {
+ PJ_LOG(6,(mutex->obj_name, "Mutex acquired by thread %s",
+ pj_thread_this()->obj_name));
+
+#if PJ_DEBUG
+ mutex->owner = pj_thread_this();
+ ++mutex->nesting_level;
+#endif
+ }
+
+ if (status==0)
+ return PJ_SUCCESS;
+ else
+ return PJ_RETURN_OS_ERROR(status);
+#else /* PJ_HAS_THREADS */
+ pj_assert( mutex == (pj_mutex_t*)1);
+ return PJ_SUCCESS;
+#endif
+}
+
+/*
+ * pj_mutex_destroy()
+ */
+PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex)
+{
+ int status;
+
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
+
+#if PJ_HAS_THREADS
+ PJ_LOG(6,(mutex->obj_name, "Mutex destroyed"));
+ status = pthread_mutex_destroy( &mutex->mutex );
+ if (status == 0)
+ return PJ_SUCCESS;
+ else
+ return PJ_RETURN_OS_ERROR(status);
+#else
+ pj_assert( mutex == (pj_mutex_t*)1 );
+ status = PJ_SUCCESS;
+ return status;
+#endif
+}
+
+#if PJ_DEBUG
+PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex)
+{
+#if PJ_HAS_THREADS
+ return mutex->owner == pj_thread_this();
+#else
+ return 1;
+#endif
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
+
+/*
+ * pj_sem_create()
+ */
+PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool,
+ const char *name,
+ unsigned initial,
+ unsigned max,
+ pj_sem_t **ptr_sem)
+{
+#if PJ_HAS_THREADS
+ pj_sem_t *sem;
+
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(pool != NULL && ptr_sem != NULL, PJ_EINVAL);
+
+ sem = pj_pool_alloc(pool, sizeof(*sem));
+ if (!sem) return PJ_ENOMEM;
+
+ if (sem_init( &sem->sem, 0, initial) != 0)
+ return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
+
+ /* Set name. */
+ if (!name) {
+ name = "sem%p";
+ }
+ if (strchr(name, '%')) {
+ pj_snprintf(sem->obj_name, PJ_MAX_OBJ_NAME, name, sem);
+ } else {
+ strncpy(sem->obj_name, name, PJ_MAX_OBJ_NAME);
+ sem->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
+ }
+
+ PJ_LOG(6, (sem->obj_name, "Semaphore created"));
+
+ *ptr_sem = sem;
+ return PJ_SUCCESS;
+#else
+ *ptr_sem = (pj_sem_t*)1;
+ return PJ_SUCCESS;
+#endif
+}
+
+/*
+ * pj_sem_wait()
+ */
+PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem)
+{
+#if PJ_HAS_THREADS
+ int result;
+
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(sem, PJ_EINVAL);
+
+ PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s is waiting",
+ pj_thread_this()->obj_name));
+
+ result = sem_wait( &sem->sem );
+
+ if (result == 0) {
+ PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s",
+ pj_thread_this()->obj_name));
+ } else {
+ PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s FAILED to acquire",
+ pj_thread_this()->obj_name));
+ }
+
+ if (result == 0)
+ return PJ_SUCCESS;
+ else
+ return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
+#else
+ pj_assert( sem == (pj_sem_t*) 1 );
+ return PJ_SUCCESS;
+#endif
+}
+
+/*
+ * pj_sem_trywait()
+ */
+PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem)
+{
+#if PJ_HAS_THREADS
+ int result;
+
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(sem, PJ_EINVAL);
+
+ result = sem_trywait( &sem->sem );
+
+ if (result == 0) {
+ PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s",
+ pj_thread_this()->obj_name));
+ }
+ if (result == 0)
+ return PJ_SUCCESS;
+ else
+ return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
+#else
+ pj_assert( sem == (pj_sem_t*)1 );
+ return PJ_SUCCESS;
+#endif
+}
+
+/*
+ * pj_sem_post()
+ */
+PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem)
+{
+#if PJ_HAS_THREADS
+ int result;
+ PJ_LOG(6, (sem->obj_name, "Semaphore released by thread %s",
+ pj_thread_this()->obj_name));
+ result = sem_post( &sem->sem );
+
+ if (result == 0)
+ return PJ_SUCCESS;
+ else
+ return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
+#else
+ pj_assert( sem == (pj_sem_t*) 1);
+ return PJ_SUCCESS;
+#endif
+}
+
+/*
+ * pj_sem_destroy()
+ */
+PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem)
+{
+#if PJ_HAS_THREADS
+ int result;
+
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(sem, PJ_EINVAL);
+
+ PJ_LOG(6, (sem->obj_name, "Semaphore destroyed by thread %s",
+ pj_thread_this()->obj_name));
+ result = sem_destroy( &sem->sem );
+
+ if (result == 0)
+ return PJ_SUCCESS;
+ else
+ return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
+#else
+ pj_assert( sem == (pj_sem_t*) 1 );
+ return PJ_SUCCESS;
+#endif
+}
+
+#endif /* PJ_HAS_SEMAPHORE */
+
+///////////////////////////////////////////////////////////////////////////////
+#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0
+
+/*
+ * pj_event_create()
+ */
+PJ_DEF(pj_status_t) pj_event_create(pj_pool_t *pool, const char *name,
+ pj_bool_t manual_reset, pj_bool_t initial,
+ pj_event_t **ptr_event)
+{
+ pj_assert(!"Not supported!");
+ PJ_UNUSED_ARG(pool);
+ PJ_UNUSED_ARG(name);
+ PJ_UNUSED_ARG(manual_reset);
+ PJ_UNUSED_ARG(initial);
+ PJ_UNUSED_ARG(ptr_event);
+ return PJ_EINVALIDOP;
+}
+
+/*
+ * pj_event_wait()
+ */
+PJ_DEF(pj_status_t) pj_event_wait(pj_event_t *event)
+{
+ PJ_UNUSED_ARG(event);
+ return PJ_EINVALIDOP;
+}
+
+/*
+ * pj_event_trywait()
+ */
+PJ_DEF(pj_status_t) pj_event_trywait(pj_event_t *event)
+{
+ PJ_UNUSED_ARG(event);
+ return PJ_EINVALIDOP;
+}
+
+/*
+ * pj_event_set()
+ */
+PJ_DEF(pj_status_t) pj_event_set(pj_event_t *event)
+{
+ PJ_UNUSED_ARG(event);
+ return PJ_EINVALIDOP;
+}
+
+/*
+ * pj_event_pulse()
+ */
+PJ_DEF(pj_status_t) pj_event_pulse(pj_event_t *event)
+{
+ PJ_UNUSED_ARG(event);
+ return PJ_EINVALIDOP;
+}
+
+/*
+ * pj_event_reset()
+ */
+PJ_DEF(pj_status_t) pj_event_reset(pj_event_t *event)
+{
+ PJ_UNUSED_ARG(event);
+ return PJ_EINVALIDOP;
+}
+
+/*
+ * pj_event_destroy()
+ */
+PJ_DEF(pj_status_t) pj_event_destroy(pj_event_t *event)
+{
+ PJ_UNUSED_ARG(event);
+ return PJ_EINVALIDOP;
+}
+
+#endif /* PJ_HAS_EVENT_OBJ */
+
+///////////////////////////////////////////////////////////////////////////////
+#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0
+/*
+ * Terminal
+ */
+
+/**
+ * Set terminal color.
+ */
+PJ_DEF(pj_status_t) pj_term_set_color(pj_color_t color)
+{
+ PJ_UNUSED_ARG(color);
+ return PJ_EINVALIDOP;
+}
+
+/**
+ * Get current terminal foreground color.
+ */
+PJ_DEF(pj_color_t) pj_term_get_color(void)
+{
+ return 0;
+}
+
+#endif /* PJ_TERM_HAS_COLOR */
+
diff --git a/pjlib/src/pj/os_core_win32.c b/pjlib/src/pj/os_core_win32.c
index be770d56..c4c4304d 100644
--- a/pjlib/src/pj/os_core_win32.c
+++ b/pjlib/src/pj/os_core_win32.c
@@ -1,517 +1,538 @@
-/* $Id$
- */
-#include <pj/os.h>
-#include <pj/pool.h>
-#include <pj/log.h>
-#include <pj/string.h>
-#include <pj/guid.h>
-#include <pj/rand.h>
-#include <pj/assert.h>
-#include <pj/compat/vsprintf.h>
-#include <pj/compat/sprintf.h>
-#include <pj/errno.h>
-#include <pj/except.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#if defined(PJ_HAS_WINSOCK_H) && PJ_HAS_WINSOCK_H != 0
-# include <winsock.h>
-#endif
-
-#if defined(PJ_HAS_WINSOCK2_H) && PJ_HAS_WINSOCK2_H != 0
-# include <winsock2.h>
-#endif
-
-/*
- * Implementation of pj_thread_t.
- */
-struct pj_thread_t
-{
- char obj_name[PJ_MAX_OBJ_NAME];
- HANDLE hthread;
- DWORD idthread;
- pj_thread_proc *proc;
- void *arg;
-
-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
- pj_uint32_t stk_size;
- pj_uint32_t stk_max_usage;
- char *stk_start;
- const char *caller_file;
- int caller_line;
-#endif
-};
-
-
-/*
- * Implementation of pj_mutex_t.
- */
-struct pj_mutex_t
-{
-#if PJ_WIN32_WINNT >= 0x0400
- CRITICAL_SECTION crit;
-#else
- HANDLE hMutex;
-#endif
- char obj_name[PJ_MAX_OBJ_NAME];
-#if PJ_DEBUG
- int nesting_level;
- pj_thread_t *owner;
-#endif
-};
-
-/*
- * Implementation of pj_sem_t.
- */
-typedef struct pj_sem_t
-{
- HANDLE hSemaphore;
- char obj_name[PJ_MAX_OBJ_NAME];
-} pj_mem_t;
-
-
-/*
- * Implementation of pj_event_t.
- */
-struct pj_event_t
-{
- HANDLE hEvent;
- char obj_name[PJ_MAX_OBJ_NAME];
-};
-
-/*
- * Implementation of pj_atomic_t.
- */
-struct pj_atomic_t
-{
- long value;
-};
-
-/*
- * Static global variables.
- */
-static pj_thread_desc main_thread;
-static long thread_tls_id;
-static pj_mutex_t critical_section_mutex;
-
-
-/*
- * Some static prototypes.
- */
-static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name);
-
-
-/*
- * pj_init(void).
- * Init PJLIB!
- */
-PJ_DEF(pj_status_t) pj_init(void)
-{
- WSADATA wsa;
- char dummy_guid[32]; /* use maximum GUID length */
- pj_str_t guid;
- pj_status_t rc;
-
- PJ_LOG(5, ("pj_init", "Initializing PJ Library.."));
-
- /* Init Winsock.. */
- if (WSAStartup(MAKEWORD(2,0), &wsa) != 0) {
- PJ_LOG(1, ("pj_init", "Winsock initialization has returned an error"));
- return PJ_RETURN_OS_ERROR(WSAGetLastError());
- }
-
- /* Init this thread's TLS. */
- if ((rc=pj_thread_init()) != PJ_SUCCESS) {
- PJ_LOG(1, ("pj_init", "Thread initialization has returned an error"));
- return rc;
- }
-
- /* Init random seed. */
- pj_srand( GetCurrentProcessId() );
-
- /* Startup GUID. */
- guid.ptr = dummy_guid;
- pj_generate_unique_string( &guid );
-
- /* Initialize critical section. */
- if ((rc=init_mutex(&critical_section_mutex, "pj%p")) != PJ_SUCCESS)
- return rc;
-
- /* Initialize exception ID for the pool.
- * Must do so after critical section is configured.
- */
- rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION);
- if (rc != PJ_SUCCESS)
- return rc;
-
- /* Startup timestamp */
-#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0
- {
- pj_timestamp dummy_ts;
- if ((rc=pj_get_timestamp(&dummy_ts)) != PJ_SUCCESS) {
- PJ_LOG(1, ("pj_init", "Unable to initialize timestamp"));
- return rc;
- }
- }
-#endif
-
- return PJ_SUCCESS;
-}
-
-/*
- * pj_getpid(void)
- */
-PJ_DEF(pj_uint32_t) pj_getpid(void)
-{
- PJ_CHECK_STACK();
- return GetCurrentProcessId();
-}
-
-/*
- * pj_thread_register(..)
- */
-PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name,
- pj_thread_desc desc,
- pj_thread_t **thread_ptr)
-{
- char stack_ptr;
- pj_status_t rc;
- pj_thread_t *thread = (pj_thread_t *)desc;
- pj_str_t thread_name = pj_str((char*)cstr_thread_name);
-
- /* Size sanity check. */
- if (sizeof(pj_thread_desc) < sizeof(pj_thread_t)) {
- pj_assert(!"Not enough pj_thread_desc size!");
- return PJ_EBUG;
- }
-
- /* If a thread descriptor has been registered before, just return it. */
- if (pj_thread_local_get (thread_tls_id) != 0) {
- *thread_ptr = (pj_thread_t*)pj_thread_local_get (thread_tls_id);
- return PJ_SUCCESS;
- }
-
- /* Initialize and set the thread entry. */
- pj_memset(desc, 0, sizeof(struct pj_thread_t));
- thread->hthread = GetCurrentThread();
- thread->idthread = GetCurrentThreadId();
-
-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
- thread->stk_start = &stack_ptr;
- thread->stk_size = 0xFFFFFFFFUL;
- thread->stk_max_usage = 0;
-#else
- stack_ptr = '\0';
-#endif
-
- if (cstr_thread_name && pj_strlen(&thread_name) < sizeof(thread->obj_name)-1)
- pj_sprintf(thread->obj_name, cstr_thread_name, thread->idthread);
- else
- pj_sprintf(thread->obj_name, "thr%p", (void*)thread->idthread);
-
- rc = pj_thread_local_set(thread_tls_id, thread);
- if (rc != PJ_SUCCESS)
- return rc;
-
- *thread_ptr = thread;
- return PJ_SUCCESS;
-}
-
-/*
- * pj_thread_init(void)
- */
-pj_status_t pj_thread_init(void)
-{
- pj_status_t rc;
- pj_thread_t *thread;
-
- rc = pj_thread_local_alloc(&thread_tls_id);
- if (rc != PJ_SUCCESS)
- return rc;
-
- return pj_thread_register("thr%p", main_thread, &thread);
-}
-
-static DWORD WINAPI thread_main(void *param)
-{
- pj_thread_t *rec = param;
- DWORD result;
-
-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
- rec->stk_start = (char*)&rec;
-#endif
-
- PJ_LOG(6,(rec->obj_name, "Thread started"));
-
- if (pj_thread_local_set(thread_tls_id, rec) != PJ_SUCCESS) {
- pj_assert(!"TLS is not set (pj_init() error?)");
- }
-
- result = (*rec->proc)(rec->arg);
-
- PJ_LOG(6,(rec->obj_name, "Thread quitting"));
- return (DWORD)result;
-}
-
-/*
- * pj_thread_create(...)
- */
-PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool,
- const char *thread_name,
- pj_thread_proc *proc,
- void *arg,
- pj_size_t stack_size,
- unsigned flags,
- pj_thread_t **thread_ptr)
-{
- DWORD dwflags = 0;
- pj_thread_t *rec;
-
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(pool && proc && thread_ptr, PJ_EINVAL);
-
- /* Set flags */
- if (flags & PJ_THREAD_SUSPENDED)
- dwflags |= CREATE_SUSPENDED;
-
- /* Create thread record and assign name for the thread */
- rec = (struct pj_thread_t*) pj_pool_calloc(pool, 1, sizeof(pj_thread_t));
- if (!rec)
- return PJ_ENOMEM;
-
- /* Set name. */
- if (!thread_name)
- thread_name = "thr%p";
-
- if (strchr(thread_name, '%')) {
- pj_snprintf(rec->obj_name, PJ_MAX_OBJ_NAME, thread_name, rec);
- } else {
- strncpy(rec->obj_name, thread_name, PJ_MAX_OBJ_NAME);
- rec->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
- }
-
- PJ_LOG(6, (rec->obj_name, "Thread created"));
-
-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
- rec->stk_size = stack_size ? stack_size : 0xFFFFFFFFUL;
- rec->stk_max_usage = 0;
-#endif
-
- /* Create the thread. */
- rec->proc = proc;
- rec->arg = arg;
- rec->hthread = CreateThread(NULL, stack_size,
- thread_main, rec,
- dwflags, &rec->idthread);
- if (rec->hthread == NULL)
- return PJ_RETURN_OS_ERROR(GetLastError());
-
- /* Success! */
- *thread_ptr = rec;
- return PJ_SUCCESS;
-}
-
-/*
- * pj_thread-get_name()
- */
-PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *p)
-{
- pj_thread_t *rec = (pj_thread_t*)p;
-
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(p, "");
-
- return rec->obj_name;
-}
-
-/*
- * pj_thread_resume()
- */
-PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *p)
-{
- pj_thread_t *rec = (pj_thread_t*)p;
-
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(p, PJ_EINVAL);
-
- if (ResumeThread(rec->hthread) == (DWORD)-1)
- return PJ_RETURN_OS_ERROR(GetLastError());
- else
- return PJ_SUCCESS;
-}
-
-/*
- * pj_thread_this()
- */
-PJ_DEF(pj_thread_t*) pj_thread_this(void)
-{
- pj_thread_t *rec = pj_thread_local_get(thread_tls_id);
- pj_assert(rec != NULL);
-
- /*
- * MUST NOT check stack because this function is called
- * by PJ_CHECK_STACK() itself!!!
- *
- */
-
- return rec;
-}
-
-/*
- * pj_thread_join()
- */
-PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p)
-{
- pj_thread_t *rec = (pj_thread_t *)p;
- DWORD rc;
-
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(p, PJ_EINVAL);
-
- PJ_LOG(6, (pj_thread_this()->obj_name, "Joining thread %s", p->obj_name));
-
- rc = WaitForSingleObject(rec->hthread, INFINITE);
-
- if (rc==WAIT_OBJECT_0)
- return PJ_SUCCESS;
- else if (rc==WAIT_TIMEOUT)
- return PJ_ETIMEDOUT;
- else
- return PJ_RETURN_OS_ERROR(GetLastError());
-}
-
-/*
- * pj_thread_destroy()
- */
-PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *p)
-{
- pj_thread_t *rec = (pj_thread_t *)p;
-
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(p, PJ_EINVAL);
-
- if (CloseHandle(rec->hthread) == TRUE)
- return PJ_SUCCESS;
- else
- return PJ_RETURN_OS_ERROR(GetLastError());
-}
-
-/*
- * pj_thread_sleep()
- */
-PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec)
-{
- PJ_CHECK_STACK();
- Sleep(msec);
- return PJ_SUCCESS;
-}
-
-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK != 0
-/*
- * pj_thread_check_stack()
- * Implementation for PJ_CHECK_STACK()
- */
-PJ_DEF(void) pj_thread_check_stack(const char *file, int line)
-{
- char stk_ptr;
- pj_uint32_t usage;
- pj_thread_t *thread = pj_thread_this();
-
- pj_assert(thread);
-
- /* Calculate current usage. */
- usage = (&stk_ptr > thread->stk_start) ? &stk_ptr - thread->stk_start :
- thread->stk_start - &stk_ptr;
-
- /* Assert if stack usage is dangerously high. */
- pj_assert("STACK OVERFLOW!! " && (usage <= thread->stk_size - 128));
-
- /* Keep statistic. */
- if (usage > thread->stk_max_usage) {
- thread->stk_max_usage = usage;
- thread->caller_file = file;
- thread->caller_line = line;
- }
-
-}
-
-/*
- * pj_thread_get_stack_max_usage()
- */
-PJ_DEF(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread)
-{
- return thread->stk_max_usage;
-}
-
-/*
- * pj_thread_get_stack_info()
- */
-PJ_DEF(pj_status_t) pj_thread_get_stack_info( pj_thread_t *thread,
- const char **file,
- int *line )
-{
- pj_assert(thread);
-
- *file = thread->caller_file;
- *line = thread->caller_line;
- return 0;
-}
-
-#endif /* PJ_OS_HAS_CHECK_STACK */
-
-
-///////////////////////////////////////////////////////////////////////////////
-
-/*
- * pj_atomic_create()
- */
-PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool,
- pj_atomic_value_t initial,
- pj_atomic_t **atomic_ptr)
-{
- pj_atomic_t *atomic_var = pj_pool_alloc(pool, sizeof(pj_atomic_t));
- if (!atomic_var)
- return PJ_ENOMEM;
-
- atomic_var->value = initial;
- *atomic_ptr = atomic_var;
-
- return PJ_SUCCESS;
-}
-
-/*
- * pj_atomic_destroy()
- */
-PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *var )
-{
- PJ_UNUSED_ARG(var);
- PJ_ASSERT_RETURN(var, PJ_EINVAL);
-
- return 0;
-}
-
-/*
- * pj_atomic_set()
- */
-PJ_DEF(void) pj_atomic_set( pj_atomic_t *atomic_var, pj_atomic_value_t value)
-{
- PJ_CHECK_STACK();
-
- InterlockedExchange(&atomic_var->value, value);
-}
-
-/*
- * pj_atomic_get()
- */
-PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var)
-{
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(atomic_var, 0);
-
- return atomic_var->value;
-}
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/os.h>
+#include <pj/pool.h>
+#include <pj/log.h>
+#include <pj/string.h>
+#include <pj/guid.h>
+#include <pj/rand.h>
+#include <pj/assert.h>
+#include <pj/compat/vsprintf.h>
+#include <pj/compat/sprintf.h>
+#include <pj/errno.h>
+#include <pj/except.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#if defined(PJ_HAS_WINSOCK_H) && PJ_HAS_WINSOCK_H != 0
+# include <winsock.h>
+#endif
+
+#if defined(PJ_HAS_WINSOCK2_H) && PJ_HAS_WINSOCK2_H != 0
+# include <winsock2.h>
+#endif
+
+/*
+ * Implementation of pj_thread_t.
+ */
+struct pj_thread_t
+{
+ char obj_name[PJ_MAX_OBJ_NAME];
+ HANDLE hthread;
+ DWORD idthread;
+ pj_thread_proc *proc;
+ void *arg;
+
+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
+ pj_uint32_t stk_size;
+ pj_uint32_t stk_max_usage;
+ char *stk_start;
+ const char *caller_file;
+ int caller_line;
+#endif
+};
+
+
+/*
+ * Implementation of pj_mutex_t.
+ */
+struct pj_mutex_t
+{
+#if PJ_WIN32_WINNT >= 0x0400
+ CRITICAL_SECTION crit;
+#else
+ HANDLE hMutex;
+#endif
+ char obj_name[PJ_MAX_OBJ_NAME];
+#if PJ_DEBUG
+ int nesting_level;
+ pj_thread_t *owner;
+#endif
+};
+
+/*
+ * Implementation of pj_sem_t.
+ */
+typedef struct pj_sem_t
+{
+ HANDLE hSemaphore;
+ char obj_name[PJ_MAX_OBJ_NAME];
+} pj_mem_t;
+
+
+/*
+ * Implementation of pj_event_t.
+ */
+struct pj_event_t
+{
+ HANDLE hEvent;
+ char obj_name[PJ_MAX_OBJ_NAME];
+};
+
+/*
+ * Implementation of pj_atomic_t.
+ */
+struct pj_atomic_t
+{
+ long value;
+};
+
+/*
+ * Static global variables.
+ */
+static pj_thread_desc main_thread;
+static long thread_tls_id;
+static pj_mutex_t critical_section_mutex;
+
+
+/*
+ * Some static prototypes.
+ */
+static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name);
+
+
+/*
+ * pj_init(void).
+ * Init PJLIB!
+ */
+PJ_DEF(pj_status_t) pj_init(void)
+{
+ WSADATA wsa;
+ char dummy_guid[32]; /* use maximum GUID length */
+ pj_str_t guid;
+ pj_status_t rc;
+
+ PJ_LOG(5, ("pj_init", "Initializing PJ Library.."));
+
+ /* Init Winsock.. */
+ if (WSAStartup(MAKEWORD(2,0), &wsa) != 0) {
+ PJ_LOG(1, ("pj_init", "Winsock initialization has returned an error"));
+ return PJ_RETURN_OS_ERROR(WSAGetLastError());
+ }
+
+ /* Init this thread's TLS. */
+ if ((rc=pj_thread_init()) != PJ_SUCCESS) {
+ PJ_LOG(1, ("pj_init", "Thread initialization has returned an error"));
+ return rc;
+ }
+
+ /* Init random seed. */
+ pj_srand( GetCurrentProcessId() );
+
+ /* Startup GUID. */
+ guid.ptr = dummy_guid;
+ pj_generate_unique_string( &guid );
+
+ /* Initialize critical section. */
+ if ((rc=init_mutex(&critical_section_mutex, "pj%p")) != PJ_SUCCESS)
+ return rc;
+
+ /* Initialize exception ID for the pool.
+ * Must do so after critical section is configured.
+ */
+ rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION);
+ if (rc != PJ_SUCCESS)
+ return rc;
+
+ /* Startup timestamp */
+#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0
+ {
+ pj_timestamp dummy_ts;
+ if ((rc=pj_get_timestamp(&dummy_ts)) != PJ_SUCCESS) {
+ PJ_LOG(1, ("pj_init", "Unable to initialize timestamp"));
+ return rc;
+ }
+ }
+#endif
+
+ return PJ_SUCCESS;
+}
+
+/*
+ * pj_getpid(void)
+ */
+PJ_DEF(pj_uint32_t) pj_getpid(void)
+{
+ PJ_CHECK_STACK();
+ return GetCurrentProcessId();
+}
+
+/*
+ * pj_thread_register(..)
+ */
+PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name,
+ pj_thread_desc desc,
+ pj_thread_t **thread_ptr)
+{
+ char stack_ptr;
+ pj_status_t rc;
+ pj_thread_t *thread = (pj_thread_t *)desc;
+ pj_str_t thread_name = pj_str((char*)cstr_thread_name);
+
+ /* Size sanity check. */
+ if (sizeof(pj_thread_desc) < sizeof(pj_thread_t)) {
+ pj_assert(!"Not enough pj_thread_desc size!");
+ return PJ_EBUG;
+ }
+
+ /* If a thread descriptor has been registered before, just return it. */
+ if (pj_thread_local_get (thread_tls_id) != 0) {
+ *thread_ptr = (pj_thread_t*)pj_thread_local_get (thread_tls_id);
+ return PJ_SUCCESS;
+ }
+
+ /* Initialize and set the thread entry. */
+ pj_memset(desc, 0, sizeof(struct pj_thread_t));
+ thread->hthread = GetCurrentThread();
+ thread->idthread = GetCurrentThreadId();
+
+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
+ thread->stk_start = &stack_ptr;
+ thread->stk_size = 0xFFFFFFFFUL;
+ thread->stk_max_usage = 0;
+#else
+ stack_ptr = '\0';
+#endif
+
+ if (cstr_thread_name && pj_strlen(&thread_name) < sizeof(thread->obj_name)-1)
+ pj_sprintf(thread->obj_name, cstr_thread_name, thread->idthread);
+ else
+ pj_sprintf(thread->obj_name, "thr%p", (void*)thread->idthread);
+
+ rc = pj_thread_local_set(thread_tls_id, thread);
+ if (rc != PJ_SUCCESS)
+ return rc;
+
+ *thread_ptr = thread;
+ return PJ_SUCCESS;
+}
+
+/*
+ * pj_thread_init(void)
+ */
+pj_status_t pj_thread_init(void)
+{
+ pj_status_t rc;
+ pj_thread_t *thread;
+
+ rc = pj_thread_local_alloc(&thread_tls_id);
+ if (rc != PJ_SUCCESS)
+ return rc;
+
+ return pj_thread_register("thr%p", main_thread, &thread);
+}
+
+static DWORD WINAPI thread_main(void *param)
+{
+ pj_thread_t *rec = param;
+ DWORD result;
+
+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
+ rec->stk_start = (char*)&rec;
+#endif
+
+ PJ_LOG(6,(rec->obj_name, "Thread started"));
+
+ if (pj_thread_local_set(thread_tls_id, rec) != PJ_SUCCESS) {
+ pj_assert(!"TLS is not set (pj_init() error?)");
+ }
+
+ result = (*rec->proc)(rec->arg);
+
+ PJ_LOG(6,(rec->obj_name, "Thread quitting"));
+ return (DWORD)result;
+}
+
+/*
+ * pj_thread_create(...)
+ */
+PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool,
+ const char *thread_name,
+ pj_thread_proc *proc,
+ void *arg,
+ pj_size_t stack_size,
+ unsigned flags,
+ pj_thread_t **thread_ptr)
+{
+ DWORD dwflags = 0;
+ pj_thread_t *rec;
+
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(pool && proc && thread_ptr, PJ_EINVAL);
+
+ /* Set flags */
+ if (flags & PJ_THREAD_SUSPENDED)
+ dwflags |= CREATE_SUSPENDED;
+
+ /* Create thread record and assign name for the thread */
+ rec = (struct pj_thread_t*) pj_pool_calloc(pool, 1, sizeof(pj_thread_t));
+ if (!rec)
+ return PJ_ENOMEM;
+
+ /* Set name. */
+ if (!thread_name)
+ thread_name = "thr%p";
+
+ if (strchr(thread_name, '%')) {
+ pj_snprintf(rec->obj_name, PJ_MAX_OBJ_NAME, thread_name, rec);
+ } else {
+ strncpy(rec->obj_name, thread_name, PJ_MAX_OBJ_NAME);
+ rec->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
+ }
+
+ PJ_LOG(6, (rec->obj_name, "Thread created"));
+
+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
+ rec->stk_size = stack_size ? stack_size : 0xFFFFFFFFUL;
+ rec->stk_max_usage = 0;
+#endif
+
+ /* Create the thread. */
+ rec->proc = proc;
+ rec->arg = arg;
+ rec->hthread = CreateThread(NULL, stack_size,
+ thread_main, rec,
+ dwflags, &rec->idthread);
+ if (rec->hthread == NULL)
+ return PJ_RETURN_OS_ERROR(GetLastError());
+
+ /* Success! */
+ *thread_ptr = rec;
+ return PJ_SUCCESS;
+}
+
+/*
+ * pj_thread-get_name()
+ */
+PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *p)
+{
+ pj_thread_t *rec = (pj_thread_t*)p;
+
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(p, "");
+
+ return rec->obj_name;
+}
+
+/*
+ * pj_thread_resume()
+ */
+PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *p)
+{
+ pj_thread_t *rec = (pj_thread_t*)p;
+
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(p, PJ_EINVAL);
+
+ if (ResumeThread(rec->hthread) == (DWORD)-1)
+ return PJ_RETURN_OS_ERROR(GetLastError());
+ else
+ return PJ_SUCCESS;
+}
+
+/*
+ * pj_thread_this()
+ */
+PJ_DEF(pj_thread_t*) pj_thread_this(void)
+{
+ pj_thread_t *rec = pj_thread_local_get(thread_tls_id);
+ pj_assert(rec != NULL);
+
+ /*
+ * MUST NOT check stack because this function is called
+ * by PJ_CHECK_STACK() itself!!!
+ *
+ */
+
+ return rec;
+}
+
+/*
+ * pj_thread_join()
+ */
+PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p)
+{
+ pj_thread_t *rec = (pj_thread_t *)p;
+ DWORD rc;
+
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(p, PJ_EINVAL);
+
+ PJ_LOG(6, (pj_thread_this()->obj_name, "Joining thread %s", p->obj_name));
+
+ rc = WaitForSingleObject(rec->hthread, INFINITE);
+
+ if (rc==WAIT_OBJECT_0)
+ return PJ_SUCCESS;
+ else if (rc==WAIT_TIMEOUT)
+ return PJ_ETIMEDOUT;
+ else
+ return PJ_RETURN_OS_ERROR(GetLastError());
+}
+
+/*
+ * pj_thread_destroy()
+ */
+PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *p)
+{
+ pj_thread_t *rec = (pj_thread_t *)p;
+
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(p, PJ_EINVAL);
+
+ if (CloseHandle(rec->hthread) == TRUE)
+ return PJ_SUCCESS;
+ else
+ return PJ_RETURN_OS_ERROR(GetLastError());
+}
+
+/*
+ * pj_thread_sleep()
+ */
+PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec)
+{
+ PJ_CHECK_STACK();
+ Sleep(msec);
+ return PJ_SUCCESS;
+}
+
+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK != 0
+/*
+ * pj_thread_check_stack()
+ * Implementation for PJ_CHECK_STACK()
+ */
+PJ_DEF(void) pj_thread_check_stack(const char *file, int line)
+{
+ char stk_ptr;
+ pj_uint32_t usage;
+ pj_thread_t *thread = pj_thread_this();
+
+ pj_assert(thread);
+
+ /* Calculate current usage. */
+ usage = (&stk_ptr > thread->stk_start) ? &stk_ptr - thread->stk_start :
+ thread->stk_start - &stk_ptr;
+
+ /* Assert if stack usage is dangerously high. */
+ pj_assert("STACK OVERFLOW!! " && (usage <= thread->stk_size - 128));
+
+ /* Keep statistic. */
+ if (usage > thread->stk_max_usage) {
+ thread->stk_max_usage = usage;
+ thread->caller_file = file;
+ thread->caller_line = line;
+ }
+
+}
+
+/*
+ * pj_thread_get_stack_max_usage()
+ */
+PJ_DEF(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread)
+{
+ return thread->stk_max_usage;
+}
+
+/*
+ * pj_thread_get_stack_info()
+ */
+PJ_DEF(pj_status_t) pj_thread_get_stack_info( pj_thread_t *thread,
+ const char **file,
+ int *line )
+{
+ pj_assert(thread);
+
+ *file = thread->caller_file;
+ *line = thread->caller_line;
+ return 0;
+}
+
+#endif /* PJ_OS_HAS_CHECK_STACK */
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+/*
+ * pj_atomic_create()
+ */
+PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool,
+ pj_atomic_value_t initial,
+ pj_atomic_t **atomic_ptr)
+{
+ pj_atomic_t *atomic_var = pj_pool_alloc(pool, sizeof(pj_atomic_t));
+ if (!atomic_var)
+ return PJ_ENOMEM;
+
+ atomic_var->value = initial;
+ *atomic_ptr = atomic_var;
+
+ return PJ_SUCCESS;
+}
+
+/*
+ * pj_atomic_destroy()
+ */
+PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *var )
+{
+ PJ_UNUSED_ARG(var);
+ PJ_ASSERT_RETURN(var, PJ_EINVAL);
+
+ return 0;
+}
+
+/*
+ * pj_atomic_set()
+ */
+PJ_DEF(void) pj_atomic_set( pj_atomic_t *atomic_var, pj_atomic_value_t value)
+{
+ PJ_CHECK_STACK();
+
+ InterlockedExchange(&atomic_var->value, value);
+}
+
+/*
+ * pj_atomic_get()
+ */
+PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var)
+{
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(atomic_var, 0);
+
+ return atomic_var->value;
+}
+
/*
* pj_atomic_inc_and_get()
*/
@@ -526,13 +547,13 @@ PJ_DEF(pj_atomic_value_t) pj_atomic_inc_and_get(pj_atomic_t *atomic_var)
#endif
}
-/*
- * pj_atomic_inc()
- */
-PJ_DEF(void) pj_atomic_inc(pj_atomic_t *atomic_var)
+/*
+ * pj_atomic_inc()
+ */
+PJ_DEF(void) pj_atomic_inc(pj_atomic_t *atomic_var)
{
- pj_atomic_inc_and_get(atomic_var);
-}
+ pj_atomic_inc_and_get(atomic_var);
+}
/*
* pj_atomic_dec_and_get()
@@ -548,26 +569,26 @@ PJ_DEF(pj_atomic_value_t) pj_atomic_dec_and_get(pj_atomic_t *atomic_var)
#endif
}
-/*
- * pj_atomic_dec()
- */
-PJ_DEF(void) pj_atomic_dec(pj_atomic_t *atomic_var)
-{
- pj_atomic_dec_and_get(atomic_var);
-}
-
-/*
- * pj_atomic_add()
- */
-PJ_DEF(void) pj_atomic_add( pj_atomic_t *atomic_var,
- pj_atomic_value_t value )
-{
+/*
+ * pj_atomic_dec()
+ */
+PJ_DEF(void) pj_atomic_dec(pj_atomic_t *atomic_var)
+{
+ pj_atomic_dec_and_get(atomic_var);
+}
+
+/*
+ * pj_atomic_add()
+ */
+PJ_DEF(void) pj_atomic_add( pj_atomic_t *atomic_var,
+ pj_atomic_value_t value )
+{
#if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400
InterlockedExchangeAdd( &atomic_var->value, value );
#else
# error Fix me
-#endif
-}
+#endif
+}
/*
* pj_atomic_add_and_get()
@@ -581,635 +602,635 @@ PJ_DEF(pj_atomic_value_t) pj_atomic_add_and_get( pj_atomic_t *atomic_var,
#else
# error Fix me
#endif
-}
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * pj_thread_local_alloc()
- */
-PJ_DEF(pj_status_t) pj_thread_local_alloc(long *index)
-{
- PJ_ASSERT_RETURN(index != NULL, PJ_EINVAL);
-
- //Can't check stack because this function is called in the
- //beginning before main thread is initialized.
- //PJ_CHECK_STACK();
-
- *index = TlsAlloc();
-
- if (*index == TLS_OUT_OF_INDEXES)
- return PJ_RETURN_OS_ERROR(GetLastError());
- else
- return PJ_SUCCESS;
-}
-
-/*
- * pj_thread_local_free()
- */
-PJ_DEF(void) pj_thread_local_free(long index)
-{
- PJ_CHECK_STACK();
- TlsFree(index);
-}
-
-/*
- * pj_thread_local_set()
- */
-PJ_DEF(pj_status_t) pj_thread_local_set(long index, void *value)
-{
- BOOL rc;
-
- //Can't check stack because this function is called in the
- //beginning before main thread is initialized.
- //PJ_CHECK_STACK();
- rc = TlsSetValue(index, value);
- return rc!=0 ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(GetLastError());
-}
-
-/*
- * pj_thread_local_get()
- */
-PJ_DEF(void*) pj_thread_local_get(long index)
-{
- //Can't check stack because this function is called
- //by PJ_CHECK_STACK() itself!!!
- //PJ_CHECK_STACK();
- return TlsGetValue(index);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name)
-{
-
- PJ_CHECK_STACK();
-
-#if PJ_WIN32_WINNT >= 0x0400
- InitializeCriticalSection(&mutex->crit);
-#else
- mutex->hMutex = CreateMutex(NULL, FALSE, NULL);
- if (!mutex->hMutex) {
- return PJ_RETURN_OS_ERROR(GetLastError());
- }
-#endif
-
-#if PJ_DEBUG
- /* Set owner. */
- mutex->nesting_level = 0;
- mutex->owner = NULL;
-#endif
-
- /* Set name. */
- if (!name) {
- name = "mtx%p";
- }
- if (strchr(name, '%')) {
- pj_snprintf(mutex->obj_name, PJ_MAX_OBJ_NAME, name, mutex);
- } else {
- strncpy(mutex->obj_name, name, PJ_MAX_OBJ_NAME);
- mutex->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
- }
-
- PJ_LOG(6, (mutex->obj_name, "Mutex created"));
- return PJ_SUCCESS;
-}
-
-/*
- * pj_mutex_create()
- */
-PJ_DEF(pj_status_t) pj_mutex_create(pj_pool_t *pool,
- const char *name,
- int type,
- pj_mutex_t **mutex_ptr)
-{
- pj_status_t rc;
- pj_mutex_t *mutex;
-
- PJ_UNUSED_ARG(type);
- PJ_ASSERT_RETURN(pool && mutex_ptr, PJ_EINVAL);
-
- mutex = pj_pool_alloc(pool, sizeof(*mutex));
- if (!mutex)
- return PJ_ENOMEM;
-
- rc = init_mutex(mutex, name);
- if (rc != PJ_SUCCESS)
- return rc;
-
- *mutex_ptr = mutex;
-
- return PJ_SUCCESS;
-}
-
-/*
- * pj_mutex_create_simple()
- */
-PJ_DEF(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool,
- const char *name,
- pj_mutex_t **mutex )
-{
- return pj_mutex_create(pool, name, PJ_MUTEX_SIMPLE, mutex);
-}
-
-/*
- * pj_mutex_create_recursive()
- */
-PJ_DEF(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool,
- const char *name,
- pj_mutex_t **mutex )
-{
- return pj_mutex_create(pool, name, PJ_MUTEX_RECURSE, mutex);
-}
-
-/*
- * pj_mutex_lock()
- */
-PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex)
-{
- pj_status_t status;
-
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
-
- PJ_LOG(6,(mutex->obj_name, "Mutex: thread %s is waiting",
- pj_thread_this()->obj_name));
-
-#if PJ_WIN32_WINNT >= 0x0400
- EnterCriticalSection(&mutex->crit);
- status=PJ_SUCCESS;
-#else
- if (WaitForSingleObject(mutex->hMutex, INFINITE)==WAIT_OBJECT_0)
- status = PJ_SUCCESS;
- else
- status = PJ_STATUS_FROM_OS(GetLastError());
-
-#endif
- PJ_LOG(6,(mutex->obj_name,
- (status==PJ_SUCCESS ? "Mutex acquired by thread %s" : "FAILED by %s"),
- pj_thread_this()->obj_name));
-
-#if PJ_DEBUG
- if (status == PJ_SUCCESS) {
- mutex->owner = pj_thread_this();
- ++mutex->nesting_level;
- }
-#endif
-
- return status;
-}
-
-/*
- * pj_mutex_unlock()
- */
-PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex)
-{
- pj_status_t status;
-
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
-
-#if PJ_DEBUG
- pj_assert(mutex->owner == pj_thread_this());
- if (--mutex->nesting_level == 0) {
- mutex->owner = NULL;
- }
-#endif
-
- PJ_LOG(6,(mutex->obj_name, "Mutex released by thread %s",
- pj_thread_this()->obj_name));
-
-#if PJ_WIN32_WINNT >= 0x0400
- LeaveCriticalSection(&mutex->crit);
- status=PJ_SUCCESS;
-#else
- status = ReleaseMutex(mutex->hMutex) ? PJ_SUCCESS :
- PJ_STATUS_FROM_OS(GetLastError());
-#endif
- return status;
-}
-
-/*
- * pj_mutex_trylock()
- */
-PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex)
-{
- pj_status_t status;
-
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
-
-#if PJ_WIN32_WINNT >= 0x0400
- status=TryEnterCriticalSection(&mutex->crit) ? PJ_SUCCESS : PJ_EUNKNOWN;
-#else
- status = WaitForSingleObject(mutex->hMutex, 0)==WAIT_OBJECT_0 ?
- PJ_SUCCESS : PJ_ETIMEDOUT;
-#endif
- if (status==PJ_SUCCESS) {
- PJ_LOG(6,(mutex->obj_name, "Mutex acquired by thread %s",
- pj_thread_this()->obj_name));
-
-#if PJ_DEBUG
- mutex->owner = pj_thread_this();
- ++mutex->nesting_level;
-#endif
- }
- return status;
-}
-
-/*
- * pj_mutex_destroy()
- */
-PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex)
-{
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
-
- PJ_LOG(6,(mutex->obj_name, "Mutex destroyed"));
-
-#if PJ_WIN32_WINNT >= 0x0400
- DeleteCriticalSection(&mutex->crit);
- return PJ_SUCCESS;
-#else
- return CloseHandle(mutex->hMutex) ? PJ_SUCCESS :
- PJ_RETURN_OS_ERROR(GetLastError());
-#endif
-}
-
-#if PJ_DEBUG
-/*
- * pj_mutex_is_locked()
- */
-PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex)
-{
- return mutex->owner == pj_thread_this();
-}
-#endif
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * pj_enter_critical_section()
- */
-PJ_DEF(void) pj_enter_critical_section(void)
-{
- pj_mutex_lock(&critical_section_mutex);
-}
-
-
-/*
- * pj_leave_critical_section()
- */
-PJ_DEF(void) pj_leave_critical_section(void)
-{
- pj_mutex_unlock(&critical_section_mutex);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
-
-/*
- * pj_sem_create()
- */
-PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool,
- const char *name,
- unsigned initial,
- unsigned max,
- pj_sem_t **sem_ptr)
-{
- pj_sem_t *sem;
-
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(pool && sem_ptr, PJ_EINVAL);
-
- sem = pj_pool_alloc(pool, sizeof(*sem));
- sem->hSemaphore = CreateSemaphore(NULL, initial, max, NULL);
- if (!sem->hSemaphore)
- return PJ_RETURN_OS_ERROR(GetLastError());
-
- /* Set name. */
- if (!name) {
- name = "sem%p";
- }
- if (strchr(name, '%')) {
- pj_snprintf(sem->obj_name, PJ_MAX_OBJ_NAME, name, sem);
- } else {
- strncpy(sem->obj_name, name, PJ_MAX_OBJ_NAME);
- sem->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
- }
-
- PJ_LOG(6, (sem->obj_name, "Semaphore created"));
-
- *sem_ptr = sem;
- return PJ_SUCCESS;
-}
-
-static pj_status_t pj_sem_wait_for(pj_sem_t *sem, unsigned timeout)
-{
- DWORD result;
-
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(sem, PJ_EINVAL);
-
- PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s is waiting",
- pj_thread_this()->obj_name));
-
- result = WaitForSingleObject(sem->hSemaphore, timeout);
- if (result == WAIT_OBJECT_0) {
- PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s",
- pj_thread_this()->obj_name));
- } else {
- PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s FAILED to acquire",
- pj_thread_this()->obj_name));
- }
-
- if (result==WAIT_OBJECT_0)
- return PJ_SUCCESS;
- else if (result==WAIT_TIMEOUT)
- return PJ_ETIMEDOUT;
- else
- return PJ_RETURN_OS_ERROR(GetLastError());
-}
-
-/*
- * pj_sem_wait()
- */
-PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem)
-{
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(sem, PJ_EINVAL);
-
- return pj_sem_wait_for(sem, INFINITE);
-}
-
-/*
- * pj_sem_trywait()
- */
-PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem)
-{
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(sem, PJ_EINVAL);
-
- return pj_sem_wait_for(sem, 0);
-}
-
-/*
- * pj_sem_post()
- */
-PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem)
-{
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(sem, PJ_EINVAL);
-
- PJ_LOG(6, (sem->obj_name, "Semaphore released by thread %s",
- pj_thread_this()->obj_name));
-
- if (ReleaseSemaphore(sem->hSemaphore, 1, NULL))
- return PJ_SUCCESS;
- else
- return PJ_RETURN_OS_ERROR(GetLastError());
-}
-
-/*
- * pj_sem_destroy()
- */
-PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem)
-{
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(sem, PJ_EINVAL);
-
- PJ_LOG(6, (sem->obj_name, "Semaphore destroyed by thread %s",
- pj_thread_this()->obj_name));
-
- if (CloseHandle(sem->hSemaphore))
- return PJ_SUCCESS;
- else
- return PJ_RETURN_OS_ERROR(GetLastError());
-}
-
-#endif /* PJ_HAS_SEMAPHORE */
-///////////////////////////////////////////////////////////////////////////////
-
-
-#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0
-
-/*
- * pj_event_create()
- */
-PJ_DEF(pj_status_t) pj_event_create( pj_pool_t *pool,
- const char *name,
- pj_bool_t manual_reset,
- pj_bool_t initial,
- pj_event_t **event_ptr)
-{
- pj_event_t *event;
-
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(pool && event_ptr, PJ_EINVAL);
-
- event = pj_pool_alloc(pool, sizeof(*event));
- if (!event)
- return PJ_ENOMEM;
-
- event->hEvent = CreateEvent(NULL, manual_reset?TRUE:FALSE,
- initial?TRUE:FALSE, NULL);
-
- if (!event->hEvent)
- return PJ_RETURN_OS_ERROR(GetLastError());
-
- /* Set name. */
- if (!name) {
- name = "evt%p";
- }
- if (strchr(name, '%')) {
- pj_snprintf(event->obj_name, PJ_MAX_OBJ_NAME, name, event);
- } else {
- strncpy(event->obj_name, name, PJ_MAX_OBJ_NAME);
- event->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
- }
-
- PJ_LOG(6, (event->obj_name, "Event created"));
-
- *event_ptr = event;
- return PJ_SUCCESS;
-}
-
-static pj_status_t pj_event_wait_for(pj_event_t *event, unsigned timeout)
-{
- DWORD result;
-
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(event, PJ_EINVAL);
-
- PJ_LOG(6, (event->obj_name, "Event: thread %s is waiting",
- pj_thread_this()->obj_name));
-
- result = WaitForSingleObject(event->hEvent, timeout);
- if (result == WAIT_OBJECT_0) {
- PJ_LOG(6, (event->obj_name, "Event: thread %s is released",
- pj_thread_this()->obj_name));
- } else {
- PJ_LOG(6, (event->obj_name, "Event: thread %s FAILED to acquire",
- pj_thread_this()->obj_name));
- }
-
- if (result==WAIT_OBJECT_0)
- return PJ_SUCCESS;
- else if (result==WAIT_TIMEOUT)
- return PJ_ETIMEDOUT;
- else
- return PJ_RETURN_OS_ERROR(GetLastError());
-}
-
-/*
- * pj_event_wait()
- */
-PJ_DEF(pj_status_t) pj_event_wait(pj_event_t *event)
-{
- PJ_ASSERT_RETURN(event, PJ_EINVAL);
-
- return pj_event_wait_for(event, INFINITE);
-}
-
-/*
- * pj_event_trywait()
- */
-PJ_DEF(pj_status_t) pj_event_trywait(pj_event_t *event)
-{
- PJ_ASSERT_RETURN(event, PJ_EINVAL);
-
- return pj_event_wait_for(event, 0);
-}
-
-/*
- * pj_event_set()
- */
-PJ_DEF(pj_status_t) pj_event_set(pj_event_t *event)
-{
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(event, PJ_EINVAL);
-
- PJ_LOG(6, (event->obj_name, "Setting event"));
-
- if (SetEvent(event->hEvent))
- return PJ_SUCCESS;
- else
- return PJ_RETURN_OS_ERROR(GetLastError());
-}
-
-/*
- * pj_event_pulse()
- */
-PJ_DEF(pj_status_t) pj_event_pulse(pj_event_t *event)
-{
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(event, PJ_EINVAL);
-
- PJ_LOG(6, (event->obj_name, "Pulsing event"));
-
- if (PulseEvent(event->hEvent))
- return PJ_SUCCESS;
- else
- return PJ_RETURN_OS_ERROR(GetLastError());
-}
-
-/*
- * pj_event_reset()
- */
-PJ_DEF(pj_status_t) pj_event_reset(pj_event_t *event)
-{
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(event, PJ_EINVAL);
-
- PJ_LOG(6, (event->obj_name, "Event is reset"));
-
- if (ResetEvent(event->hEvent))
- return PJ_SUCCESS;
- else
- return PJ_RETURN_OS_ERROR(GetLastError());
-}
-
-/*
- * pj_event_destroy()
- */
-PJ_DEF(pj_status_t) pj_event_destroy(pj_event_t *event)
-{
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(event, PJ_EINVAL);
-
- PJ_LOG(6, (event->obj_name, "Event is destroying"));
-
- if (CloseHandle(event->hEvent))
- return PJ_SUCCESS;
- else
- return PJ_RETURN_OS_ERROR(GetLastError());
-}
-
-#endif /* PJ_HAS_EVENT_OBJ */
-
-///////////////////////////////////////////////////////////////////////////////
-#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0
-/*
- * Terminal color
- */
-
-static WORD pj_color_to_os_attr(pj_color_t color)
-{
- WORD attr = 0;
-
- if (color & PJ_TERM_COLOR_R)
- attr |= FOREGROUND_RED;
- if (color & PJ_TERM_COLOR_G)
- attr |= FOREGROUND_GREEN;
- if (color & PJ_TERM_COLOR_B)
- attr |= FOREGROUND_BLUE;
- if (color & PJ_TERM_COLOR_BRIGHT)
- attr |= FOREGROUND_INTENSITY;
-
- return attr;
-}
-
-static pj_color_t os_attr_to_pj_color(WORD attr)
-{
- int color = 0;
-
- if (attr & FOREGROUND_RED)
- color |= PJ_TERM_COLOR_R;
- if (attr & FOREGROUND_GREEN)
- color |= PJ_TERM_COLOR_G;
- if (attr & FOREGROUND_BLUE)
- color |= PJ_TERM_COLOR_B;
- if (attr & FOREGROUND_INTENSITY)
- color |= PJ_TERM_COLOR_BRIGHT;
-
- return color;
-}
-
-
-/*
- * pj_term_set_color()
- */
-PJ_DEF(pj_status_t) pj_term_set_color(pj_color_t color)
-{
- BOOL rc;
- WORD attr = 0;
-
- PJ_CHECK_STACK();
-
- attr = pj_color_to_os_attr(color);
- rc = SetConsoleTextAttribute( GetStdHandle(STD_OUTPUT_HANDLE), attr);
- return rc ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(GetLastError());
-}
-
-/*
- * pj_term_get_color()
- * Get current terminal foreground color.
- */
-PJ_DEF(pj_color_t) pj_term_get_color(void)
-{
- CONSOLE_SCREEN_BUFFER_INFO info;
-
- PJ_CHECK_STACK();
-
- GetConsoleScreenBufferInfo( GetStdHandle(STD_OUTPUT_HANDLE), &info);
- return os_attr_to_pj_color(info.wAttributes);
-}
-
-#endif /* PJ_TERM_HAS_COLOR */
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * pj_thread_local_alloc()
+ */
+PJ_DEF(pj_status_t) pj_thread_local_alloc(long *index)
+{
+ PJ_ASSERT_RETURN(index != NULL, PJ_EINVAL);
+
+ //Can't check stack because this function is called in the
+ //beginning before main thread is initialized.
+ //PJ_CHECK_STACK();
+
+ *index = TlsAlloc();
+
+ if (*index == TLS_OUT_OF_INDEXES)
+ return PJ_RETURN_OS_ERROR(GetLastError());
+ else
+ return PJ_SUCCESS;
+}
+
+/*
+ * pj_thread_local_free()
+ */
+PJ_DEF(void) pj_thread_local_free(long index)
+{
+ PJ_CHECK_STACK();
+ TlsFree(index);
+}
+
+/*
+ * pj_thread_local_set()
+ */
+PJ_DEF(pj_status_t) pj_thread_local_set(long index, void *value)
+{
+ BOOL rc;
+
+ //Can't check stack because this function is called in the
+ //beginning before main thread is initialized.
+ //PJ_CHECK_STACK();
+ rc = TlsSetValue(index, value);
+ return rc!=0 ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(GetLastError());
+}
+
+/*
+ * pj_thread_local_get()
+ */
+PJ_DEF(void*) pj_thread_local_get(long index)
+{
+ //Can't check stack because this function is called
+ //by PJ_CHECK_STACK() itself!!!
+ //PJ_CHECK_STACK();
+ return TlsGetValue(index);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name)
+{
+
+ PJ_CHECK_STACK();
+
+#if PJ_WIN32_WINNT >= 0x0400
+ InitializeCriticalSection(&mutex->crit);
+#else
+ mutex->hMutex = CreateMutex(NULL, FALSE, NULL);
+ if (!mutex->hMutex) {
+ return PJ_RETURN_OS_ERROR(GetLastError());
+ }
+#endif
+
+#if PJ_DEBUG
+ /* Set owner. */
+ mutex->nesting_level = 0;
+ mutex->owner = NULL;
+#endif
+
+ /* Set name. */
+ if (!name) {
+ name = "mtx%p";
+ }
+ if (strchr(name, '%')) {
+ pj_snprintf(mutex->obj_name, PJ_MAX_OBJ_NAME, name, mutex);
+ } else {
+ strncpy(mutex->obj_name, name, PJ_MAX_OBJ_NAME);
+ mutex->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
+ }
+
+ PJ_LOG(6, (mutex->obj_name, "Mutex created"));
+ return PJ_SUCCESS;
+}
+
+/*
+ * pj_mutex_create()
+ */
+PJ_DEF(pj_status_t) pj_mutex_create(pj_pool_t *pool,
+ const char *name,
+ int type,
+ pj_mutex_t **mutex_ptr)
+{
+ pj_status_t rc;
+ pj_mutex_t *mutex;
+
+ PJ_UNUSED_ARG(type);
+ PJ_ASSERT_RETURN(pool && mutex_ptr, PJ_EINVAL);
+
+ mutex = pj_pool_alloc(pool, sizeof(*mutex));
+ if (!mutex)
+ return PJ_ENOMEM;
+
+ rc = init_mutex(mutex, name);
+ if (rc != PJ_SUCCESS)
+ return rc;
+
+ *mutex_ptr = mutex;
+
+ return PJ_SUCCESS;
+}
+
+/*
+ * pj_mutex_create_simple()
+ */
+PJ_DEF(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool,
+ const char *name,
+ pj_mutex_t **mutex )
+{
+ return pj_mutex_create(pool, name, PJ_MUTEX_SIMPLE, mutex);
+}
+
+/*
+ * pj_mutex_create_recursive()
+ */
+PJ_DEF(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool,
+ const char *name,
+ pj_mutex_t **mutex )
+{
+ return pj_mutex_create(pool, name, PJ_MUTEX_RECURSE, mutex);
+}
+
+/*
+ * pj_mutex_lock()
+ */
+PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex)
+{
+ pj_status_t status;
+
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
+
+ PJ_LOG(6,(mutex->obj_name, "Mutex: thread %s is waiting",
+ pj_thread_this()->obj_name));
+
+#if PJ_WIN32_WINNT >= 0x0400
+ EnterCriticalSection(&mutex->crit);
+ status=PJ_SUCCESS;
+#else
+ if (WaitForSingleObject(mutex->hMutex, INFINITE)==WAIT_OBJECT_0)
+ status = PJ_SUCCESS;
+ else
+ status = PJ_STATUS_FROM_OS(GetLastError());
+
+#endif
+ PJ_LOG(6,(mutex->obj_name,
+ (status==PJ_SUCCESS ? "Mutex acquired by thread %s" : "FAILED by %s"),
+ pj_thread_this()->obj_name));
+
+#if PJ_DEBUG
+ if (status == PJ_SUCCESS) {
+ mutex->owner = pj_thread_this();
+ ++mutex->nesting_level;
+ }
+#endif
+
+ return status;
+}
+
+/*
+ * pj_mutex_unlock()
+ */
+PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex)
+{
+ pj_status_t status;
+
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
+
+#if PJ_DEBUG
+ pj_assert(mutex->owner == pj_thread_this());
+ if (--mutex->nesting_level == 0) {
+ mutex->owner = NULL;
+ }
+#endif
+
+ PJ_LOG(6,(mutex->obj_name, "Mutex released by thread %s",
+ pj_thread_this()->obj_name));
+
+#if PJ_WIN32_WINNT >= 0x0400
+ LeaveCriticalSection(&mutex->crit);
+ status=PJ_SUCCESS;
+#else
+ status = ReleaseMutex(mutex->hMutex) ? PJ_SUCCESS :
+ PJ_STATUS_FROM_OS(GetLastError());
+#endif
+ return status;
+}
+
+/*
+ * pj_mutex_trylock()
+ */
+PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex)
+{
+ pj_status_t status;
+
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
+
+#if PJ_WIN32_WINNT >= 0x0400
+ status=TryEnterCriticalSection(&mutex->crit) ? PJ_SUCCESS : PJ_EUNKNOWN;
+#else
+ status = WaitForSingleObject(mutex->hMutex, 0)==WAIT_OBJECT_0 ?
+ PJ_SUCCESS : PJ_ETIMEDOUT;
+#endif
+ if (status==PJ_SUCCESS) {
+ PJ_LOG(6,(mutex->obj_name, "Mutex acquired by thread %s",
+ pj_thread_this()->obj_name));
+
+#if PJ_DEBUG
+ mutex->owner = pj_thread_this();
+ ++mutex->nesting_level;
+#endif
+ }
+ return status;
+}
+
+/*
+ * pj_mutex_destroy()
+ */
+PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex)
+{
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
+
+ PJ_LOG(6,(mutex->obj_name, "Mutex destroyed"));
+
+#if PJ_WIN32_WINNT >= 0x0400
+ DeleteCriticalSection(&mutex->crit);
+ return PJ_SUCCESS;
+#else
+ return CloseHandle(mutex->hMutex) ? PJ_SUCCESS :
+ PJ_RETURN_OS_ERROR(GetLastError());
+#endif
+}
+
+#if PJ_DEBUG
+/*
+ * pj_mutex_is_locked()
+ */
+PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex)
+{
+ return mutex->owner == pj_thread_this();
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * pj_enter_critical_section()
+ */
+PJ_DEF(void) pj_enter_critical_section(void)
+{
+ pj_mutex_lock(&critical_section_mutex);
+}
+
+
+/*
+ * pj_leave_critical_section()
+ */
+PJ_DEF(void) pj_leave_critical_section(void)
+{
+ pj_mutex_unlock(&critical_section_mutex);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
+
+/*
+ * pj_sem_create()
+ */
+PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool,
+ const char *name,
+ unsigned initial,
+ unsigned max,
+ pj_sem_t **sem_ptr)
+{
+ pj_sem_t *sem;
+
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(pool && sem_ptr, PJ_EINVAL);
+
+ sem = pj_pool_alloc(pool, sizeof(*sem));
+ sem->hSemaphore = CreateSemaphore(NULL, initial, max, NULL);
+ if (!sem->hSemaphore)
+ return PJ_RETURN_OS_ERROR(GetLastError());
+
+ /* Set name. */
+ if (!name) {
+ name = "sem%p";
+ }
+ if (strchr(name, '%')) {
+ pj_snprintf(sem->obj_name, PJ_MAX_OBJ_NAME, name, sem);
+ } else {
+ strncpy(sem->obj_name, name, PJ_MAX_OBJ_NAME);
+ sem->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
+ }
+
+ PJ_LOG(6, (sem->obj_name, "Semaphore created"));
+
+ *sem_ptr = sem;
+ return PJ_SUCCESS;
+}
+
+static pj_status_t pj_sem_wait_for(pj_sem_t *sem, unsigned timeout)
+{
+ DWORD result;
+
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(sem, PJ_EINVAL);
+
+ PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s is waiting",
+ pj_thread_this()->obj_name));
+
+ result = WaitForSingleObject(sem->hSemaphore, timeout);
+ if (result == WAIT_OBJECT_0) {
+ PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s",
+ pj_thread_this()->obj_name));
+ } else {
+ PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s FAILED to acquire",
+ pj_thread_this()->obj_name));
+ }
+
+ if (result==WAIT_OBJECT_0)
+ return PJ_SUCCESS;
+ else if (result==WAIT_TIMEOUT)
+ return PJ_ETIMEDOUT;
+ else
+ return PJ_RETURN_OS_ERROR(GetLastError());
+}
+
+/*
+ * pj_sem_wait()
+ */
+PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem)
+{
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(sem, PJ_EINVAL);
+
+ return pj_sem_wait_for(sem, INFINITE);
+}
+
+/*
+ * pj_sem_trywait()
+ */
+PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem)
+{
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(sem, PJ_EINVAL);
+
+ return pj_sem_wait_for(sem, 0);
+}
+
+/*
+ * pj_sem_post()
+ */
+PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem)
+{
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(sem, PJ_EINVAL);
+
+ PJ_LOG(6, (sem->obj_name, "Semaphore released by thread %s",
+ pj_thread_this()->obj_name));
+
+ if (ReleaseSemaphore(sem->hSemaphore, 1, NULL))
+ return PJ_SUCCESS;
+ else
+ return PJ_RETURN_OS_ERROR(GetLastError());
+}
+
+/*
+ * pj_sem_destroy()
+ */
+PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem)
+{
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(sem, PJ_EINVAL);
+
+ PJ_LOG(6, (sem->obj_name, "Semaphore destroyed by thread %s",
+ pj_thread_this()->obj_name));
+
+ if (CloseHandle(sem->hSemaphore))
+ return PJ_SUCCESS;
+ else
+ return PJ_RETURN_OS_ERROR(GetLastError());
+}
+
+#endif /* PJ_HAS_SEMAPHORE */
+///////////////////////////////////////////////////////////////////////////////
+
+
+#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0
+
+/*
+ * pj_event_create()
+ */
+PJ_DEF(pj_status_t) pj_event_create( pj_pool_t *pool,
+ const char *name,
+ pj_bool_t manual_reset,
+ pj_bool_t initial,
+ pj_event_t **event_ptr)
+{
+ pj_event_t *event;
+
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(pool && event_ptr, PJ_EINVAL);
+
+ event = pj_pool_alloc(pool, sizeof(*event));
+ if (!event)
+ return PJ_ENOMEM;
+
+ event->hEvent = CreateEvent(NULL, manual_reset?TRUE:FALSE,
+ initial?TRUE:FALSE, NULL);
+
+ if (!event->hEvent)
+ return PJ_RETURN_OS_ERROR(GetLastError());
+
+ /* Set name. */
+ if (!name) {
+ name = "evt%p";
+ }
+ if (strchr(name, '%')) {
+ pj_snprintf(event->obj_name, PJ_MAX_OBJ_NAME, name, event);
+ } else {
+ strncpy(event->obj_name, name, PJ_MAX_OBJ_NAME);
+ event->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
+ }
+
+ PJ_LOG(6, (event->obj_name, "Event created"));
+
+ *event_ptr = event;
+ return PJ_SUCCESS;
+}
+
+static pj_status_t pj_event_wait_for(pj_event_t *event, unsigned timeout)
+{
+ DWORD result;
+
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(event, PJ_EINVAL);
+
+ PJ_LOG(6, (event->obj_name, "Event: thread %s is waiting",
+ pj_thread_this()->obj_name));
+
+ result = WaitForSingleObject(event->hEvent, timeout);
+ if (result == WAIT_OBJECT_0) {
+ PJ_LOG(6, (event->obj_name, "Event: thread %s is released",
+ pj_thread_this()->obj_name));
+ } else {
+ PJ_LOG(6, (event->obj_name, "Event: thread %s FAILED to acquire",
+ pj_thread_this()->obj_name));
+ }
+
+ if (result==WAIT_OBJECT_0)
+ return PJ_SUCCESS;
+ else if (result==WAIT_TIMEOUT)
+ return PJ_ETIMEDOUT;
+ else
+ return PJ_RETURN_OS_ERROR(GetLastError());
+}
+
+/*
+ * pj_event_wait()
+ */
+PJ_DEF(pj_status_t) pj_event_wait(pj_event_t *event)
+{
+ PJ_ASSERT_RETURN(event, PJ_EINVAL);
+
+ return pj_event_wait_for(event, INFINITE);
+}
+
+/*
+ * pj_event_trywait()
+ */
+PJ_DEF(pj_status_t) pj_event_trywait(pj_event_t *event)
+{
+ PJ_ASSERT_RETURN(event, PJ_EINVAL);
+
+ return pj_event_wait_for(event, 0);
+}
+
+/*
+ * pj_event_set()
+ */
+PJ_DEF(pj_status_t) pj_event_set(pj_event_t *event)
+{
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(event, PJ_EINVAL);
+
+ PJ_LOG(6, (event->obj_name, "Setting event"));
+
+ if (SetEvent(event->hEvent))
+ return PJ_SUCCESS;
+ else
+ return PJ_RETURN_OS_ERROR(GetLastError());
+}
+
+/*
+ * pj_event_pulse()
+ */
+PJ_DEF(pj_status_t) pj_event_pulse(pj_event_t *event)
+{
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(event, PJ_EINVAL);
+
+ PJ_LOG(6, (event->obj_name, "Pulsing event"));
+
+ if (PulseEvent(event->hEvent))
+ return PJ_SUCCESS;
+ else
+ return PJ_RETURN_OS_ERROR(GetLastError());
+}
+
+/*
+ * pj_event_reset()
+ */
+PJ_DEF(pj_status_t) pj_event_reset(pj_event_t *event)
+{
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(event, PJ_EINVAL);
+
+ PJ_LOG(6, (event->obj_name, "Event is reset"));
+
+ if (ResetEvent(event->hEvent))
+ return PJ_SUCCESS;
+ else
+ return PJ_RETURN_OS_ERROR(GetLastError());
+}
+
+/*
+ * pj_event_destroy()
+ */
+PJ_DEF(pj_status_t) pj_event_destroy(pj_event_t *event)
+{
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(event, PJ_EINVAL);
+
+ PJ_LOG(6, (event->obj_name, "Event is destroying"));
+
+ if (CloseHandle(event->hEvent))
+ return PJ_SUCCESS;
+ else
+ return PJ_RETURN_OS_ERROR(GetLastError());
+}
+
+#endif /* PJ_HAS_EVENT_OBJ */
+
+///////////////////////////////////////////////////////////////////////////////
+#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0
+/*
+ * Terminal color
+ */
+
+static WORD pj_color_to_os_attr(pj_color_t color)
+{
+ WORD attr = 0;
+
+ if (color & PJ_TERM_COLOR_R)
+ attr |= FOREGROUND_RED;
+ if (color & PJ_TERM_COLOR_G)
+ attr |= FOREGROUND_GREEN;
+ if (color & PJ_TERM_COLOR_B)
+ attr |= FOREGROUND_BLUE;
+ if (color & PJ_TERM_COLOR_BRIGHT)
+ attr |= FOREGROUND_INTENSITY;
+
+ return attr;
+}
+
+static pj_color_t os_attr_to_pj_color(WORD attr)
+{
+ int color = 0;
+
+ if (attr & FOREGROUND_RED)
+ color |= PJ_TERM_COLOR_R;
+ if (attr & FOREGROUND_GREEN)
+ color |= PJ_TERM_COLOR_G;
+ if (attr & FOREGROUND_BLUE)
+ color |= PJ_TERM_COLOR_B;
+ if (attr & FOREGROUND_INTENSITY)
+ color |= PJ_TERM_COLOR_BRIGHT;
+
+ return color;
+}
+
+
+/*
+ * pj_term_set_color()
+ */
+PJ_DEF(pj_status_t) pj_term_set_color(pj_color_t color)
+{
+ BOOL rc;
+ WORD attr = 0;
+
+ PJ_CHECK_STACK();
+
+ attr = pj_color_to_os_attr(color);
+ rc = SetConsoleTextAttribute( GetStdHandle(STD_OUTPUT_HANDLE), attr);
+ return rc ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(GetLastError());
+}
+
+/*
+ * pj_term_get_color()
+ * Get current terminal foreground color.
+ */
+PJ_DEF(pj_color_t) pj_term_get_color(void)
+{
+ CONSOLE_SCREEN_BUFFER_INFO info;
+
+ PJ_CHECK_STACK();
+
+ GetConsoleScreenBufferInfo( GetStdHandle(STD_OUTPUT_HANDLE), &info);
+ return os_attr_to_pj_color(info.wAttributes);
+}
+
+#endif /* PJ_TERM_HAS_COLOR */
diff --git a/pjlib/src/pj/os_error_linux_kernel.c b/pjlib/src/pj/os_error_linux_kernel.c
index cd5dfe7e..a6ecb1a5 100644
--- a/pjlib/src/pj/os_error_linux_kernel.c
+++ b/pjlib/src/pj/os_error_linux_kernel.c
@@ -1,65 +1,86 @@
-/* $Id$
- *
- */
-#include <pj/string.h>
-#include <pj/compat/errno.h>
-#include <linux/config.h>
-#include <linux/version.h>
-#if defined(MODVERSIONS)
-#include <linux/modversions.h>
-#endif
-#include <linux/kernel.h>
-#include <linux/errno.h>
-
-int kernel_errno;
-
-PJ_DEF(pj_status_t) pj_get_os_error(void)
-{
- return errno;
-}
-
-PJ_DEF(void) pj_set_os_error(pj_status_t code)
-{
- errno = code;
-}
-
-PJ_DEF(pj_status_t) pj_get_netos_error(void)
-{
- return errno;
-}
-
-PJ_DEF(void) pj_set_netos_error(pj_status_t code)
-{
- errno = code;
-}
-
-/*
- * platform_strerror()
- *
- * Platform specific error message. This file is called by pj_strerror()
- * in errno.c
- */
-int platform_strerror( pj_os_err_type os_errcode,
- char *buf, pj_size_t bufsize)
-{
- char errmsg[32];
- int len;
-
- /* Handle EINVAL as special case so that it'll pass errno test. */
- if (os_errcode==EINVAL)
- strcpy(errmsg, "Invalid value");
- else
- sprintf(errmsg, "errno=%d", os_errcode);
-
- len = strlen(errmsg);
-
- if (len >= bufsize)
- len = bufsize-1;
-
- pj_memcpy(buf, errmsg, len);
- buf[len] = '\0';
-
- return len;
-}
-
-
+/* $Id$
+ *
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/string.h>
+#include <pj/compat/errno.h>
+#include <linux/config.h>
+#include <linux/version.h>
+#if defined(MODVERSIONS)
+#include <linux/modversions.h>
+#endif
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+int kernel_errno;
+
+PJ_DEF(pj_status_t) pj_get_os_error(void)
+{
+ return errno;
+}
+
+PJ_DEF(void) pj_set_os_error(pj_status_t code)
+{
+ errno = code;
+}
+
+PJ_DEF(pj_status_t) pj_get_netos_error(void)
+{
+ return errno;
+}
+
+PJ_DEF(void) pj_set_netos_error(pj_status_t code)
+{
+ errno = code;
+}
+
+/*
+ * platform_strerror()
+ *
+ * Platform specific error message. This file is called by pj_strerror()
+ * in errno.c
+ */
+int platform_strerror( pj_os_err_type os_errcode,
+ char *buf, pj_size_t bufsize)
+{
+ char errmsg[32];
+ int len;
+
+ /* Handle EINVAL as special case so that it'll pass errno test. */
+ if (os_errcode==EINVAL)
+ strcpy(errmsg, "Invalid value");
+ else
+ sprintf(errmsg, "errno=%d", os_errcode);
+
+ len = strlen(errmsg);
+
+ if (len >= bufsize)
+ len = bufsize-1;
+
+ pj_memcpy(buf, errmsg, len);
+ buf[len] = '\0';
+
+ return len;
+}
+
+
diff --git a/pjlib/src/pj/os_error_unix.c b/pjlib/src/pj/os_error_unix.c
index acb1f807..fa902b60 100644
--- a/pjlib/src/pj/os_error_unix.c
+++ b/pjlib/src/pj/os_error_unix.c
@@ -1,54 +1,75 @@
-/* $Id$
- *
- */
-/*
- * $Log: /pjproject-0.3/pjlib/src/pj/os_error_unix.c $
- *
- * 1 10/14/05 12:19a Bennylp
- * Created.
- *
- */
-#include <pj/errno.h>
-#include <pj/string.h>
-#include <errno.h>
-
-PJ_DEF(pj_status_t) pj_get_os_error(void)
-{
- return PJ_STATUS_FROM_OS(errno);
-}
-
-PJ_DEF(void) pj_set_os_error(pj_status_t code)
-{
- errno = PJ_STATUS_TO_OS(code);
-}
-
-PJ_DEF(pj_status_t) pj_get_netos_error(void)
-{
- return PJ_STATUS_FROM_OS(errno);
-}
-
-PJ_DEF(void) pj_set_netos_error(pj_status_t code)
-{
- errno = PJ_STATUS_TO_OS(code);
-}
-
-/*
- * platform_strerror()
- *
- * Platform specific error message. This file is called by pj_strerror()
- * in errno.c
- */
-int platform_strerror( pj_os_err_type os_errcode,
- char *buf, pj_size_t bufsize)
-{
- const char *syserr = strerror(os_errcode);
- pj_size_t len = syserr ? strlen(syserr) : 0;
-
- if (len >= bufsize) len = bufsize - 1;
- if (len > 0)
- pj_memcpy(buf, syserr, len);
- buf[len] = '\0';
- return len;
-}
-
-
+/* $Id$
+ *
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*
+ * $Log: /pjproject-0.3/pjlib/src/pj/os_error_unix.c $
+ *
+ * 1 10/14/05 12:19a Bennylp
+ * Created.
+ *
+ */
+#include <pj/errno.h>
+#include <pj/string.h>
+#include <errno.h>
+
+PJ_DEF(pj_status_t) pj_get_os_error(void)
+{
+ return PJ_STATUS_FROM_OS(errno);
+}
+
+PJ_DEF(void) pj_set_os_error(pj_status_t code)
+{
+ errno = PJ_STATUS_TO_OS(code);
+}
+
+PJ_DEF(pj_status_t) pj_get_netos_error(void)
+{
+ return PJ_STATUS_FROM_OS(errno);
+}
+
+PJ_DEF(void) pj_set_netos_error(pj_status_t code)
+{
+ errno = PJ_STATUS_TO_OS(code);
+}
+
+/*
+ * platform_strerror()
+ *
+ * Platform specific error message. This file is called by pj_strerror()
+ * in errno.c
+ */
+int platform_strerror( pj_os_err_type os_errcode,
+ char *buf, pj_size_t bufsize)
+{
+ const char *syserr = strerror(os_errcode);
+ pj_size_t len = syserr ? strlen(syserr) : 0;
+
+ if (len >= bufsize) len = bufsize - 1;
+ if (len > 0)
+ pj_memcpy(buf, syserr, len);
+ buf[len] = '\0';
+ return len;
+}
+
+
diff --git a/pjlib/src/pj/os_error_win32.c b/pjlib/src/pj/os_error_win32.c
index 23da7cf8..8274467e 100644
--- a/pjlib/src/pj/os_error_win32.c
+++ b/pjlib/src/pj/os_error_win32.c
@@ -1,149 +1,170 @@
-/* $Id$
- */
-#include <pj/errno.h>
-#include <pj/assert.h>
-#include <pj/compat/stdarg.h>
-#include <pj/compat/sprintf.h>
-#include <pj/compat/vsprintf.h>
-#include <pj/string.h>
-
-
-#if defined(PJ_HAS_WINSOCK2_H) && PJ_HAS_WINSOCK2_H != 0
-# include <winsock2.h>
-#elif defined(PJ_HAS_WINSOCK_H) && PJ_HAS_WINSOCK_H != 0
-# include <winsock.h>
-#endif
-
-
-/*
- * From Apache's APR:
- */
-static const struct {
- pj_os_err_type code;
- const char *msg;
-} gaErrorList[] = {
- {WSAEINTR, "Interrupted system call"},
- {WSAEBADF, "Bad file number"},
- {WSAEACCES, "Permission denied"},
- {WSAEFAULT, "Bad address"},
- {WSAEINVAL, "Invalid argument"},
- {WSAEMFILE, "Too many open sockets"},
- {WSAEWOULDBLOCK, "Operation would block"},
- {WSAEINPROGRESS, "Operation now in progress"},
- {WSAEALREADY, "Operation already in progress"},
- {WSAENOTSOCK, "Socket operation on non-socket"},
- {WSAEDESTADDRREQ, "Destination address required"},
- {WSAEMSGSIZE, "Message too long"},
- {WSAEPROTOTYPE, "Protocol wrong type for socket"},
- {WSAENOPROTOOPT, "Bad protocol option"},
- {WSAEPROTONOSUPPORT, "Protocol not supported"},
- {WSAESOCKTNOSUPPORT, "Socket type not supported"},
- {WSAEOPNOTSUPP, "Operation not supported on socket"},
- {WSAEPFNOSUPPORT, "Protocol family not supported"},
- {WSAEAFNOSUPPORT, "Address family not supported"},
- {WSAEADDRINUSE, "Address already in use"},
- {WSAEADDRNOTAVAIL, "Can't assign requested address"},
- {WSAENETDOWN, "Network is down"},
- {WSAENETUNREACH, "Network is unreachable"},
- {WSAENETRESET, "Net connection reset"},
- {WSAECONNABORTED, "Software caused connection abort"},
- {WSAECONNRESET, "Connection reset by peer"},
- {WSAENOBUFS, "No buffer space available"},
- {WSAEISCONN, "Socket is already connected"},
- {WSAENOTCONN, "Socket is not connected"},
- {WSAESHUTDOWN, "Can't send after socket shutdown"},
- {WSAETOOMANYREFS, "Too many references, can't splice"},
- {WSAETIMEDOUT, "Connection timed out"},
- {WSAECONNREFUSED, "Connection refused"},
- {WSAELOOP, "Too many levels of symbolic links"},
- {WSAENAMETOOLONG, "File name too long"},
- {WSAEHOSTDOWN, "Host is down"},
- {WSAEHOSTUNREACH, "No route to host"},
- {WSAENOTEMPTY, "Directory not empty"},
- {WSAEPROCLIM, "Too many processes"},
- {WSAEUSERS, "Too many users"},
- {WSAEDQUOT, "Disc quota exceeded"},
- {WSAESTALE, "Stale NFS file handle"},
- {WSAEREMOTE, "Too many levels of remote in path"},
- {WSASYSNOTREADY, "Network system is unavailable"},
- {WSAVERNOTSUPPORTED, "Winsock version out of range"},
- {WSANOTINITIALISED, "WSAStartup not yet called"},
- {WSAEDISCON, "Graceful shutdown in progress"},
- {WSAHOST_NOT_FOUND, "Host not found"},
- {WSANO_DATA, "No host data of that type was found"},
- {0, NULL}
-};
-
-
-PJ_DEF(pj_status_t) pj_get_os_error(void)
-{
- return PJ_STATUS_FROM_OS(GetLastError());
-}
-
-PJ_DEF(void) pj_set_os_error(pj_status_t code)
-{
- SetLastError(PJ_STATUS_TO_OS(code));
-}
-
-PJ_DEF(pj_status_t) pj_get_netos_error(void)
-{
- return PJ_STATUS_FROM_OS(WSAGetLastError());
-}
-
-PJ_DEF(void) pj_set_netos_error(pj_status_t code)
-{
- WSASetLastError(PJ_STATUS_TO_OS(code));
-}
-
-/*
- * platform_strerror()
- *
- * Platform specific error message. This file is called by pj_strerror()
- * in errno.c
- */
-int platform_strerror( pj_os_err_type os_errcode,
- char *buf, pj_size_t bufsize)
-{
- int len;
-
- pj_assert(buf != NULL);
- pj_assert(bufsize >= 0);
-
- /*
- * MUST NOT check stack here.
- * This function might be called from PJ_CHECK_STACK() itself!
- //PJ_CHECK_STACK();
- */
-
- len = FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM
- | FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL,
- os_errcode,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPTSTR)buf,
- (DWORD)bufsize,
- NULL);
-
- if (!len) {
- int i;
- for (i = 0; gaErrorList[i].msg; ++i) {
- if (gaErrorList[i].code == os_errcode) {
- len = strlen(gaErrorList[i].msg);
- if ((pj_size_t)len >= bufsize) {
- len = bufsize-1;
- }
- pj_memcpy(buf, gaErrorList[i].msg, len);
- buf[len] = '\0';
- break;
- }
- }
- }
-
- if (!len) {
- len = snprintf( buf, bufsize, "Unknown native error %u", (unsigned)os_errcode);
- buf[len] = '\0';
- }
-
- return len;
-}
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/errno.h>
+#include <pj/assert.h>
+#include <pj/compat/stdarg.h>
+#include <pj/compat/sprintf.h>
+#include <pj/compat/vsprintf.h>
+#include <pj/string.h>
+
+
+#if defined(PJ_HAS_WINSOCK2_H) && PJ_HAS_WINSOCK2_H != 0
+# include <winsock2.h>
+#elif defined(PJ_HAS_WINSOCK_H) && PJ_HAS_WINSOCK_H != 0
+# include <winsock.h>
+#endif
+
+
+/*
+ * From Apache's APR:
+ */
+static const struct {
+ pj_os_err_type code;
+ const char *msg;
+} gaErrorList[] = {
+ {WSAEINTR, "Interrupted system call"},
+ {WSAEBADF, "Bad file number"},
+ {WSAEACCES, "Permission denied"},
+ {WSAEFAULT, "Bad address"},
+ {WSAEINVAL, "Invalid argument"},
+ {WSAEMFILE, "Too many open sockets"},
+ {WSAEWOULDBLOCK, "Operation would block"},
+ {WSAEINPROGRESS, "Operation now in progress"},
+ {WSAEALREADY, "Operation already in progress"},
+ {WSAENOTSOCK, "Socket operation on non-socket"},
+ {WSAEDESTADDRREQ, "Destination address required"},
+ {WSAEMSGSIZE, "Message too long"},
+ {WSAEPROTOTYPE, "Protocol wrong type for socket"},
+ {WSAENOPROTOOPT, "Bad protocol option"},
+ {WSAEPROTONOSUPPORT, "Protocol not supported"},
+ {WSAESOCKTNOSUPPORT, "Socket type not supported"},
+ {WSAEOPNOTSUPP, "Operation not supported on socket"},
+ {WSAEPFNOSUPPORT, "Protocol family not supported"},
+ {WSAEAFNOSUPPORT, "Address family not supported"},
+ {WSAEADDRINUSE, "Address already in use"},
+ {WSAEADDRNOTAVAIL, "Can't assign requested address"},
+ {WSAENETDOWN, "Network is down"},
+ {WSAENETUNREACH, "Network is unreachable"},
+ {WSAENETRESET, "Net connection reset"},
+ {WSAECONNABORTED, "Software caused connection abort"},
+ {WSAECONNRESET, "Connection reset by peer"},
+ {WSAENOBUFS, "No buffer space available"},
+ {WSAEISCONN, "Socket is already connected"},
+ {WSAENOTCONN, "Socket is not connected"},
+ {WSAESHUTDOWN, "Can't send after socket shutdown"},
+ {WSAETOOMANYREFS, "Too many references, can't splice"},
+ {WSAETIMEDOUT, "Connection timed out"},
+ {WSAECONNREFUSED, "Connection refused"},
+ {WSAELOOP, "Too many levels of symbolic links"},
+ {WSAENAMETOOLONG, "File name too long"},
+ {WSAEHOSTDOWN, "Host is down"},
+ {WSAEHOSTUNREACH, "No route to host"},
+ {WSAENOTEMPTY, "Directory not empty"},
+ {WSAEPROCLIM, "Too many processes"},
+ {WSAEUSERS, "Too many users"},
+ {WSAEDQUOT, "Disc quota exceeded"},
+ {WSAESTALE, "Stale NFS file handle"},
+ {WSAEREMOTE, "Too many levels of remote in path"},
+ {WSASYSNOTREADY, "Network system is unavailable"},
+ {WSAVERNOTSUPPORTED, "Winsock version out of range"},
+ {WSANOTINITIALISED, "WSAStartup not yet called"},
+ {WSAEDISCON, "Graceful shutdown in progress"},
+ {WSAHOST_NOT_FOUND, "Host not found"},
+ {WSANO_DATA, "No host data of that type was found"},
+ {0, NULL}
+};
+
+
+PJ_DEF(pj_status_t) pj_get_os_error(void)
+{
+ return PJ_STATUS_FROM_OS(GetLastError());
+}
+
+PJ_DEF(void) pj_set_os_error(pj_status_t code)
+{
+ SetLastError(PJ_STATUS_TO_OS(code));
+}
+
+PJ_DEF(pj_status_t) pj_get_netos_error(void)
+{
+ return PJ_STATUS_FROM_OS(WSAGetLastError());
+}
+
+PJ_DEF(void) pj_set_netos_error(pj_status_t code)
+{
+ WSASetLastError(PJ_STATUS_TO_OS(code));
+}
+
+/*
+ * platform_strerror()
+ *
+ * Platform specific error message. This file is called by pj_strerror()
+ * in errno.c
+ */
+int platform_strerror( pj_os_err_type os_errcode,
+ char *buf, pj_size_t bufsize)
+{
+ int len;
+
+ pj_assert(buf != NULL);
+ pj_assert(bufsize >= 0);
+
+ /*
+ * MUST NOT check stack here.
+ * This function might be called from PJ_CHECK_STACK() itself!
+ //PJ_CHECK_STACK();
+ */
+
+ len = FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM
+ | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ os_errcode,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR)buf,
+ (DWORD)bufsize,
+ NULL);
+
+ if (!len) {
+ int i;
+ for (i = 0; gaErrorList[i].msg; ++i) {
+ if (gaErrorList[i].code == os_errcode) {
+ len = strlen(gaErrorList[i].msg);
+ if ((pj_size_t)len >= bufsize) {
+ len = bufsize-1;
+ }
+ pj_memcpy(buf, gaErrorList[i].msg, len);
+ buf[len] = '\0';
+ break;
+ }
+ }
+ }
+
+ if (!len) {
+ len = snprintf( buf, bufsize, "Unknown native error %u", (unsigned)os_errcode);
+ buf[len] = '\0';
+ }
+
+ return len;
+}
+
diff --git a/pjlib/src/pj/os_time_ansi.c b/pjlib/src/pj/os_time_ansi.c
index 20fc7f68..f4fd4865 100644
--- a/pjlib/src/pj/os_time_ansi.c
+++ b/pjlib/src/pj/os_time_ansi.c
@@ -1,56 +1,77 @@
-/* $Id$
- */
-#include <pj/os.h>
-#include <pj/compat/time.h>
-
-///////////////////////////////////////////////////////////////////////////////
-
-PJ_DEF(pj_status_t) pj_gettimeofday(pj_time_val *tv)
-{
- struct timeb tb;
-
- PJ_CHECK_STACK();
-
- ftime(&tb);
- tv->sec = tb.time;
- tv->msec = tb.millitm;
- return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_time_decode(const pj_time_val *tv, pj_parsed_time *pt)
-{
- struct tm *local_time;
-
- PJ_CHECK_STACK();
-
- local_time = localtime((time_t*)&tv->sec);
-
- pt->year = local_time->tm_year+1900;
- pt->mon = local_time->tm_mon;
- pt->day = local_time->tm_mday;
- pt->hour = local_time->tm_hour;
- pt->min = local_time->tm_min;
- pt->sec = local_time->tm_sec;
- pt->wday = local_time->tm_wday;
- pt->yday = local_time->tm_yday;
- pt->msec = tv->msec;
-
- return PJ_SUCCESS;
-}
-
-/**
- * Encode parsed time to time value.
- */
-PJ_DEF(pj_status_t) pj_time_encode(const pj_parsed_time *pt, pj_time_val *tv);
-
-/**
- * Convert local time to GMT.
- */
-PJ_DEF(pj_status_t) pj_time_local_to_gmt(pj_time_val *tv);
-
-/**
- * Convert GMT to local time.
- */
-PJ_DEF(pj_status_t) pj_time_gmt_to_local(pj_time_val *tv);
-
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/os.h>
+#include <pj/compat/time.h>
+
+///////////////////////////////////////////////////////////////////////////////
+
+PJ_DEF(pj_status_t) pj_gettimeofday(pj_time_val *tv)
+{
+ struct timeb tb;
+
+ PJ_CHECK_STACK();
+
+ ftime(&tb);
+ tv->sec = tb.time;
+ tv->msec = tb.millitm;
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_time_decode(const pj_time_val *tv, pj_parsed_time *pt)
+{
+ struct tm *local_time;
+
+ PJ_CHECK_STACK();
+
+ local_time = localtime((time_t*)&tv->sec);
+
+ pt->year = local_time->tm_year+1900;
+ pt->mon = local_time->tm_mon;
+ pt->day = local_time->tm_mday;
+ pt->hour = local_time->tm_hour;
+ pt->min = local_time->tm_min;
+ pt->sec = local_time->tm_sec;
+ pt->wday = local_time->tm_wday;
+ pt->yday = local_time->tm_yday;
+ pt->msec = tv->msec;
+
+ return PJ_SUCCESS;
+}
+
+/**
+ * Encode parsed time to time value.
+ */
+PJ_DEF(pj_status_t) pj_time_encode(const pj_parsed_time *pt, pj_time_val *tv);
+
+/**
+ * Convert local time to GMT.
+ */
+PJ_DEF(pj_status_t) pj_time_local_to_gmt(pj_time_val *tv);
+
+/**
+ * Convert GMT to local time.
+ */
+PJ_DEF(pj_status_t) pj_time_gmt_to_local(pj_time_val *tv);
+
+
diff --git a/pjlib/src/pj/os_time_linux_kernel.c b/pjlib/src/pj/os_time_linux_kernel.c
index 03c0cc26..d9d5ed8a 100644
--- a/pjlib/src/pj/os_time_linux_kernel.c
+++ b/pjlib/src/pj/os_time_linux_kernel.c
@@ -1,60 +1,81 @@
-/* $Id$
- *
- */
-/* $Log: /pjproject-0.3/pjlib/src/pj/os_time_linux_kernel.c $
- *
- * 2 10/14/05 12:26a Bennylp
- * Finished error code framework, some fixes in ioqueue, etc. Pretty
- * major.
- *
- * 1 9/22/05 10:39a Bennylp
- * Created.
- *
- */
-#include <pj/os.h>
-#include <linux/time.h>
-
-///////////////////////////////////////////////////////////////////////////////
-
-PJ_DEF(pj_status_t) pj_gettimeofday(pj_time_val *tv)
-{
- struct timeval tval;
-
- do_gettimeofday(&tval);
- tv->sec = tval.tv_sec;
- tv->msec = tval.tv_usec / 1000;
-
- return 0;
-}
-
-PJ_DEF(pj_status_t) pj_time_decode(const pj_time_val *tv, pj_parsed_time *pt)
-{
- pt->year = 2005;
- pt->mon = 8;
- pt->day = 20;
- pt->hour = 16;
- pt->min = 30;
- pt->sec = 30;
- pt->wday = 3;
- pt->yday = 200;
- pt->msec = 777;
-
- return -1;
-}
-
-/**
- * Encode parsed time to time value.
- */
-PJ_DEF(pj_status_t) pj_time_encode(const pj_parsed_time *pt, pj_time_val *tv);
-
-/**
- * Convert local time to GMT.
- */
-PJ_DEF(pj_status_t) pj_time_local_to_gmt(pj_time_val *tv);
-
-/**
- * Convert GMT to local time.
- */
-PJ_DEF(pj_status_t) pj_time_gmt_to_local(pj_time_val *tv);
-
-
+/* $Id$
+ *
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/* $Log: /pjproject-0.3/pjlib/src/pj/os_time_linux_kernel.c $
+ *
+ * 2 10/14/05 12:26a Bennylp
+ * Finished error code framework, some fixes in ioqueue, etc. Pretty
+ * major.
+ *
+ * 1 9/22/05 10:39a Bennylp
+ * Created.
+ *
+ */
+#include <pj/os.h>
+#include <linux/time.h>
+
+///////////////////////////////////////////////////////////////////////////////
+
+PJ_DEF(pj_status_t) pj_gettimeofday(pj_time_val *tv)
+{
+ struct timeval tval;
+
+ do_gettimeofday(&tval);
+ tv->sec = tval.tv_sec;
+ tv->msec = tval.tv_usec / 1000;
+
+ return 0;
+}
+
+PJ_DEF(pj_status_t) pj_time_decode(const pj_time_val *tv, pj_parsed_time *pt)
+{
+ pt->year = 2005;
+ pt->mon = 8;
+ pt->day = 20;
+ pt->hour = 16;
+ pt->min = 30;
+ pt->sec = 30;
+ pt->wday = 3;
+ pt->yday = 200;
+ pt->msec = 777;
+
+ return -1;
+}
+
+/**
+ * Encode parsed time to time value.
+ */
+PJ_DEF(pj_status_t) pj_time_encode(const pj_parsed_time *pt, pj_time_val *tv);
+
+/**
+ * Convert local time to GMT.
+ */
+PJ_DEF(pj_status_t) pj_time_local_to_gmt(pj_time_val *tv);
+
+/**
+ * Convert GMT to local time.
+ */
+PJ_DEF(pj_status_t) pj_time_gmt_to_local(pj_time_val *tv);
+
+
diff --git a/pjlib/src/pj/os_timestamp_common.c b/pjlib/src/pj/os_timestamp_common.c
index f9824d59..ddba4cf9 100644
--- a/pjlib/src/pj/os_timestamp_common.c
+++ b/pjlib/src/pj/os_timestamp_common.c
@@ -1,119 +1,140 @@
-/* $Id$
- */
-#include <pj/os.h>
-#include <pj/compat/high_precision.h>
-
-#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0
-
-#define U32MAX (0xFFFFFFFFUL)
-#define NANOSEC (1000000000UL)
-#define USEC (1000000UL)
-#define MSEC (1000)
-
-static pj_highprec_t get_elapsed( const pj_timestamp *start,
- const pj_timestamp *stop )
-{
- pj_highprec_t elapsed_hi, elapsed_lo;
-
- elapsed_hi = stop->u32.hi - start->u32.hi;
- elapsed_lo = stop->u32.lo - start->u32.lo;
-
- /* elapsed_hi = elapsed_hi * U32MAX */
- pj_highprec_mul(elapsed_hi, U32MAX);
-
- return elapsed_hi + elapsed_lo;
-}
-
-static pj_highprec_t elapsed_usec( const pj_timestamp *start,
- const pj_timestamp *stop )
-{
- pj_timestamp ts_freq;
- pj_highprec_t freq, elapsed;
-
- if (pj_get_timestamp_freq(&ts_freq) != PJ_SUCCESS)
- return 0;
-
- /* Convert frequency timestamp */
- freq = ts_freq.u32.hi;
- pj_highprec_mul(freq, U32MAX);
- freq += ts_freq.u32.lo;
-
- /* Avoid division by zero. */
- if (freq == 0) freq = 1;
-
- /* Get elapsed time in cycles. */
- elapsed = get_elapsed(start, stop);
-
- /* usec = elapsed * USEC / freq */
- pj_highprec_mul(elapsed, USEC);
- pj_highprec_div(elapsed, freq);
-
- return elapsed;
-}
-
-PJ_DEF(pj_uint32_t) pj_elapsed_nanosec( const pj_timestamp *start,
- const pj_timestamp *stop )
-{
- pj_timestamp ts_freq;
- pj_highprec_t freq, elapsed;
-
- if (pj_get_timestamp_freq(&ts_freq) != PJ_SUCCESS)
- return 0;
-
- /* Convert frequency timestamp */
- freq = ts_freq.u32.hi;
- pj_highprec_mul(freq, U32MAX);
- freq += ts_freq.u32.lo;
-
- /* Avoid division by zero. */
- if (freq == 0) freq = 1;
-
- /* Get elapsed time in cycles. */
- elapsed = get_elapsed(start, stop);
-
- /* usec = elapsed * USEC / freq */
- pj_highprec_mul(elapsed, NANOSEC);
- pj_highprec_div(elapsed, freq);
-
- return (pj_uint32_t)elapsed;
-}
-
-PJ_DEF(pj_uint32_t) pj_elapsed_usec( const pj_timestamp *start,
- const pj_timestamp *stop )
-{
- return (pj_uint32_t)elapsed_usec(start, stop);
-}
-
-PJ_DEF(pj_time_val) pj_elapsed_time( const pj_timestamp *start,
- const pj_timestamp *stop )
-{
- pj_highprec_t elapsed = elapsed_usec(start, stop);
- pj_time_val tv_elapsed;
-
- if (PJ_HIGHPREC_VALUE_IS_ZERO(elapsed)) {
- tv_elapsed.sec = tv_elapsed.msec = 0;
- return tv_elapsed;
- } else {
- pj_highprec_t sec, msec;
-
- sec = elapsed;
- pj_highprec_div(sec, USEC);
- tv_elapsed.sec = (long)sec;
-
- msec = elapsed;
- pj_highprec_mod(msec, USEC);
- pj_highprec_div(msec, 1000);
- tv_elapsed.msec = (long)msec;
-
- return tv_elapsed;
- }
-}
-
-PJ_DEF(pj_uint32_t) pj_elapsed_cycle( const pj_timestamp *start,
- const pj_timestamp *stop )
-{
- return stop->u32.lo - start->u32.lo;
-}
-
-#endif /* PJ_HAS_HIGH_RES_TIMER */
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/os.h>
+#include <pj/compat/high_precision.h>
+
+#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0
+
+#define U32MAX (0xFFFFFFFFUL)
+#define NANOSEC (1000000000UL)
+#define USEC (1000000UL)
+#define MSEC (1000)
+
+static pj_highprec_t get_elapsed( const pj_timestamp *start,
+ const pj_timestamp *stop )
+{
+ pj_highprec_t elapsed_hi, elapsed_lo;
+
+ elapsed_hi = stop->u32.hi - start->u32.hi;
+ elapsed_lo = stop->u32.lo - start->u32.lo;
+
+ /* elapsed_hi = elapsed_hi * U32MAX */
+ pj_highprec_mul(elapsed_hi, U32MAX);
+
+ return elapsed_hi + elapsed_lo;
+}
+
+static pj_highprec_t elapsed_usec( const pj_timestamp *start,
+ const pj_timestamp *stop )
+{
+ pj_timestamp ts_freq;
+ pj_highprec_t freq, elapsed;
+
+ if (pj_get_timestamp_freq(&ts_freq) != PJ_SUCCESS)
+ return 0;
+
+ /* Convert frequency timestamp */
+ freq = ts_freq.u32.hi;
+ pj_highprec_mul(freq, U32MAX);
+ freq += ts_freq.u32.lo;
+
+ /* Avoid division by zero. */
+ if (freq == 0) freq = 1;
+
+ /* Get elapsed time in cycles. */
+ elapsed = get_elapsed(start, stop);
+
+ /* usec = elapsed * USEC / freq */
+ pj_highprec_mul(elapsed, USEC);
+ pj_highprec_div(elapsed, freq);
+
+ return elapsed;
+}
+
+PJ_DEF(pj_uint32_t) pj_elapsed_nanosec( const pj_timestamp *start,
+ const pj_timestamp *stop )
+{
+ pj_timestamp ts_freq;
+ pj_highprec_t freq, elapsed;
+
+ if (pj_get_timestamp_freq(&ts_freq) != PJ_SUCCESS)
+ return 0;
+
+ /* Convert frequency timestamp */
+ freq = ts_freq.u32.hi;
+ pj_highprec_mul(freq, U32MAX);
+ freq += ts_freq.u32.lo;
+
+ /* Avoid division by zero. */
+ if (freq == 0) freq = 1;
+
+ /* Get elapsed time in cycles. */
+ elapsed = get_elapsed(start, stop);
+
+ /* usec = elapsed * USEC / freq */
+ pj_highprec_mul(elapsed, NANOSEC);
+ pj_highprec_div(elapsed, freq);
+
+ return (pj_uint32_t)elapsed;
+}
+
+PJ_DEF(pj_uint32_t) pj_elapsed_usec( const pj_timestamp *start,
+ const pj_timestamp *stop )
+{
+ return (pj_uint32_t)elapsed_usec(start, stop);
+}
+
+PJ_DEF(pj_time_val) pj_elapsed_time( const pj_timestamp *start,
+ const pj_timestamp *stop )
+{
+ pj_highprec_t elapsed = elapsed_usec(start, stop);
+ pj_time_val tv_elapsed;
+
+ if (PJ_HIGHPREC_VALUE_IS_ZERO(elapsed)) {
+ tv_elapsed.sec = tv_elapsed.msec = 0;
+ return tv_elapsed;
+ } else {
+ pj_highprec_t sec, msec;
+
+ sec = elapsed;
+ pj_highprec_div(sec, USEC);
+ tv_elapsed.sec = (long)sec;
+
+ msec = elapsed;
+ pj_highprec_mod(msec, USEC);
+ pj_highprec_div(msec, 1000);
+ tv_elapsed.msec = (long)msec;
+
+ return tv_elapsed;
+ }
+}
+
+PJ_DEF(pj_uint32_t) pj_elapsed_cycle( const pj_timestamp *start,
+ const pj_timestamp *stop )
+{
+ return stop->u32.lo - start->u32.lo;
+}
+
+#endif /* PJ_HAS_HIGH_RES_TIMER */
+
diff --git a/pjlib/src/pj/os_timestamp_linux.c b/pjlib/src/pj/os_timestamp_linux.c
index ada9076a..15921f97 100644
--- a/pjlib/src/pj/os_timestamp_linux.c
+++ b/pjlib/src/pj/os_timestamp_linux.c
@@ -1,124 +1,145 @@
-/* $Id$
- *
- */
-#include <pj/os.h>
-#include <pj/errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-
-#if defined(PJ_HAS_PENTIUM) && PJ_HAS_PENTIUM!=0
-static int machine_speed_mhz;
-static pj_timestamp machine_speed;
-
-static __inline__ unsigned long long int rdtsc()
-{
- unsigned long long int x;
- __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
- return x;
-}
-
-/* Determine machine's CPU MHz to get the counter's frequency.
- */
-static int get_machine_speed_mhz()
-{
- FILE *strm;
- char buf[512];
- int len;
- char *pos, *end;
-
- PJ_CHECK_STACK();
-
- /* Open /proc/cpuinfo and read the file */
- strm = fopen("/proc/cpuinfo", "r");
- if (!strm)
- return -1;
- len = fread(buf, 1, sizeof(buf), strm);
- fclose(strm);
- if (len < 1) {
- return -1;
- }
- buf[len] = '\0';
-
- /* Locate the MHz digit. */
- pos = strstr(buf, "cpu MHz");
- if (!pos)
- return -1;
- pos = strchr(pos, ':');
- if (!pos)
- return -1;
- end = (pos += 2);
- while (isdigit(*end)) ++end;
- *end = '\0';
-
- /* Return the Mhz part, and give it a +1. */
- return atoi(pos)+1;
-}
-
-PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
-{
- if (machine_speed_mhz == 0) {
- machine_speed_mhz = get_machine_speed_mhz();
- if (machine_speed_mhz > 0) {
- machine_speed.u64 = machine_speed_mhz * 1000000.0;
- }
- }
-
- if (machine_speed_mhz == -1) {
- ts->u64 = 0;
- return -1;
- }
- ts->u64 = rdtsc();
- return 0;
-}
-
-PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
-{
- if (machine_speed_mhz == 0) {
- machine_speed_mhz = get_machine_speed_mhz();
- if (machine_speed_mhz > 0) {
- machine_speed.u64 = machine_speed_mhz * 1000000.0;
- }
- }
-
- if (machine_speed_mhz == -1) {
- freq->u64 = 1; /* return 1 to prevent division by zero in apps. */
- return -1;
- }
-
- freq->u64 = machine_speed.u64;
- return 0;
-}
-
-#else
-#include <sys/time.h>
-#include <errno.h>
-
-#define USEC_PER_SEC 1000000
-
-PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
-{
- struct timeval tv;
-
- if (gettimeofday(&tv, NULL) != 0) {
- return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
- }
-
- ts->u64 = tv.tv_sec;
- ts->u64 *= USEC_PER_SEC;
- ts->u64 += tv.tv_usec;
-
- return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
-{
- freq->u32.hi = 0;
- freq->u32.lo = USEC_PER_SEC;
-
- return PJ_SUCCESS;
-}
-
-#endif
-
+/* $Id$
+ *
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/os.h>
+#include <pj/errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#if defined(PJ_HAS_PENTIUM) && PJ_HAS_PENTIUM!=0
+static int machine_speed_mhz;
+static pj_timestamp machine_speed;
+
+static __inline__ unsigned long long int rdtsc()
+{
+ unsigned long long int x;
+ __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
+ return x;
+}
+
+/* Determine machine's CPU MHz to get the counter's frequency.
+ */
+static int get_machine_speed_mhz()
+{
+ FILE *strm;
+ char buf[512];
+ int len;
+ char *pos, *end;
+
+ PJ_CHECK_STACK();
+
+ /* Open /proc/cpuinfo and read the file */
+ strm = fopen("/proc/cpuinfo", "r");
+ if (!strm)
+ return -1;
+ len = fread(buf, 1, sizeof(buf), strm);
+ fclose(strm);
+ if (len < 1) {
+ return -1;
+ }
+ buf[len] = '\0';
+
+ /* Locate the MHz digit. */
+ pos = strstr(buf, "cpu MHz");
+ if (!pos)
+ return -1;
+ pos = strchr(pos, ':');
+ if (!pos)
+ return -1;
+ end = (pos += 2);
+ while (isdigit(*end)) ++end;
+ *end = '\0';
+
+ /* Return the Mhz part, and give it a +1. */
+ return atoi(pos)+1;
+}
+
+PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
+{
+ if (machine_speed_mhz == 0) {
+ machine_speed_mhz = get_machine_speed_mhz();
+ if (machine_speed_mhz > 0) {
+ machine_speed.u64 = machine_speed_mhz * 1000000.0;
+ }
+ }
+
+ if (machine_speed_mhz == -1) {
+ ts->u64 = 0;
+ return -1;
+ }
+ ts->u64 = rdtsc();
+ return 0;
+}
+
+PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
+{
+ if (machine_speed_mhz == 0) {
+ machine_speed_mhz = get_machine_speed_mhz();
+ if (machine_speed_mhz > 0) {
+ machine_speed.u64 = machine_speed_mhz * 1000000.0;
+ }
+ }
+
+ if (machine_speed_mhz == -1) {
+ freq->u64 = 1; /* return 1 to prevent division by zero in apps. */
+ return -1;
+ }
+
+ freq->u64 = machine_speed.u64;
+ return 0;
+}
+
+#else
+#include <sys/time.h>
+#include <errno.h>
+
+#define USEC_PER_SEC 1000000
+
+PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
+{
+ struct timeval tv;
+
+ if (gettimeofday(&tv, NULL) != 0) {
+ return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
+ }
+
+ ts->u64 = tv.tv_sec;
+ ts->u64 *= USEC_PER_SEC;
+ ts->u64 += tv.tv_usec;
+
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
+{
+ freq->u32.hi = 0;
+ freq->u32.lo = USEC_PER_SEC;
+
+ return PJ_SUCCESS;
+}
+
+#endif
+
diff --git a/pjlib/src/pj/os_timestamp_linux_kernel.c b/pjlib/src/pj/os_timestamp_linux_kernel.c
index d70bcfd7..0b75c765 100644
--- a/pjlib/src/pj/os_timestamp_linux_kernel.c
+++ b/pjlib/src/pj/os_timestamp_linux_kernel.c
@@ -1,63 +1,84 @@
-/* $Id$
- *
- */
-#include <pj/os.h>
-#include <linux/time.h>
-
-#if 0
-PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
-{
- ts->u32.hi = 0;
- ts->u32.lo = jiffies;
- return 0;
-}
-
-PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
-{
- freq->u32.hi = 0;
- freq->u32.lo = HZ;
- return 0;
-}
-#elif 0
-PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
-{
- struct timespec tv;
-
- tv = CURRENT_TIME;
-
- ts->u64 = tv.tv_sec;
- ts->u64 *= NSEC_PER_SEC;
- ts->u64 += tv.tv_nsec;
-
- return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
-{
- freq->u32.hi = 0;
- freq->u32.lo = NSEC_PER_SEC;
- return 0;
-}
-#else
-PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
-{
- struct timeval tv;
-
- do_gettimeofday(&tv);
-
- ts->u64 = tv.tv_sec;
- ts->u64 *= USEC_PER_SEC;
- ts->u64 += tv.tv_usec;
-
- return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
-{
- freq->u32.hi = 0;
- freq->u32.lo = USEC_PER_SEC;
- return 0;
-}
-
-#endif
-
+/* $Id$
+ *
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/os.h>
+#include <linux/time.h>
+
+#if 0
+PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
+{
+ ts->u32.hi = 0;
+ ts->u32.lo = jiffies;
+ return 0;
+}
+
+PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
+{
+ freq->u32.hi = 0;
+ freq->u32.lo = HZ;
+ return 0;
+}
+#elif 0
+PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
+{
+ struct timespec tv;
+
+ tv = CURRENT_TIME;
+
+ ts->u64 = tv.tv_sec;
+ ts->u64 *= NSEC_PER_SEC;
+ ts->u64 += tv.tv_nsec;
+
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
+{
+ freq->u32.hi = 0;
+ freq->u32.lo = NSEC_PER_SEC;
+ return 0;
+}
+#else
+PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
+{
+ struct timeval tv;
+
+ do_gettimeofday(&tv);
+
+ ts->u64 = tv.tv_sec;
+ ts->u64 *= USEC_PER_SEC;
+ ts->u64 += tv.tv_usec;
+
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
+{
+ freq->u32.hi = 0;
+ freq->u32.lo = USEC_PER_SEC;
+ return 0;
+}
+
+#endif
+
diff --git a/pjlib/src/pj/os_timestamp_win32.c b/pjlib/src/pj/os_timestamp_win32.c
index 1cfd81d8..1626ca62 100644
--- a/pjlib/src/pj/os_timestamp_win32.c
+++ b/pjlib/src/pj/os_timestamp_win32.c
@@ -1,28 +1,49 @@
-/* $Id$
- */
-#include <pj/os.h>
-#include <pj/errno.h>
-#include <windows.h>
-
-PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
-{
- LARGE_INTEGER val;
-
- if (!QueryPerformanceCounter(&val))
- return PJ_RETURN_OS_ERROR(GetLastError());
-
- ts->u64 = val.QuadPart;
- return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
-{
- LARGE_INTEGER val;
-
- if (!QueryPerformanceFrequency(&val))
- return PJ_RETURN_OS_ERROR(GetLastError());
-
- freq->u64 = val.QuadPart;
- return PJ_SUCCESS;
-}
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/os.h>
+#include <pj/errno.h>
+#include <windows.h>
+
+PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
+{
+ LARGE_INTEGER val;
+
+ if (!QueryPerformanceCounter(&val))
+ return PJ_RETURN_OS_ERROR(GetLastError());
+
+ ts->u64 = val.QuadPart;
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
+{
+ LARGE_INTEGER val;
+
+ if (!QueryPerformanceFrequency(&val))
+ return PJ_RETURN_OS_ERROR(GetLastError());
+
+ freq->u64 = val.QuadPart;
+ return PJ_SUCCESS;
+}
+
diff --git a/pjlib/src/pj/pool.c b/pjlib/src/pj/pool.c
index 5561612b..c5a31923 100644
--- a/pjlib/src/pj/pool.c
+++ b/pjlib/src/pj/pool.c
@@ -1,256 +1,277 @@
-/* $Id$
- */
-#include <pj/pool.h>
-#include <pj/log.h>
-#include <pj/except.h>
-#include <pj/assert.h>
-#include <pj/os.h>
-#include <pj/compat/sprintf.h>
-
-/* Include inline definitions when inlining is disabled. */
-#if !PJ_FUNCTIONS_ARE_INLINED
-# include <pj/pool_i.h>
-#endif
-
-#define LOG(expr) PJ_LOG(5,expr)
-
-int PJ_NO_MEMORY_EXCEPTION;
-
-/*
- * Create new block.
- * Create a new big chunk of memory block, from which user allocation will be
- * taken from.
- */
-static pj_pool_block *pj_pool_create_block( pj_pool_t *pool, pj_size_t size)
-{
- pj_pool_block *block;
-
- PJ_CHECK_STACK();
- pj_assert(size >= sizeof(pj_pool_block));
-
- LOG((pool->obj_name, "create_block(sz=%u), cur.cap=%u, cur.used=%u",
- size, pool->capacity, pool->used_size));
-
- /* Request memory from allocator. */
- block = (pj_pool_block*)
- (*pool->factory->policy.block_alloc)(pool->factory, size);
- if (block == NULL) {
- (*pool->callback)(pool, size);
- return NULL;
- }
-
- /* Add capacity. */
- pool->capacity += size;
- pool->used_size += sizeof(pj_pool_block);
-
- /* Set block attribytes. */
- block->cur = block->buf = ((unsigned char*)block) + sizeof(pj_pool_block);
- block->end = ((unsigned char*)block) + size;
-
- /* Insert in the front of the list. */
- pj_list_insert_after(&pool->block_list, block);
-
- LOG((pool->obj_name," block created, buffer=%p-%p",block->buf, block->end));
-
- return block;
-}
-
-/*
- * Allocate memory chunk for user from available blocks.
- * This will iterate through block list to find space to allocate the chunk.
- * If no space is available in all the blocks, a new block might be created
- * (depending on whether the pool is allowed to resize).
- */
-PJ_DEF(void*) pj_pool_allocate_find(pj_pool_t *pool, unsigned size)
-{
- pj_pool_block *block = pool->block_list.next;
- void *p;
- unsigned block_size;
-
- PJ_CHECK_STACK();
-
- while (block != &pool->block_list) {
- p = pj_pool_alloc_from_block(pool, block, size);
- if (p != NULL)
- return p;
- block = block->next;
- }
- /* No available space in all blocks. */
-
- /* If pool is configured NOT to expand, return error. */
- if (pool->increment_size == 0) {
- LOG((pool->obj_name, "Can't expand pool to allocate %u bytes "
- "(used=%u, cap=%u)",
- size, pool->used_size, pool->capacity));
- (*pool->callback)(pool, size);
- return NULL;
- }
-
- /* If pool is configured to expand, but the increment size
- * is less than the required size, expand the pool by multiple
- * increment size
- */
- if (pool->increment_size < size + sizeof(pj_pool_block)) {
- unsigned count;
- count = (size + pool->increment_size + sizeof(pj_pool_block)) /
- pool->increment_size;
- block_size = count * pool->increment_size;
-
- } else {
- block_size = pool->increment_size;
- }
-
- LOG((pool->obj_name,
- "%u bytes requested, resizing pool by %u bytes (used=%u, cap=%u)",
- size, block_size, pool->used_size, pool->capacity));
-
- block = pj_pool_create_block(pool, block_size);
- if (!block)
- return NULL;
-
- p = pj_pool_alloc_from_block(pool, block, size);
- pj_assert(p != NULL);
-#if PJ_DEBUG
- if (p == NULL) {
- p = p;
- }
-#endif
- return p;
-}
-
-/*
- * Internal function to initialize pool.
- */
-PJ_DEF(void) pj_pool_init_int( pj_pool_t *pool,
- const char *name,
- pj_size_t increment_size,
- pj_pool_callback *callback)
-{
- pj_pool_block *block;
-
- PJ_CHECK_STACK();
-
- pool->increment_size = increment_size;
- pool->callback = callback;
- pool->used_size = sizeof(*pool);
- block = pool->block_list.next;
- while (block != &pool->block_list) {
- pool->used_size += sizeof(pj_pool_block);
- block = block->next;
- }
-
- if (name) {
- if (strchr(name, '%') != NULL) {
- sprintf(pool->obj_name, name, pool);
- } else {
- strncpy(pool->obj_name, name, PJ_MAX_OBJ_NAME);
- }
- } else {
- pool->obj_name[0] = '\0';
- }
-}
-
-/*
- * Create new memory pool.
- */
-PJ_DEF(pj_pool_t*) pj_pool_create_int( pj_pool_factory *f, const char *name,
- pj_size_t initial_size,
- pj_size_t increment_size,
- pj_pool_callback *callback)
-{
- pj_pool_t *pool;
- pj_pool_block *block;
- unsigned char *buffer;
-
- PJ_CHECK_STACK();
-
- buffer = (*f->policy.block_alloc)(f, initial_size);
- if (!buffer)
- return NULL;
-
- /* Set pool administrative data. */
- pool = (pj_pool_t*)buffer;
- pj_memset(pool, 0, sizeof(*pool));
-
- pj_list_init(&pool->block_list);
- pool->factory = f;
-
- /* Create the first block from the memory. */
- block = (pj_pool_block*) (buffer + sizeof(*pool));
- block->cur = block->buf = ((unsigned char*)block) + sizeof(pj_pool_block);
- block->end = buffer + initial_size;
- pj_list_insert_after(&pool->block_list, block);
-
- pj_pool_init_int(pool, name, increment_size, callback);
-
- /* Pool initial capacity and used size */
- pool->capacity = initial_size;
-
- LOG((pool->obj_name, "pool created, size=%u", pool->capacity));
- return pool;
-}
-
-/*
- * Reset the pool to the state when it was created.
- * All blocks will be deallocated except the first block. All memory areas
- * are marked as free.
- */
-static void reset_pool(pj_pool_t *pool)
-{
- pj_pool_block *block;
-
- PJ_CHECK_STACK();
-
- block = pool->block_list.prev;
- if (block == &pool->block_list)
- return;
-
- /* Skip the first block because it is occupying the same memory
- as the pool itself.
- */
- block = block->prev;
-
- while (block != &pool->block_list) {
- pj_pool_block *prev = block->prev;
- pj_list_erase(block);
- (*pool->factory->policy.block_free)(pool->factory, block,
- block->end - (unsigned char*)block);
- block = prev;
- }
-
- block = pool->block_list.next;
- block->cur = block->buf;
- pool->capacity = block->end - (unsigned char*)pool;
- pool->used_size = 0;
-}
-
-/*
- * The public function to reset pool.
- */
-PJ_DEF(void) pj_pool_reset(pj_pool_t *pool)
-{
- LOG((pool->obj_name, "reset(): cap=%d, used=%d(%d%%)",
- pool->capacity, pool->used_size, pool->used_size*100/pool->capacity));
-
- reset_pool(pool);
-}
-
-/*
- * Destroy the pool.
- */
-PJ_DEF(void) pj_pool_destroy_int(pj_pool_t *pool)
-{
- pj_size_t initial_size;
-
- LOG((pool->obj_name, "destroy(): cap=%d, used=%d(%d%%), block0=%p-%p",
- pool->capacity, pool->used_size, pool->used_size*100/pool->capacity,
- ((pj_pool_block*)pool->block_list.next)->buf,
- ((pj_pool_block*)pool->block_list.next)->end));
-
- reset_pool(pool);
- initial_size = ((pj_pool_block*)pool->block_list.next)->end -
- (unsigned char*)pool;
- (*pool->factory->policy.block_free)(pool->factory, pool, initial_size);
-}
-
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/pool.h>
+#include <pj/log.h>
+#include <pj/except.h>
+#include <pj/assert.h>
+#include <pj/os.h>
+#include <pj/compat/sprintf.h>
+
+/* Include inline definitions when inlining is disabled. */
+#if !PJ_FUNCTIONS_ARE_INLINED
+# include <pj/pool_i.h>
+#endif
+
+#define LOG(expr) PJ_LOG(5,expr)
+
+int PJ_NO_MEMORY_EXCEPTION;
+
+/*
+ * Create new block.
+ * Create a new big chunk of memory block, from which user allocation will be
+ * taken from.
+ */
+static pj_pool_block *pj_pool_create_block( pj_pool_t *pool, pj_size_t size)
+{
+ pj_pool_block *block;
+
+ PJ_CHECK_STACK();
+ pj_assert(size >= sizeof(pj_pool_block));
+
+ LOG((pool->obj_name, "create_block(sz=%u), cur.cap=%u, cur.used=%u",
+ size, pool->capacity, pool->used_size));
+
+ /* Request memory from allocator. */
+ block = (pj_pool_block*)
+ (*pool->factory->policy.block_alloc)(pool->factory, size);
+ if (block == NULL) {
+ (*pool->callback)(pool, size);
+ return NULL;
+ }
+
+ /* Add capacity. */
+ pool->capacity += size;
+ pool->used_size += sizeof(pj_pool_block);
+
+ /* Set block attribytes. */
+ block->cur = block->buf = ((unsigned char*)block) + sizeof(pj_pool_block);
+ block->end = ((unsigned char*)block) + size;
+
+ /* Insert in the front of the list. */
+ pj_list_insert_after(&pool->block_list, block);
+
+ LOG((pool->obj_name," block created, buffer=%p-%p",block->buf, block->end));
+
+ return block;
+}
+
+/*
+ * Allocate memory chunk for user from available blocks.
+ * This will iterate through block list to find space to allocate the chunk.
+ * If no space is available in all the blocks, a new block might be created
+ * (depending on whether the pool is allowed to resize).
+ */
+PJ_DEF(void*) pj_pool_allocate_find(pj_pool_t *pool, unsigned size)
+{
+ pj_pool_block *block = pool->block_list.next;
+ void *p;
+ unsigned block_size;
+
+ PJ_CHECK_STACK();
+
+ while (block != &pool->block_list) {
+ p = pj_pool_alloc_from_block(pool, block, size);
+ if (p != NULL)
+ return p;
+ block = block->next;
+ }
+ /* No available space in all blocks. */
+
+ /* If pool is configured NOT to expand, return error. */
+ if (pool->increment_size == 0) {
+ LOG((pool->obj_name, "Can't expand pool to allocate %u bytes "
+ "(used=%u, cap=%u)",
+ size, pool->used_size, pool->capacity));
+ (*pool->callback)(pool, size);
+ return NULL;
+ }
+
+ /* If pool is configured to expand, but the increment size
+ * is less than the required size, expand the pool by multiple
+ * increment size
+ */
+ if (pool->increment_size < size + sizeof(pj_pool_block)) {
+ unsigned count;
+ count = (size + pool->increment_size + sizeof(pj_pool_block)) /
+ pool->increment_size;
+ block_size = count * pool->increment_size;
+
+ } else {
+ block_size = pool->increment_size;
+ }
+
+ LOG((pool->obj_name,
+ "%u bytes requested, resizing pool by %u bytes (used=%u, cap=%u)",
+ size, block_size, pool->used_size, pool->capacity));
+
+ block = pj_pool_create_block(pool, block_size);
+ if (!block)
+ return NULL;
+
+ p = pj_pool_alloc_from_block(pool, block, size);
+ pj_assert(p != NULL);
+#if PJ_DEBUG
+ if (p == NULL) {
+ p = p;
+ }
+#endif
+ return p;
+}
+
+/*
+ * Internal function to initialize pool.
+ */
+PJ_DEF(void) pj_pool_init_int( pj_pool_t *pool,
+ const char *name,
+ pj_size_t increment_size,
+ pj_pool_callback *callback)
+{
+ pj_pool_block *block;
+
+ PJ_CHECK_STACK();
+
+ pool->increment_size = increment_size;
+ pool->callback = callback;
+ pool->used_size = sizeof(*pool);
+ block = pool->block_list.next;
+ while (block != &pool->block_list) {
+ pool->used_size += sizeof(pj_pool_block);
+ block = block->next;
+ }
+
+ if (name) {
+ if (strchr(name, '%') != NULL) {
+ sprintf(pool->obj_name, name, pool);
+ } else {
+ strncpy(pool->obj_name, name, PJ_MAX_OBJ_NAME);
+ }
+ } else {
+ pool->obj_name[0] = '\0';
+ }
+}
+
+/*
+ * Create new memory pool.
+ */
+PJ_DEF(pj_pool_t*) pj_pool_create_int( pj_pool_factory *f, const char *name,
+ pj_size_t initial_size,
+ pj_size_t increment_size,
+ pj_pool_callback *callback)
+{
+ pj_pool_t *pool;
+ pj_pool_block *block;
+ unsigned char *buffer;
+
+ PJ_CHECK_STACK();
+
+ buffer = (*f->policy.block_alloc)(f, initial_size);
+ if (!buffer)
+ return NULL;
+
+ /* Set pool administrative data. */
+ pool = (pj_pool_t*)buffer;
+ pj_memset(pool, 0, sizeof(*pool));
+
+ pj_list_init(&pool->block_list);
+ pool->factory = f;
+
+ /* Create the first block from the memory. */
+ block = (pj_pool_block*) (buffer + sizeof(*pool));
+ block->cur = block->buf = ((unsigned char*)block) + sizeof(pj_pool_block);
+ block->end = buffer + initial_size;
+ pj_list_insert_after(&pool->block_list, block);
+
+ pj_pool_init_int(pool, name, increment_size, callback);
+
+ /* Pool initial capacity and used size */
+ pool->capacity = initial_size;
+
+ LOG((pool->obj_name, "pool created, size=%u", pool->capacity));
+ return pool;
+}
+
+/*
+ * Reset the pool to the state when it was created.
+ * All blocks will be deallocated except the first block. All memory areas
+ * are marked as free.
+ */
+static void reset_pool(pj_pool_t *pool)
+{
+ pj_pool_block *block;
+
+ PJ_CHECK_STACK();
+
+ block = pool->block_list.prev;
+ if (block == &pool->block_list)
+ return;
+
+ /* Skip the first block because it is occupying the same memory
+ as the pool itself.
+ */
+ block = block->prev;
+
+ while (block != &pool->block_list) {
+ pj_pool_block *prev = block->prev;
+ pj_list_erase(block);
+ (*pool->factory->policy.block_free)(pool->factory, block,
+ block->end - (unsigned char*)block);
+ block = prev;
+ }
+
+ block = pool->block_list.next;
+ block->cur = block->buf;
+ pool->capacity = block->end - (unsigned char*)pool;
+ pool->used_size = 0;
+}
+
+/*
+ * The public function to reset pool.
+ */
+PJ_DEF(void) pj_pool_reset(pj_pool_t *pool)
+{
+ LOG((pool->obj_name, "reset(): cap=%d, used=%d(%d%%)",
+ pool->capacity, pool->used_size, pool->used_size*100/pool->capacity));
+
+ reset_pool(pool);
+}
+
+/*
+ * Destroy the pool.
+ */
+PJ_DEF(void) pj_pool_destroy_int(pj_pool_t *pool)
+{
+ pj_size_t initial_size;
+
+ LOG((pool->obj_name, "destroy(): cap=%d, used=%d(%d%%), block0=%p-%p",
+ pool->capacity, pool->used_size, pool->used_size*100/pool->capacity,
+ ((pj_pool_block*)pool->block_list.next)->buf,
+ ((pj_pool_block*)pool->block_list.next)->end));
+
+ reset_pool(pool);
+ initial_size = ((pj_pool_block*)pool->block_list.next)->end -
+ (unsigned char*)pool;
+ (*pool->factory->policy.block_free)(pool->factory, pool, initial_size);
+}
+
+
diff --git a/pjlib/src/pj/pool_caching.c b/pjlib/src/pj/pool_caching.c
index d59ed28c..20c55dd2 100644
--- a/pjlib/src/pj/pool_caching.c
+++ b/pjlib/src/pj/pool_caching.c
@@ -1,205 +1,226 @@
-/* $Id$
- */
-#include <pj/pool.h>
-#include <pj/log.h>
-#include <pj/string.h>
-#include <pj/assert.h>
-#include <pj/os.h>
-
-static pj_pool_t* cpool_create_pool(pj_pool_factory *pf,
- const char *name,
- pj_size_t initial_size,
- pj_size_t increment_sz,
- pj_pool_callback *callback);
-static void cpool_release_pool(pj_pool_factory *pf, pj_pool_t *pool);
-static void cpool_dump_status(pj_pool_factory *factory, pj_bool_t detail );
-
-static pj_size_t pool_sizes[PJ_CACHING_POOL_ARRAY_SIZE] =
-{
- 256, 512, 1024, 2048, 4096, 8192, 12288, 16384,
- 20480, 24576, 28672, 32768, 40960, 49152, 57344, 65536
-};
-
-
-PJ_DEF(void) pj_caching_pool_init( pj_caching_pool *cp,
- const pj_pool_factory_policy *policy,
- pj_size_t max_capacity)
-{
- int i;
-
- PJ_CHECK_STACK();
-
- pj_memset(cp, 0, sizeof(*cp));
-
- cp->max_capacity = max_capacity;
- pj_list_init(&cp->used_list);
- for (i=0; i<PJ_CACHING_POOL_ARRAY_SIZE; ++i)
- pj_list_init(&cp->free_list[i]);
-
- pj_memcpy(&cp->factory.policy, policy, sizeof(pj_pool_factory_policy));
- cp->factory.create_pool = &cpool_create_pool;
- cp->factory.release_pool = &cpool_release_pool;
- cp->factory.dump_status = &cpool_dump_status;
-}
-
-PJ_DEF(void) pj_caching_pool_destroy( pj_caching_pool *cp )
-{
- int i;
- pj_pool_t *pool;
-
- PJ_CHECK_STACK();
-
- /* Delete all pool in free list */
- for (i=0; i < PJ_CACHING_POOL_ARRAY_SIZE; ++i) {
- pj_pool_t *pool = cp->free_list[i].next;
- pj_pool_t *next;
- for (; pool != (void*)&cp->free_list[i]; pool = next) {
- next = pool->next;
- pj_list_erase(pool);
- pj_pool_destroy_int(pool);
- }
- }
-
- /* Delete all pools in used list */
- pool = cp->used_list.next;
- while (pool != (pj_pool_t*) &cp->used_list) {
- pj_pool_t *next = pool->next;
- pj_list_erase(pool);
- pj_pool_destroy_int(pool);
- pool = next;
- }
-}
-
-static pj_pool_t* cpool_create_pool(pj_pool_factory *pf,
- const char *name,
- pj_size_t initial_size,
- pj_size_t increment_sz,
- pj_pool_callback *callback)
-{
- pj_caching_pool *cp = (pj_caching_pool*)pf;
- pj_pool_t *pool;
- int idx;
-
- PJ_CHECK_STACK();
-
- /* Use pool factory's policy when callback is NULL */
- if (callback == NULL) {
- callback = pf->policy.callback;
- }
-
- /* Search the suitable size for the pool.
- * We'll just do linear search to the size array, as the array size itself
- * is only a few elements. Binary search I suspect will be less efficient
- * for this purpose.
- */
- for (idx=0;
- idx < PJ_CACHING_POOL_ARRAY_SIZE && pool_sizes[idx] < initial_size;
- ++idx)
- ;
-
- /* Check whether there's a pool in the list. */
- if (idx==PJ_CACHING_POOL_ARRAY_SIZE || pj_list_empty(&cp->free_list[idx])) {
- /* No pool is available. */
- /* Set minimum size. */
- if (idx < PJ_CACHING_POOL_ARRAY_SIZE)
- initial_size = pool_sizes[idx];
-
- /* Create new pool */
- pool = pj_pool_create_int(&cp->factory, name, initial_size,
- increment_sz, callback);
- if (!pool)
- return NULL;
-
- } else {
- /* Get one pool from the list. */
- pool = cp->free_list[idx].next;
- pj_list_erase(pool);
-
- /* Initialize the pool. */
- pj_pool_init_int(pool, name, increment_sz, callback);
-
- /* Update pool manager's free capacity. */
- cp->capacity -= pj_pool_get_capacity(pool);
-
- PJ_LOG(5, (pool->obj_name, "pool reused, size=%u", pool->capacity));
- }
-
- /* Put in used list. */
- pj_list_insert_before( &cp->used_list, pool );
-
- /* Increment used count. */
- ++cp->used_count;
- return pool;
-}
-
-static void cpool_release_pool( pj_pool_factory *pf, pj_pool_t *pool)
-{
- pj_caching_pool *cp = (pj_caching_pool*)pf;
- int i;
-
- PJ_CHECK_STACK();
-
- /* Erase from the used list. */
- pj_list_erase(pool);
-
- /* Decrement used count. */
- --cp->used_count;
-
- /* Destroy the pool if the size is greater than our size or if the total
- * capacity in our recycle list (plus the size of the pool) exceeds
- * maximum capacity.
- . */
- if (pool->capacity > pool_sizes[PJ_CACHING_POOL_ARRAY_SIZE-1] ||
- cp->capacity + pool->capacity > cp->max_capacity)
- {
- pj_pool_destroy_int(pool);
- return;
- }
-
- /* Reset pool. */
- PJ_LOG(4, (pool->obj_name, "recycle(): cap=%d, used=%d(%d%%)",
- pool->capacity, pool->used_size, pool->used_size*100/pool->capacity));
- pj_pool_reset(pool);
-
- /*
- * Otherwise put the pool in our recycle list.
- */
- for (i=0; i < PJ_CACHING_POOL_ARRAY_SIZE && pool_sizes[i] != pool->capacity; ++i)
- ;
-
- pj_assert( i != PJ_CACHING_POOL_ARRAY_SIZE );
- if (i == PJ_CACHING_POOL_ARRAY_SIZE) {
- /* Something has gone wrong with the pool. */
- pj_pool_destroy_int(pool);
- return;
- }
-
- pj_list_insert_after(&cp->free_list[i], pool);
- cp->capacity += pool->capacity;
-}
-
-static void cpool_dump_status(pj_pool_factory *factory, pj_bool_t detail )
-{
-#if PJ_LOG_MAX_LEVEL >= 3
- pj_caching_pool *cp = (pj_caching_pool*)factory;
- PJ_LOG(3,("cachpool", " Dumping caching pool:"));
- PJ_LOG(3,("cachpool", " Capacity=%u, max_capacity=%u, used_cnt=%u", \
- cp->capacity, cp->max_capacity, cp->used_count));
- if (detail) {
- pj_pool_t *pool = cp->used_list.next;
- pj_uint32_t total_used = 0, total_capacity = 0;
- PJ_LOG(3,("cachpool", " Dumping all active pools:"));
- while (pool != (void*)&cp->used_list) {
- PJ_LOG(3,("cachpool", " %12s: %8d of %8d (%d%%) used", pool->obj_name,
- pool->used_size, pool->capacity,
- pool->used_size*100/pool->capacity));
- total_used += pool->used_size;
- total_capacity += pool->capacity;
- pool = pool->next;
- }
- PJ_LOG(3,("cachpool", " Total %9d of %9d (%d %%) used!",
- total_used, total_capacity,
- total_used * 100 / total_capacity));
- }
-#endif
-}
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/pool.h>
+#include <pj/log.h>
+#include <pj/string.h>
+#include <pj/assert.h>
+#include <pj/os.h>
+
+static pj_pool_t* cpool_create_pool(pj_pool_factory *pf,
+ const char *name,
+ pj_size_t initial_size,
+ pj_size_t increment_sz,
+ pj_pool_callback *callback);
+static void cpool_release_pool(pj_pool_factory *pf, pj_pool_t *pool);
+static void cpool_dump_status(pj_pool_factory *factory, pj_bool_t detail );
+
+static pj_size_t pool_sizes[PJ_CACHING_POOL_ARRAY_SIZE] =
+{
+ 256, 512, 1024, 2048, 4096, 8192, 12288, 16384,
+ 20480, 24576, 28672, 32768, 40960, 49152, 57344, 65536
+};
+
+
+PJ_DEF(void) pj_caching_pool_init( pj_caching_pool *cp,
+ const pj_pool_factory_policy *policy,
+ pj_size_t max_capacity)
+{
+ int i;
+
+ PJ_CHECK_STACK();
+
+ pj_memset(cp, 0, sizeof(*cp));
+
+ cp->max_capacity = max_capacity;
+ pj_list_init(&cp->used_list);
+ for (i=0; i<PJ_CACHING_POOL_ARRAY_SIZE; ++i)
+ pj_list_init(&cp->free_list[i]);
+
+ pj_memcpy(&cp->factory.policy, policy, sizeof(pj_pool_factory_policy));
+ cp->factory.create_pool = &cpool_create_pool;
+ cp->factory.release_pool = &cpool_release_pool;
+ cp->factory.dump_status = &cpool_dump_status;
+}
+
+PJ_DEF(void) pj_caching_pool_destroy( pj_caching_pool *cp )
+{
+ int i;
+ pj_pool_t *pool;
+
+ PJ_CHECK_STACK();
+
+ /* Delete all pool in free list */
+ for (i=0; i < PJ_CACHING_POOL_ARRAY_SIZE; ++i) {
+ pj_pool_t *pool = cp->free_list[i].next;
+ pj_pool_t *next;
+ for (; pool != (void*)&cp->free_list[i]; pool = next) {
+ next = pool->next;
+ pj_list_erase(pool);
+ pj_pool_destroy_int(pool);
+ }
+ }
+
+ /* Delete all pools in used list */
+ pool = cp->used_list.next;
+ while (pool != (pj_pool_t*) &cp->used_list) {
+ pj_pool_t *next = pool->next;
+ pj_list_erase(pool);
+ pj_pool_destroy_int(pool);
+ pool = next;
+ }
+}
+
+static pj_pool_t* cpool_create_pool(pj_pool_factory *pf,
+ const char *name,
+ pj_size_t initial_size,
+ pj_size_t increment_sz,
+ pj_pool_callback *callback)
+{
+ pj_caching_pool *cp = (pj_caching_pool*)pf;
+ pj_pool_t *pool;
+ int idx;
+
+ PJ_CHECK_STACK();
+
+ /* Use pool factory's policy when callback is NULL */
+ if (callback == NULL) {
+ callback = pf->policy.callback;
+ }
+
+ /* Search the suitable size for the pool.
+ * We'll just do linear search to the size array, as the array size itself
+ * is only a few elements. Binary search I suspect will be less efficient
+ * for this purpose.
+ */
+ for (idx=0;
+ idx < PJ_CACHING_POOL_ARRAY_SIZE && pool_sizes[idx] < initial_size;
+ ++idx)
+ ;
+
+ /* Check whether there's a pool in the list. */
+ if (idx==PJ_CACHING_POOL_ARRAY_SIZE || pj_list_empty(&cp->free_list[idx])) {
+ /* No pool is available. */
+ /* Set minimum size. */
+ if (idx < PJ_CACHING_POOL_ARRAY_SIZE)
+ initial_size = pool_sizes[idx];
+
+ /* Create new pool */
+ pool = pj_pool_create_int(&cp->factory, name, initial_size,
+ increment_sz, callback);
+ if (!pool)
+ return NULL;
+
+ } else {
+ /* Get one pool from the list. */
+ pool = cp->free_list[idx].next;
+ pj_list_erase(pool);
+
+ /* Initialize the pool. */
+ pj_pool_init_int(pool, name, increment_sz, callback);
+
+ /* Update pool manager's free capacity. */
+ cp->capacity -= pj_pool_get_capacity(pool);
+
+ PJ_LOG(5, (pool->obj_name, "pool reused, size=%u", pool->capacity));
+ }
+
+ /* Put in used list. */
+ pj_list_insert_before( &cp->used_list, pool );
+
+ /* Increment used count. */
+ ++cp->used_count;
+ return pool;
+}
+
+static void cpool_release_pool( pj_pool_factory *pf, pj_pool_t *pool)
+{
+ pj_caching_pool *cp = (pj_caching_pool*)pf;
+ int i;
+
+ PJ_CHECK_STACK();
+
+ /* Erase from the used list. */
+ pj_list_erase(pool);
+
+ /* Decrement used count. */
+ --cp->used_count;
+
+ /* Destroy the pool if the size is greater than our size or if the total
+ * capacity in our recycle list (plus the size of the pool) exceeds
+ * maximum capacity.
+ . */
+ if (pool->capacity > pool_sizes[PJ_CACHING_POOL_ARRAY_SIZE-1] ||
+ cp->capacity + pool->capacity > cp->max_capacity)
+ {
+ pj_pool_destroy_int(pool);
+ return;
+ }
+
+ /* Reset pool. */
+ PJ_LOG(4, (pool->obj_name, "recycle(): cap=%d, used=%d(%d%%)",
+ pool->capacity, pool->used_size, pool->used_size*100/pool->capacity));
+ pj_pool_reset(pool);
+
+ /*
+ * Otherwise put the pool in our recycle list.
+ */
+ for (i=0; i < PJ_CACHING_POOL_ARRAY_SIZE && pool_sizes[i] != pool->capacity; ++i)
+ ;
+
+ pj_assert( i != PJ_CACHING_POOL_ARRAY_SIZE );
+ if (i == PJ_CACHING_POOL_ARRAY_SIZE) {
+ /* Something has gone wrong with the pool. */
+ pj_pool_destroy_int(pool);
+ return;
+ }
+
+ pj_list_insert_after(&cp->free_list[i], pool);
+ cp->capacity += pool->capacity;
+}
+
+static void cpool_dump_status(pj_pool_factory *factory, pj_bool_t detail )
+{
+#if PJ_LOG_MAX_LEVEL >= 3
+ pj_caching_pool *cp = (pj_caching_pool*)factory;
+ PJ_LOG(3,("cachpool", " Dumping caching pool:"));
+ PJ_LOG(3,("cachpool", " Capacity=%u, max_capacity=%u, used_cnt=%u", \
+ cp->capacity, cp->max_capacity, cp->used_count));
+ if (detail) {
+ pj_pool_t *pool = cp->used_list.next;
+ pj_uint32_t total_used = 0, total_capacity = 0;
+ PJ_LOG(3,("cachpool", " Dumping all active pools:"));
+ while (pool != (void*)&cp->used_list) {
+ PJ_LOG(3,("cachpool", " %12s: %8d of %8d (%d%%) used", pool->obj_name,
+ pool->used_size, pool->capacity,
+ pool->used_size*100/pool->capacity));
+ total_used += pool->used_size;
+ total_capacity += pool->capacity;
+ pool = pool->next;
+ }
+ PJ_LOG(3,("cachpool", " Total %9d of %9d (%d %%) used!",
+ total_used, total_capacity,
+ total_used * 100 / total_capacity));
+ }
+#endif
+}
diff --git a/pjlib/src/pj/pool_dbg_win32.c b/pjlib/src/pj/pool_dbg_win32.c
index 9e451d7b..33aa80d5 100644
--- a/pjlib/src/pj/pool_dbg_win32.c
+++ b/pjlib/src/pj/pool_dbg_win32.c
@@ -1,221 +1,242 @@
-/* $Id$
- */
-#include <pj/pool.h>
-
-/* Only if we ARE debugging memory allocations. */
-#if PJ_POOL_DEBUG
-
-#include <pj/list.h>
-#include <pj/log.h>
-
-#include <stdlib.h>
-#include <stdio.h>
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-
-typedef struct memory_entry
-{
- PJ_DECL_LIST_MEMBER(struct memory_entry)
- void *ptr;
- char *file;
- int line;
-} memory_entry;
-
-struct pj_pool_t
-{
- char obj_name[32];
- HANDLE hHeap;
- memory_entry first;
- pj_size_t initial_size;
- pj_size_t increment;
- pj_size_t used_size;
- char *file;
- int line;
-};
-
-PJ_DEF(void) pj_pool_set_functions( void *(*malloc_func)(pj_size_t),
- void (*free_func)(void *ptr, pj_size_t))
-{
- /* Ignored. */
- PJ_CHECK_STACK();
- PJ_UNUSED_ARG(malloc_func)
- PJ_UNUSED_ARG(free_func)
-}
-
-PJ_DEF(pj_pool_t*) pj_pool_create_dbg( const char *name,
- pj_size_t initial_size,
- pj_size_t increment_size,
- pj_pool_callback *callback,
- char *file, int line)
-{
- pj_pool_t *pool;
- HANDLE hHeap;
-
- PJ_CHECK_STACK();
- PJ_UNUSED_ARG(callback)
-
- /* Create Win32 heap for the pool. */
- hHeap = HeapCreate(HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE,
- initial_size, 0);
- if (!hHeap) {
- return NULL;
- }
-
-
- /* Create and initialize the pool structure. */
- pool = HeapAlloc(hHeap, HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE,
- sizeof(*pool));
- memset(pool, 0, sizeof(*pool));
- pool->file = file;
- pool->line = line;
- pool->hHeap = hHeap;
- pool->initial_size = initial_size;
- pool->increment = increment_size;
- pool->used_size = 0;
-
- /* Set name. */
- if (name) {
- if (strchr(name, '%') != NULL) {
- sprintf(pool->obj_name, name, pool);
- } else {
- strncpy(pool->obj_name, name, PJ_MAX_OBJ_NAME);
- }
- } else {
- pool->obj_name[0] = '\0';
- }
-
- /* List pool's entry. */
- pj_list_init(&pool->first);
-
- PJ_LOG(3,(pool->obj_name, "Pool created"));
- return pool;
-}
-
-PJ_DEF(void) pj_pool_destroy( pj_pool_t *pool )
-{
- memory_entry *entry;
-
- PJ_CHECK_STACK();
-
- PJ_LOG(3,(pool->obj_name, "Destoying pool, init_size=%u, used=%u",
- pool->initial_size, pool->used_size));
-
- if (!HeapValidate( pool->hHeap, HEAP_NO_SERIALIZE, pool)) {
- PJ_LOG(2,(pool->obj_name, "Corrupted pool structure, allocated in %s:%d",
- pool->file, pool->line));
- }
-
- /* Validate all memory entries in the pool. */
- for (entry=pool->first.next; entry != &pool->first; entry = entry->next) {
- if (!HeapValidate( pool->hHeap, HEAP_NO_SERIALIZE, entry)) {
- PJ_LOG(2,(pool->obj_name, "Corrupted pool entry, allocated in %s:%d",
- entry->file, entry->line));
- }
-
- if (!HeapValidate( pool->hHeap, HEAP_NO_SERIALIZE, entry->ptr)) {
- PJ_LOG(2,(pool->obj_name, "Corrupted pool memory, allocated in %s:%d",
- entry->file, entry->line));
- }
- }
-
- /* Destroy heap. */
- HeapDestroy(pool->hHeap);
-}
-
-PJ_DEF(void) pj_pool_reset( pj_pool_t *pool )
-{
- /* Do nothing. */
- PJ_CHECK_STACK();
- PJ_UNUSED_ARG(pool)
-}
-
-PJ_DEF(pj_size_t) pj_pool_get_capacity( pj_pool_t *pool )
-{
- PJ_CHECK_STACK();
- PJ_UNUSED_ARG(pool)
- return 0;
-}
-
-PJ_DEF(pj_size_t) pj_pool_get_used_size( pj_pool_t *pool )
-{
- PJ_CHECK_STACK();
- PJ_UNUSED_ARG(pool)
- return 0;
-}
-
-PJ_DEF(pj_size_t) pj_pool_get_request_count( pj_pool_t *pool )
-{
- PJ_CHECK_STACK();
- PJ_UNUSED_ARG(pool)
- return 0;
-}
-
-PJ_DEF(void*) pj_pool_alloc_dbg( pj_pool_t *pool, pj_size_t size,
- char *file, int line)
-{
- memory_entry *entry;
- int entry_size;
-
- PJ_CHECK_STACK();
-
- entry_size = sizeof(*entry);
- entry = HeapAlloc(pool->hHeap, HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE,
- entry_size);
- entry->file = file;
- entry->line = line;
- entry->ptr = HeapAlloc(pool->hHeap, HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE,
- size);
- pj_list_insert_before( &pool->first, entry);
-
- pool->used_size += size;
- return entry->ptr;
-}
-
-PJ_DEF(void*) pj_pool_calloc_dbg( pj_pool_t *pool, pj_size_t count, pj_size_t elem,
- char *file, int line)
-{
- void *ptr;
-
- PJ_CHECK_STACK();
-
- ptr = pj_pool_alloc_dbg(pool, count*elem, file, line);
- memset(ptr, 0, count*elem);
- return ptr;
-}
-
-
-PJ_DEF(void) pj_pool_pool_init( pj_pool_pool_t *pool_pool,
- pj_size_t max_capacity)
-{
- PJ_CHECK_STACK();
- PJ_UNUSED_ARG(pool_pool)
- PJ_UNUSED_ARG(max_capacity)
-}
-
-PJ_DEF(void) pj_pool_pool_destroy( pj_pool_pool_t *pool_pool )
-{
- PJ_CHECK_STACK();
- PJ_UNUSED_ARG(pool_pool)
-}
-
-PJ_DEF(pj_pool_t*) pj_pool_pool_create_pool( pj_pool_pool_t *pool_pool,
- const char *name,
- pj_size_t initial_size,
- pj_size_t increment_size,
- pj_pool_callback *callback)
-{
- PJ_CHECK_STACK();
- PJ_UNUSED_ARG(pool_pool)
- return pj_pool_create(name, initial_size, increment_size, callback);
-}
-
-PJ_DEF(void) pj_pool_pool_release_pool( pj_pool_pool_t *pool_pool,
- pj_pool_t *pool )
-{
- PJ_CHECK_STACK();
- PJ_UNUSED_ARG(pool_pool)
- pj_pool_destroy(pool);
-}
-
-
-#endif /* PJ_POOL_DEBUG */
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/pool.h>
+
+/* Only if we ARE debugging memory allocations. */
+#if PJ_POOL_DEBUG
+
+#include <pj/list.h>
+#include <pj/log.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+typedef struct memory_entry
+{
+ PJ_DECL_LIST_MEMBER(struct memory_entry)
+ void *ptr;
+ char *file;
+ int line;
+} memory_entry;
+
+struct pj_pool_t
+{
+ char obj_name[32];
+ HANDLE hHeap;
+ memory_entry first;
+ pj_size_t initial_size;
+ pj_size_t increment;
+ pj_size_t used_size;
+ char *file;
+ int line;
+};
+
+PJ_DEF(void) pj_pool_set_functions( void *(*malloc_func)(pj_size_t),
+ void (*free_func)(void *ptr, pj_size_t))
+{
+ /* Ignored. */
+ PJ_CHECK_STACK();
+ PJ_UNUSED_ARG(malloc_func)
+ PJ_UNUSED_ARG(free_func)
+}
+
+PJ_DEF(pj_pool_t*) pj_pool_create_dbg( const char *name,
+ pj_size_t initial_size,
+ pj_size_t increment_size,
+ pj_pool_callback *callback,
+ char *file, int line)
+{
+ pj_pool_t *pool;
+ HANDLE hHeap;
+
+ PJ_CHECK_STACK();
+ PJ_UNUSED_ARG(callback)
+
+ /* Create Win32 heap for the pool. */
+ hHeap = HeapCreate(HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE,
+ initial_size, 0);
+ if (!hHeap) {
+ return NULL;
+ }
+
+
+ /* Create and initialize the pool structure. */
+ pool = HeapAlloc(hHeap, HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE,
+ sizeof(*pool));
+ memset(pool, 0, sizeof(*pool));
+ pool->file = file;
+ pool->line = line;
+ pool->hHeap = hHeap;
+ pool->initial_size = initial_size;
+ pool->increment = increment_size;
+ pool->used_size = 0;
+
+ /* Set name. */
+ if (name) {
+ if (strchr(name, '%') != NULL) {
+ sprintf(pool->obj_name, name, pool);
+ } else {
+ strncpy(pool->obj_name, name, PJ_MAX_OBJ_NAME);
+ }
+ } else {
+ pool->obj_name[0] = '\0';
+ }
+
+ /* List pool's entry. */
+ pj_list_init(&pool->first);
+
+ PJ_LOG(3,(pool->obj_name, "Pool created"));
+ return pool;
+}
+
+PJ_DEF(void) pj_pool_destroy( pj_pool_t *pool )
+{
+ memory_entry *entry;
+
+ PJ_CHECK_STACK();
+
+ PJ_LOG(3,(pool->obj_name, "Destoying pool, init_size=%u, used=%u",
+ pool->initial_size, pool->used_size));
+
+ if (!HeapValidate( pool->hHeap, HEAP_NO_SERIALIZE, pool)) {
+ PJ_LOG(2,(pool->obj_name, "Corrupted pool structure, allocated in %s:%d",
+ pool->file, pool->line));
+ }
+
+ /* Validate all memory entries in the pool. */
+ for (entry=pool->first.next; entry != &pool->first; entry = entry->next) {
+ if (!HeapValidate( pool->hHeap, HEAP_NO_SERIALIZE, entry)) {
+ PJ_LOG(2,(pool->obj_name, "Corrupted pool entry, allocated in %s:%d",
+ entry->file, entry->line));
+ }
+
+ if (!HeapValidate( pool->hHeap, HEAP_NO_SERIALIZE, entry->ptr)) {
+ PJ_LOG(2,(pool->obj_name, "Corrupted pool memory, allocated in %s:%d",
+ entry->file, entry->line));
+ }
+ }
+
+ /* Destroy heap. */
+ HeapDestroy(pool->hHeap);
+}
+
+PJ_DEF(void) pj_pool_reset( pj_pool_t *pool )
+{
+ /* Do nothing. */
+ PJ_CHECK_STACK();
+ PJ_UNUSED_ARG(pool)
+}
+
+PJ_DEF(pj_size_t) pj_pool_get_capacity( pj_pool_t *pool )
+{
+ PJ_CHECK_STACK();
+ PJ_UNUSED_ARG(pool)
+ return 0;
+}
+
+PJ_DEF(pj_size_t) pj_pool_get_used_size( pj_pool_t *pool )
+{
+ PJ_CHECK_STACK();
+ PJ_UNUSED_ARG(pool)
+ return 0;
+}
+
+PJ_DEF(pj_size_t) pj_pool_get_request_count( pj_pool_t *pool )
+{
+ PJ_CHECK_STACK();
+ PJ_UNUSED_ARG(pool)
+ return 0;
+}
+
+PJ_DEF(void*) pj_pool_alloc_dbg( pj_pool_t *pool, pj_size_t size,
+ char *file, int line)
+{
+ memory_entry *entry;
+ int entry_size;
+
+ PJ_CHECK_STACK();
+
+ entry_size = sizeof(*entry);
+ entry = HeapAlloc(pool->hHeap, HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE,
+ entry_size);
+ entry->file = file;
+ entry->line = line;
+ entry->ptr = HeapAlloc(pool->hHeap, HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE,
+ size);
+ pj_list_insert_before( &pool->first, entry);
+
+ pool->used_size += size;
+ return entry->ptr;
+}
+
+PJ_DEF(void*) pj_pool_calloc_dbg( pj_pool_t *pool, pj_size_t count, pj_size_t elem,
+ char *file, int line)
+{
+ void *ptr;
+
+ PJ_CHECK_STACK();
+
+ ptr = pj_pool_alloc_dbg(pool, count*elem, file, line);
+ memset(ptr, 0, count*elem);
+ return ptr;
+}
+
+
+PJ_DEF(void) pj_pool_pool_init( pj_pool_pool_t *pool_pool,
+ pj_size_t max_capacity)
+{
+ PJ_CHECK_STACK();
+ PJ_UNUSED_ARG(pool_pool)
+ PJ_UNUSED_ARG(max_capacity)
+}
+
+PJ_DEF(void) pj_pool_pool_destroy( pj_pool_pool_t *pool_pool )
+{
+ PJ_CHECK_STACK();
+ PJ_UNUSED_ARG(pool_pool)
+}
+
+PJ_DEF(pj_pool_t*) pj_pool_pool_create_pool( pj_pool_pool_t *pool_pool,
+ const char *name,
+ pj_size_t initial_size,
+ pj_size_t increment_size,
+ pj_pool_callback *callback)
+{
+ PJ_CHECK_STACK();
+ PJ_UNUSED_ARG(pool_pool)
+ return pj_pool_create(name, initial_size, increment_size, callback);
+}
+
+PJ_DEF(void) pj_pool_pool_release_pool( pj_pool_pool_t *pool_pool,
+ pj_pool_t *pool )
+{
+ PJ_CHECK_STACK();
+ PJ_UNUSED_ARG(pool_pool)
+ pj_pool_destroy(pool);
+}
+
+
+#endif /* PJ_POOL_DEBUG */
diff --git a/pjlib/src/pj/pool_policy_kmalloc.c b/pjlib/src/pj/pool_policy_kmalloc.c
index 267f72f2..6b40d311 100644
--- a/pjlib/src/pj/pool_policy_kmalloc.c
+++ b/pjlib/src/pj/pool_policy_kmalloc.c
@@ -1,43 +1,64 @@
-/* $Id$
- *
- */
-#include <pj/pool.h>
-#include <pj/except.h>
-#include <pj/os.h>
-
-
-static void *default_block_alloc(pj_pool_factory *factory, pj_size_t size)
-{
- PJ_CHECK_STACK();
- PJ_UNUSED_ARG(factory);
-
- return kmalloc(size, GFP_ATOMIC);
-}
-
-static void default_block_free(pj_pool_factory *factory,
- void *mem, pj_size_t size)
-{
- PJ_CHECK_STACK();
- PJ_UNUSED_ARG(factory);
- PJ_UNUSED_ARG(size);
-
- kfree(mem);
-}
-
-static void default_pool_callback(pj_pool_t *pool, pj_size_t size)
-{
- PJ_CHECK_STACK();
- PJ_UNUSED_ARG(pool);
- PJ_UNUSED_ARG(size);
-
- PJ_THROW(PJ_NO_MEMORY_EXCEPTION);
-}
-
-pj_pool_factory_policy pj_pool_factory_default_policy =
-{
- &default_block_alloc,
- &default_block_free,
- &default_pool_callback,
- 0
-};
-
+/* $Id$
+ *
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/pool.h>
+#include <pj/except.h>
+#include <pj/os.h>
+
+
+static void *default_block_alloc(pj_pool_factory *factory, pj_size_t size)
+{
+ PJ_CHECK_STACK();
+ PJ_UNUSED_ARG(factory);
+
+ return kmalloc(size, GFP_ATOMIC);
+}
+
+static void default_block_free(pj_pool_factory *factory,
+ void *mem, pj_size_t size)
+{
+ PJ_CHECK_STACK();
+ PJ_UNUSED_ARG(factory);
+ PJ_UNUSED_ARG(size);
+
+ kfree(mem);
+}
+
+static void default_pool_callback(pj_pool_t *pool, pj_size_t size)
+{
+ PJ_CHECK_STACK();
+ PJ_UNUSED_ARG(pool);
+ PJ_UNUSED_ARG(size);
+
+ PJ_THROW(PJ_NO_MEMORY_EXCEPTION);
+}
+
+pj_pool_factory_policy pj_pool_factory_default_policy =
+{
+ &default_block_alloc,
+ &default_block_free,
+ &default_pool_callback,
+ 0
+};
+
diff --git a/pjlib/src/pj/pool_policy_malloc.c b/pjlib/src/pj/pool_policy_malloc.c
index bb82cbb5..4baf98b5 100644
--- a/pjlib/src/pj/pool_policy_malloc.c
+++ b/pjlib/src/pj/pool_policy_malloc.c
@@ -1,46 +1,67 @@
-/* $Id$
- */
-#include <pj/pool.h>
-#include <pj/except.h>
-#include <pj/os.h>
-#include <pj/compat/malloc.h>
-
-/*
- * This file contains pool default policy definition and implementation.
- */
-
-
-static void *default_block_alloc(pj_pool_factory *factory, pj_size_t size)
-{
- PJ_CHECK_STACK();
- PJ_UNUSED_ARG(factory);
- PJ_UNUSED_ARG(size);
-
- return malloc(size);
-}
-
-static void default_block_free(pj_pool_factory *factory, void *mem, pj_size_t size)
-{
- PJ_CHECK_STACK();
- PJ_UNUSED_ARG(factory);
- PJ_UNUSED_ARG(size);
-
- free(mem);
-}
-
-static void default_pool_callback(pj_pool_t *pool, pj_size_t size)
-{
- PJ_CHECK_STACK();
- PJ_UNUSED_ARG(pool);
- PJ_UNUSED_ARG(size);
-
- PJ_THROW(PJ_NO_MEMORY_EXCEPTION);
-}
-
-pj_pool_factory_policy pj_pool_factory_default_policy =
-{
- &default_block_alloc,
- &default_block_free,
- &default_pool_callback,
- 0
-};
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/pool.h>
+#include <pj/except.h>
+#include <pj/os.h>
+#include <pj/compat/malloc.h>
+
+/*
+ * This file contains pool default policy definition and implementation.
+ */
+
+
+static void *default_block_alloc(pj_pool_factory *factory, pj_size_t size)
+{
+ PJ_CHECK_STACK();
+ PJ_UNUSED_ARG(factory);
+ PJ_UNUSED_ARG(size);
+
+ return malloc(size);
+}
+
+static void default_block_free(pj_pool_factory *factory, void *mem, pj_size_t size)
+{
+ PJ_CHECK_STACK();
+ PJ_UNUSED_ARG(factory);
+ PJ_UNUSED_ARG(size);
+
+ free(mem);
+}
+
+static void default_pool_callback(pj_pool_t *pool, pj_size_t size)
+{
+ PJ_CHECK_STACK();
+ PJ_UNUSED_ARG(pool);
+ PJ_UNUSED_ARG(size);
+
+ PJ_THROW(PJ_NO_MEMORY_EXCEPTION);
+}
+
+pj_pool_factory_policy pj_pool_factory_default_policy =
+{
+ &default_block_alloc,
+ &default_block_free,
+ &default_pool_callback,
+ 0
+};
diff --git a/pjlib/src/pj/rand.c b/pjlib/src/pj/rand.c
index a8a2878e..df549d5f 100644
--- a/pjlib/src/pj/rand.c
+++ b/pjlib/src/pj/rand.c
@@ -1,18 +1,39 @@
-/* $Id$
- */
-#include <pj/rand.h>
-#include <pj/os.h>
-#include <pj/compat/rand.h>
-
-PJ_DEF(void) pj_srand(unsigned int seed)
-{
- PJ_CHECK_STACK();
- platform_srand(seed);
-}
-
-PJ_DEF(int) pj_rand(void)
-{
- PJ_CHECK_STACK();
- return platform_rand();
-}
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/rand.h>
+#include <pj/os.h>
+#include <pj/compat/rand.h>
+
+PJ_DEF(void) pj_srand(unsigned int seed)
+{
+ PJ_CHECK_STACK();
+ platform_srand(seed);
+}
+
+PJ_DEF(int) pj_rand(void)
+{
+ PJ_CHECK_STACK();
+ return platform_rand();
+}
+
diff --git a/pjlib/src/pj/rbtree.c b/pjlib/src/pj/rbtree.c
index a0babe0f..2f548c25 100644
--- a/pjlib/src/pj/rbtree.c
+++ b/pjlib/src/pj/rbtree.c
@@ -1,411 +1,432 @@
-/* $Id$
- */
-#include <pj/rbtree.h>
-#include <pj/os.h>
-
-static void left_rotate( pj_rbtree *tree, pj_rbtree_node *node )
-{
- pj_rbtree_node *rnode, *parent;
-
- PJ_CHECK_STACK();
-
- rnode = node->right;
- if (rnode == tree->null)
- return;
-
- node->right = rnode->left;
- if (rnode->left != tree->null)
- rnode->left->parent = node;
- parent = node->parent;
- rnode->parent = parent;
- if (parent != tree->null) {
- if (parent->left == node)
- parent->left = rnode;
- else
- parent->right = rnode;
- } else {
- tree->root = rnode;
- }
- rnode->left = node;
- node->parent = rnode;
-}
-
-static void right_rotate( pj_rbtree *tree, pj_rbtree_node *node )
-{
- pj_rbtree_node *lnode, *parent;
-
- PJ_CHECK_STACK();
-
- lnode = node->left;
- if (lnode == tree->null)
- return;
-
- node->left = lnode->right;
- if (lnode->right != tree->null)
- lnode->right->parent = node;
- parent = node->parent;
- lnode->parent = parent;
-
- if (parent != tree->null) {
- if (parent->left == node)
- parent->left = lnode;
- else
- parent->right = lnode;
- } else {
- tree->root = lnode;
- }
- lnode->right = node;
- node->parent = lnode;
-}
-
-static void insert_fixup( pj_rbtree *tree, pj_rbtree_node *node )
-{
- pj_rbtree_node *temp, *parent;
-
- PJ_CHECK_STACK();
-
- while (node != tree->root && node->parent->color == PJ_RBCOLOR_RED) {
- parent = node->parent;
- if (parent == parent->parent->left) {
- temp = parent->parent->right;
- if (temp->color == PJ_RBCOLOR_RED) {
- temp->color = PJ_RBCOLOR_BLACK;
- node = parent;
- node->color = PJ_RBCOLOR_BLACK;
- node = node->parent;
- node->color = PJ_RBCOLOR_RED;
- } else {
- if (node == parent->right) {
- node = parent;
- left_rotate(tree, node);
- }
- temp = node->parent;
- temp->color = PJ_RBCOLOR_BLACK;
- temp = temp->parent;
- temp->color = PJ_RBCOLOR_RED;
- right_rotate( tree, temp);
- }
- } else {
- temp = parent->parent->left;
- if (temp->color == PJ_RBCOLOR_RED) {
- temp->color = PJ_RBCOLOR_BLACK;
- node = parent;
- node->color = PJ_RBCOLOR_BLACK;
- node = node->parent;
- node->color = PJ_RBCOLOR_RED;
- } else {
- if (node == parent->left) {
- node = parent;
- right_rotate(tree, node);
- }
- temp = node->parent;
- temp->color = PJ_RBCOLOR_BLACK;
- temp = temp->parent;
- temp->color = PJ_RBCOLOR_RED;
- left_rotate(tree, temp);
- }
- }
- }
-
- tree->root->color = PJ_RBCOLOR_BLACK;
-}
-
-
-static void delete_fixup( pj_rbtree *tree, pj_rbtree_node *node )
-{
- pj_rbtree_node *temp;
-
- PJ_CHECK_STACK();
-
- while (node != tree->root && node->color == PJ_RBCOLOR_BLACK) {
- if (node->parent->left == node) {
- temp = node->parent->right;
- if (temp->color == PJ_RBCOLOR_RED) {
- temp->color = PJ_RBCOLOR_BLACK;
- node->parent->color = PJ_RBCOLOR_RED;
- left_rotate(tree, node->parent);
- temp = node->parent->right;
- }
- if (temp->left->color == PJ_RBCOLOR_BLACK &&
- temp->right->color == PJ_RBCOLOR_BLACK)
- {
- temp->color = PJ_RBCOLOR_RED;
- node = node->parent;
- } else {
- if (temp->right->color == PJ_RBCOLOR_BLACK) {
- temp->left->color = PJ_RBCOLOR_BLACK;
- temp->color = PJ_RBCOLOR_RED;
- right_rotate( tree, temp);
- temp = node->parent->right;
- }
- temp->color = node->parent->color;
- temp->right->color = PJ_RBCOLOR_BLACK;
- node->parent->color = PJ_RBCOLOR_BLACK;
- left_rotate(tree, node->parent);
- node = tree->root;
- }
- } else {
- temp = node->parent->left;
- if (temp->color == PJ_RBCOLOR_RED) {
- temp->color = PJ_RBCOLOR_BLACK;
- node->parent->color = PJ_RBCOLOR_RED;
- right_rotate( tree, node->parent);
- temp = node->parent->left;
- }
- if (temp->right->color == PJ_RBCOLOR_BLACK &&
- temp->left->color == PJ_RBCOLOR_BLACK)
- {
- temp->color = PJ_RBCOLOR_RED;
- node = node->parent;
- } else {
- if (temp->left->color == PJ_RBCOLOR_BLACK) {
- temp->right->color = PJ_RBCOLOR_BLACK;
- temp->color = PJ_RBCOLOR_RED;
- left_rotate( tree, temp);
- temp = node->parent->left;
- }
- temp->color = node->parent->color;
- node->parent->color = PJ_RBCOLOR_BLACK;
- temp->left->color = PJ_RBCOLOR_BLACK;
- right_rotate(tree, node->parent);
- node = tree->root;
- }
- }
- }
-
- node->color = PJ_RBCOLOR_BLACK;
-}
-
-
-PJ_DEF(void) pj_rbtree_init( pj_rbtree *tree, pj_rbtree_comp *comp )
-{
- PJ_CHECK_STACK();
-
- tree->null = tree->root = &tree->null_node;
- tree->null->key = NULL;
- tree->null->user_data = NULL;
- tree->size = 0;
- tree->null->left = tree->null->right = tree->null->parent = tree->null;
- tree->null->color = PJ_RBCOLOR_BLACK;
- tree->comp = comp;
-}
-
-PJ_DEF(pj_rbtree_node*) pj_rbtree_first( pj_rbtree *tree )
-{
- register pj_rbtree_node *node = tree->root;
- register pj_rbtree_node *null = tree->null;
-
- PJ_CHECK_STACK();
-
- while (node->left != null)
- node = node->left;
- return node != null ? node : NULL;
-}
-
-PJ_DEF(pj_rbtree_node*) pj_rbtree_last( pj_rbtree *tree )
-{
- register pj_rbtree_node *node = tree->root;
- register pj_rbtree_node *null = tree->null;
-
- PJ_CHECK_STACK();
-
- while (node->right != null)
- node = node->right;
- return node != null ? node : NULL;
-}
-
-PJ_DEF(pj_rbtree_node*) pj_rbtree_next( pj_rbtree *tree,
- register pj_rbtree_node *node )
-{
- register pj_rbtree_node *null = tree->null;
-
- PJ_CHECK_STACK();
-
- if (node->right != null) {
- for (node=node->right; node->left!=null; node = node->left)
- /* void */;
- } else {
- register pj_rbtree_node *temp = node->parent;
- while (temp!=null && temp->right==node) {
- node = temp;
- temp = temp->parent;
- }
- node = temp;
- }
- return node != null ? node : NULL;
-}
-
-PJ_DEF(pj_rbtree_node*) pj_rbtree_prev( pj_rbtree *tree,
- register pj_rbtree_node *node )
-{
- register pj_rbtree_node *null = tree->null;
-
- PJ_CHECK_STACK();
-
- if (node->left != null) {
- for (node=node->left; node->right!=null; node=node->right)
- /* void */;
- } else {
- register pj_rbtree_node *temp = node->parent;
- while (temp!=null && temp->left==node) {
- node = temp;
- temp = temp->parent;
- }
- node = temp;
- }
- return node != null ? node : NULL;
-}
-
-PJ_DEF(int) pj_rbtree_insert( pj_rbtree *tree,
- pj_rbtree_node *element )
-{
- int rv = 0;
- pj_rbtree_node *node, *parent = tree->null,
- *null = tree->null;
- pj_rbtree_comp *comp = tree->comp;
-
- PJ_CHECK_STACK();
-
- node = tree->root;
- while (node != null) {
- rv = (*comp)(element->key, node->key);
- if (rv == 0) {
- /* found match, i.e. entry with equal key already exist */
- return -1;
- }
- parent = node;
- node = rv < 0 ? node->left : node->right;
- }
-
- element->color = PJ_RBCOLOR_RED;
- element->left = element->right = null;
-
- node = element;
- if (parent != null) {
- node->parent = parent;
- if (rv < 0)
- parent->left = node;
- else
- parent->right = node;
- insert_fixup( tree, node);
- } else {
- tree->root = node;
- node->parent = null;
- node->color = PJ_RBCOLOR_BLACK;
- }
-
- ++tree->size;
- return 0;
-}
-
-
-PJ_DEF(pj_rbtree_node*) pj_rbtree_find( pj_rbtree *tree,
- const void *key )
-{
- int rv;
- pj_rbtree_node *node = tree->root;
- pj_rbtree_node *null = tree->null;
- pj_rbtree_comp *comp = tree->comp;
-
- while (node != null) {
- rv = (*comp)(key, node->key);
- if (rv == 0)
- return node;
- node = rv < 0 ? node->left : node->right;
- }
- return node != null ? node : NULL;
-}
-
-PJ_DEF(pj_rbtree_node*) pj_rbtree_erase( pj_rbtree *tree,
- pj_rbtree_node *node )
-{
- pj_rbtree_node *succ;
- pj_rbtree_node *null = tree->null;
- pj_rbtree_node *child;
- pj_rbtree_node *parent;
-
- PJ_CHECK_STACK();
-
- if (node->left == null || node->right == null) {
- succ = node;
- } else {
- for (succ=node->right; succ->left!=null; succ=succ->left)
- /* void */;
- }
-
- child = succ->left != null ? succ->left : succ->right;
- parent = succ->parent;
- child->parent = parent;
-
- if (parent != null) {
- if (parent->left == succ)
- parent->left = child;
- else
- parent->right = child;
- } else
- tree->root = child;
-
- if (succ != node) {
- succ->parent = node->parent;
- succ->left = node->left;
- succ->right = node->right;
- succ->color = node->color;
-
- parent = node->parent;
- if (parent != null) {
- if (parent->left==node)
- parent->left=succ;
- else
- parent->right=succ;
- }
- if (node->left != null)
- node->left->parent = succ;;
- if (node->right != null)
- node->right->parent = succ;
-
- if (tree->root == node)
- tree->root = succ;
- }
-
- if (succ->color == PJ_RBCOLOR_BLACK) {
- if (child != null)
- delete_fixup(tree, child);
- tree->null->color = PJ_RBCOLOR_BLACK;
- }
-
- --tree->size;
- return node;
-}
-
-
-PJ_DEF(unsigned) pj_rbtree_max_height( pj_rbtree *tree,
- pj_rbtree_node *node )
-{
- unsigned l, r;
-
- PJ_CHECK_STACK();
-
- if (node==NULL)
- node = tree->root;
-
- l = node->left != tree->null ? pj_rbtree_max_height(tree,node->left)+1 : 0;
- r = node->right != tree->null ? pj_rbtree_max_height(tree,node->right)+1 : 0;
- return l > r ? l : r;
-}
-
-PJ_DEF(unsigned) pj_rbtree_min_height( pj_rbtree *tree,
- pj_rbtree_node *node )
-{
- unsigned l, r;
-
- PJ_CHECK_STACK();
-
- if (node==NULL)
- node=tree->root;
-
- l = (node->left != tree->null) ? pj_rbtree_max_height(tree,node->left)+1 : 0;
- r = (node->right != tree->null) ? pj_rbtree_max_height(tree,node->right)+1 : 0;
- return l > r ? r : l;
-}
-
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/rbtree.h>
+#include <pj/os.h>
+
+static void left_rotate( pj_rbtree *tree, pj_rbtree_node *node )
+{
+ pj_rbtree_node *rnode, *parent;
+
+ PJ_CHECK_STACK();
+
+ rnode = node->right;
+ if (rnode == tree->null)
+ return;
+
+ node->right = rnode->left;
+ if (rnode->left != tree->null)
+ rnode->left->parent = node;
+ parent = node->parent;
+ rnode->parent = parent;
+ if (parent != tree->null) {
+ if (parent->left == node)
+ parent->left = rnode;
+ else
+ parent->right = rnode;
+ } else {
+ tree->root = rnode;
+ }
+ rnode->left = node;
+ node->parent = rnode;
+}
+
+static void right_rotate( pj_rbtree *tree, pj_rbtree_node *node )
+{
+ pj_rbtree_node *lnode, *parent;
+
+ PJ_CHECK_STACK();
+
+ lnode = node->left;
+ if (lnode == tree->null)
+ return;
+
+ node->left = lnode->right;
+ if (lnode->right != tree->null)
+ lnode->right->parent = node;
+ parent = node->parent;
+ lnode->parent = parent;
+
+ if (parent != tree->null) {
+ if (parent->left == node)
+ parent->left = lnode;
+ else
+ parent->right = lnode;
+ } else {
+ tree->root = lnode;
+ }
+ lnode->right = node;
+ node->parent = lnode;
+}
+
+static void insert_fixup( pj_rbtree *tree, pj_rbtree_node *node )
+{
+ pj_rbtree_node *temp, *parent;
+
+ PJ_CHECK_STACK();
+
+ while (node != tree->root && node->parent->color == PJ_RBCOLOR_RED) {
+ parent = node->parent;
+ if (parent == parent->parent->left) {
+ temp = parent->parent->right;
+ if (temp->color == PJ_RBCOLOR_RED) {
+ temp->color = PJ_RBCOLOR_BLACK;
+ node = parent;
+ node->color = PJ_RBCOLOR_BLACK;
+ node = node->parent;
+ node->color = PJ_RBCOLOR_RED;
+ } else {
+ if (node == parent->right) {
+ node = parent;
+ left_rotate(tree, node);
+ }
+ temp = node->parent;
+ temp->color = PJ_RBCOLOR_BLACK;
+ temp = temp->parent;
+ temp->color = PJ_RBCOLOR_RED;
+ right_rotate( tree, temp);
+ }
+ } else {
+ temp = parent->parent->left;
+ if (temp->color == PJ_RBCOLOR_RED) {
+ temp->color = PJ_RBCOLOR_BLACK;
+ node = parent;
+ node->color = PJ_RBCOLOR_BLACK;
+ node = node->parent;
+ node->color = PJ_RBCOLOR_RED;
+ } else {
+ if (node == parent->left) {
+ node = parent;
+ right_rotate(tree, node);
+ }
+ temp = node->parent;
+ temp->color = PJ_RBCOLOR_BLACK;
+ temp = temp->parent;
+ temp->color = PJ_RBCOLOR_RED;
+ left_rotate(tree, temp);
+ }
+ }
+ }
+
+ tree->root->color = PJ_RBCOLOR_BLACK;
+}
+
+
+static void delete_fixup( pj_rbtree *tree, pj_rbtree_node *node )
+{
+ pj_rbtree_node *temp;
+
+ PJ_CHECK_STACK();
+
+ while (node != tree->root && node->color == PJ_RBCOLOR_BLACK) {
+ if (node->parent->left == node) {
+ temp = node->parent->right;
+ if (temp->color == PJ_RBCOLOR_RED) {
+ temp->color = PJ_RBCOLOR_BLACK;
+ node->parent->color = PJ_RBCOLOR_RED;
+ left_rotate(tree, node->parent);
+ temp = node->parent->right;
+ }
+ if (temp->left->color == PJ_RBCOLOR_BLACK &&
+ temp->right->color == PJ_RBCOLOR_BLACK)
+ {
+ temp->color = PJ_RBCOLOR_RED;
+ node = node->parent;
+ } else {
+ if (temp->right->color == PJ_RBCOLOR_BLACK) {
+ temp->left->color = PJ_RBCOLOR_BLACK;
+ temp->color = PJ_RBCOLOR_RED;
+ right_rotate( tree, temp);
+ temp = node->parent->right;
+ }
+ temp->color = node->parent->color;
+ temp->right->color = PJ_RBCOLOR_BLACK;
+ node->parent->color = PJ_RBCOLOR_BLACK;
+ left_rotate(tree, node->parent);
+ node = tree->root;
+ }
+ } else {
+ temp = node->parent->left;
+ if (temp->color == PJ_RBCOLOR_RED) {
+ temp->color = PJ_RBCOLOR_BLACK;
+ node->parent->color = PJ_RBCOLOR_RED;
+ right_rotate( tree, node->parent);
+ temp = node->parent->left;
+ }
+ if (temp->right->color == PJ_RBCOLOR_BLACK &&
+ temp->left->color == PJ_RBCOLOR_BLACK)
+ {
+ temp->color = PJ_RBCOLOR_RED;
+ node = node->parent;
+ } else {
+ if (temp->left->color == PJ_RBCOLOR_BLACK) {
+ temp->right->color = PJ_RBCOLOR_BLACK;
+ temp->color = PJ_RBCOLOR_RED;
+ left_rotate( tree, temp);
+ temp = node->parent->left;
+ }
+ temp->color = node->parent->color;
+ node->parent->color = PJ_RBCOLOR_BLACK;
+ temp->left->color = PJ_RBCOLOR_BLACK;
+ right_rotate(tree, node->parent);
+ node = tree->root;
+ }
+ }
+ }
+
+ node->color = PJ_RBCOLOR_BLACK;
+}
+
+
+PJ_DEF(void) pj_rbtree_init( pj_rbtree *tree, pj_rbtree_comp *comp )
+{
+ PJ_CHECK_STACK();
+
+ tree->null = tree->root = &tree->null_node;
+ tree->null->key = NULL;
+ tree->null->user_data = NULL;
+ tree->size = 0;
+ tree->null->left = tree->null->right = tree->null->parent = tree->null;
+ tree->null->color = PJ_RBCOLOR_BLACK;
+ tree->comp = comp;
+}
+
+PJ_DEF(pj_rbtree_node*) pj_rbtree_first( pj_rbtree *tree )
+{
+ register pj_rbtree_node *node = tree->root;
+ register pj_rbtree_node *null = tree->null;
+
+ PJ_CHECK_STACK();
+
+ while (node->left != null)
+ node = node->left;
+ return node != null ? node : NULL;
+}
+
+PJ_DEF(pj_rbtree_node*) pj_rbtree_last( pj_rbtree *tree )
+{
+ register pj_rbtree_node *node = tree->root;
+ register pj_rbtree_node *null = tree->null;
+
+ PJ_CHECK_STACK();
+
+ while (node->right != null)
+ node = node->right;
+ return node != null ? node : NULL;
+}
+
+PJ_DEF(pj_rbtree_node*) pj_rbtree_next( pj_rbtree *tree,
+ register pj_rbtree_node *node )
+{
+ register pj_rbtree_node *null = tree->null;
+
+ PJ_CHECK_STACK();
+
+ if (node->right != null) {
+ for (node=node->right; node->left!=null; node = node->left)
+ /* void */;
+ } else {
+ register pj_rbtree_node *temp = node->parent;
+ while (temp!=null && temp->right==node) {
+ node = temp;
+ temp = temp->parent;
+ }
+ node = temp;
+ }
+ return node != null ? node : NULL;
+}
+
+PJ_DEF(pj_rbtree_node*) pj_rbtree_prev( pj_rbtree *tree,
+ register pj_rbtree_node *node )
+{
+ register pj_rbtree_node *null = tree->null;
+
+ PJ_CHECK_STACK();
+
+ if (node->left != null) {
+ for (node=node->left; node->right!=null; node=node->right)
+ /* void */;
+ } else {
+ register pj_rbtree_node *temp = node->parent;
+ while (temp!=null && temp->left==node) {
+ node = temp;
+ temp = temp->parent;
+ }
+ node = temp;
+ }
+ return node != null ? node : NULL;
+}
+
+PJ_DEF(int) pj_rbtree_insert( pj_rbtree *tree,
+ pj_rbtree_node *element )
+{
+ int rv = 0;
+ pj_rbtree_node *node, *parent = tree->null,
+ *null = tree->null;
+ pj_rbtree_comp *comp = tree->comp;
+
+ PJ_CHECK_STACK();
+
+ node = tree->root;
+ while (node != null) {
+ rv = (*comp)(element->key, node->key);
+ if (rv == 0) {
+ /* found match, i.e. entry with equal key already exist */
+ return -1;
+ }
+ parent = node;
+ node = rv < 0 ? node->left : node->right;
+ }
+
+ element->color = PJ_RBCOLOR_RED;
+ element->left = element->right = null;
+
+ node = element;
+ if (parent != null) {
+ node->parent = parent;
+ if (rv < 0)
+ parent->left = node;
+ else
+ parent->right = node;
+ insert_fixup( tree, node);
+ } else {
+ tree->root = node;
+ node->parent = null;
+ node->color = PJ_RBCOLOR_BLACK;
+ }
+
+ ++tree->size;
+ return 0;
+}
+
+
+PJ_DEF(pj_rbtree_node*) pj_rbtree_find( pj_rbtree *tree,
+ const void *key )
+{
+ int rv;
+ pj_rbtree_node *node = tree->root;
+ pj_rbtree_node *null = tree->null;
+ pj_rbtree_comp *comp = tree->comp;
+
+ while (node != null) {
+ rv = (*comp)(key, node->key);
+ if (rv == 0)
+ return node;
+ node = rv < 0 ? node->left : node->right;
+ }
+ return node != null ? node : NULL;
+}
+
+PJ_DEF(pj_rbtree_node*) pj_rbtree_erase( pj_rbtree *tree,
+ pj_rbtree_node *node )
+{
+ pj_rbtree_node *succ;
+ pj_rbtree_node *null = tree->null;
+ pj_rbtree_node *child;
+ pj_rbtree_node *parent;
+
+ PJ_CHECK_STACK();
+
+ if (node->left == null || node->right == null) {
+ succ = node;
+ } else {
+ for (succ=node->right; succ->left!=null; succ=succ->left)
+ /* void */;
+ }
+
+ child = succ->left != null ? succ->left : succ->right;
+ parent = succ->parent;
+ child->parent = parent;
+
+ if (parent != null) {
+ if (parent->left == succ)
+ parent->left = child;
+ else
+ parent->right = child;
+ } else
+ tree->root = child;
+
+ if (succ != node) {
+ succ->parent = node->parent;
+ succ->left = node->left;
+ succ->right = node->right;
+ succ->color = node->color;
+
+ parent = node->parent;
+ if (parent != null) {
+ if (parent->left==node)
+ parent->left=succ;
+ else
+ parent->right=succ;
+ }
+ if (node->left != null)
+ node->left->parent = succ;;
+ if (node->right != null)
+ node->right->parent = succ;
+
+ if (tree->root == node)
+ tree->root = succ;
+ }
+
+ if (succ->color == PJ_RBCOLOR_BLACK) {
+ if (child != null)
+ delete_fixup(tree, child);
+ tree->null->color = PJ_RBCOLOR_BLACK;
+ }
+
+ --tree->size;
+ return node;
+}
+
+
+PJ_DEF(unsigned) pj_rbtree_max_height( pj_rbtree *tree,
+ pj_rbtree_node *node )
+{
+ unsigned l, r;
+
+ PJ_CHECK_STACK();
+
+ if (node==NULL)
+ node = tree->root;
+
+ l = node->left != tree->null ? pj_rbtree_max_height(tree,node->left)+1 : 0;
+ r = node->right != tree->null ? pj_rbtree_max_height(tree,node->right)+1 : 0;
+ return l > r ? l : r;
+}
+
+PJ_DEF(unsigned) pj_rbtree_min_height( pj_rbtree *tree,
+ pj_rbtree_node *node )
+{
+ unsigned l, r;
+
+ PJ_CHECK_STACK();
+
+ if (node==NULL)
+ node=tree->root;
+
+ l = (node->left != tree->null) ? pj_rbtree_max_height(tree,node->left)+1 : 0;
+ r = (node->right != tree->null) ? pj_rbtree_max_height(tree,node->right)+1 : 0;
+ return l > r ? r : l;
+}
+
+
diff --git a/pjlib/src/pj/sock_bsd.c b/pjlib/src/pj/sock_bsd.c
index 8f1fa1df..1904a2ea 100644
--- a/pjlib/src/pj/sock_bsd.c
+++ b/pjlib/src/pj/sock_bsd.c
@@ -1,568 +1,589 @@
-/* $Id$
- */
-#include <pj/sock.h>
-#include <pj/os.h>
-#include <pj/assert.h>
-#include <pj/string.h>
-#include <pj/compat/socket.h>
-#include <pj/addr_resolv.h>
-#include <pj/errno.h>
-
-/*
- * Address families conversion.
- * The values here are indexed based on pj_addr_family-0xFF00.
- */
-const pj_uint16_t PJ_AF_UNIX = AF_UNIX;
-const pj_uint16_t PJ_AF_INET = AF_INET;
-const pj_uint16_t PJ_AF_INET6 = AF_INET6;
-#ifdef AF_PACKET
-const pj_uint16_t PJ_AF_PACKET = AF_PACKET;
-#else
-const pj_uint16_t PJ_AF_PACKET = 0xFFFF;
-#endif
-#ifdef AF_IRDA
-const pj_uint16_t PJ_AF_IRDA = AF_IRDA;
-#else
-const pj_uint16_t PJ_AF_IRDA = 0xFFFF;
-#endif
-
-/*
- * Socket types conversion.
- * The values here are indexed based on pj_sock_type-0xFF00
- */
-const pj_uint16_t PJ_SOCK_STREAM = SOCK_STREAM;
-const pj_uint16_t PJ_SOCK_DGRAM = SOCK_DGRAM;
-const pj_uint16_t PJ_SOCK_RAW = SOCK_RAW;
-const pj_uint16_t PJ_SOCK_RDM = SOCK_RDM;
-
-/*
- * Socket level values.
- */
-const pj_uint16_t PJ_SOL_SOCKET = SOL_SOCKET;
-#ifdef SOL_IP
-const pj_uint16_t PJ_SOL_IP = SOL_IP;
-#else
-const pj_uint16_t PJ_SOL_IP = 0xFFFF;
-#endif /* SOL_IP */
-#if defined(SOL_TCP)
-const pj_uint16_t PJ_SOL_TCP = SOL_TCP;
-#elif defined(IPPROTO_TCP)
-const pj_uint16_t PJ_SOL_TCP = IPPROTO_TCP;
-#endif /* SOL_TCP */
-#ifdef SOL_UDP
-const pj_uint16_t PJ_SOL_UDP = SOL_UDP;
-#else
-const pj_uint16_t PJ_SOL_UDP = 0xFFFF;
-#endif
-#ifdef SOL_IPV6
-const pj_uint16_t PJ_SOL_IPV6 = SOL_IPV6;
-#else
-const pj_uint16_t PJ_SOL_IPV6 = 0xFFFF;
-#endif
-
-/* optname values. */
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/sock.h>
+#include <pj/os.h>
+#include <pj/assert.h>
+#include <pj/string.h>
+#include <pj/compat/socket.h>
+#include <pj/addr_resolv.h>
+#include <pj/errno.h>
+
+/*
+ * Address families conversion.
+ * The values here are indexed based on pj_addr_family-0xFF00.
+ */
+const pj_uint16_t PJ_AF_UNIX = AF_UNIX;
+const pj_uint16_t PJ_AF_INET = AF_INET;
+const pj_uint16_t PJ_AF_INET6 = AF_INET6;
+#ifdef AF_PACKET
+const pj_uint16_t PJ_AF_PACKET = AF_PACKET;
+#else
+const pj_uint16_t PJ_AF_PACKET = 0xFFFF;
+#endif
+#ifdef AF_IRDA
+const pj_uint16_t PJ_AF_IRDA = AF_IRDA;
+#else
+const pj_uint16_t PJ_AF_IRDA = 0xFFFF;
+#endif
+
+/*
+ * Socket types conversion.
+ * The values here are indexed based on pj_sock_type-0xFF00
+ */
+const pj_uint16_t PJ_SOCK_STREAM = SOCK_STREAM;
+const pj_uint16_t PJ_SOCK_DGRAM = SOCK_DGRAM;
+const pj_uint16_t PJ_SOCK_RAW = SOCK_RAW;
+const pj_uint16_t PJ_SOCK_RDM = SOCK_RDM;
+
+/*
+ * Socket level values.
+ */
+const pj_uint16_t PJ_SOL_SOCKET = SOL_SOCKET;
+#ifdef SOL_IP
+const pj_uint16_t PJ_SOL_IP = SOL_IP;
+#else
+const pj_uint16_t PJ_SOL_IP = 0xFFFF;
+#endif /* SOL_IP */
+#if defined(SOL_TCP)
+const pj_uint16_t PJ_SOL_TCP = SOL_TCP;
+#elif defined(IPPROTO_TCP)
+const pj_uint16_t PJ_SOL_TCP = IPPROTO_TCP;
+#endif /* SOL_TCP */
+#ifdef SOL_UDP
+const pj_uint16_t PJ_SOL_UDP = SOL_UDP;
+#else
+const pj_uint16_t PJ_SOL_UDP = 0xFFFF;
+#endif
+#ifdef SOL_IPV6
+const pj_uint16_t PJ_SOL_IPV6 = SOL_IPV6;
+#else
+const pj_uint16_t PJ_SOL_IPV6 = 0xFFFF;
+#endif
+
+/* optname values. */
const pj_uint16_t PJ_SO_TYPE = SO_TYPE;
const pj_uint16_t PJ_SO_RCVBUF = SO_RCVBUF;
const pj_uint16_t PJ_SO_SNDBUF = SO_SNDBUF;
-
-/*
- * Convert 16-bit value from network byte order to host byte order.
- */
-PJ_DEF(pj_uint16_t) pj_ntohs(pj_uint16_t netshort)
-{
- return ntohs(netshort);
-}
-
-/*
- * Convert 16-bit value from host byte order to network byte order.
- */
-PJ_DEF(pj_uint16_t) pj_htons(pj_uint16_t hostshort)
-{
- return htons(hostshort);
-}
-
-/*
- * Convert 32-bit value from network byte order to host byte order.
- */
-PJ_DEF(pj_uint32_t) pj_ntohl(pj_uint32_t netlong)
-{
- return ntohl(netlong);
-}
-
-/*
- * Convert 32-bit value from host byte order to network byte order.
- */
-PJ_DEF(pj_uint32_t) pj_htonl(pj_uint32_t hostlong)
-{
- return htonl(hostlong);
-}
-
-/*
- * Convert an Internet host address given in network byte order
- * to string in standard numbers and dots notation.
- */
-PJ_DEF(char*) pj_inet_ntoa(pj_in_addr inaddr)
+
+/*
+ * Convert 16-bit value from network byte order to host byte order.
+ */
+PJ_DEF(pj_uint16_t) pj_ntohs(pj_uint16_t netshort)
+{
+ return ntohs(netshort);
+}
+
+/*
+ * Convert 16-bit value from host byte order to network byte order.
+ */
+PJ_DEF(pj_uint16_t) pj_htons(pj_uint16_t hostshort)
+{
+ return htons(hostshort);
+}
+
+/*
+ * Convert 32-bit value from network byte order to host byte order.
+ */
+PJ_DEF(pj_uint32_t) pj_ntohl(pj_uint32_t netlong)
+{
+ return ntohl(netlong);
+}
+
+/*
+ * Convert 32-bit value from host byte order to network byte order.
+ */
+PJ_DEF(pj_uint32_t) pj_htonl(pj_uint32_t hostlong)
+{
+ return htonl(hostlong);
+}
+
+/*
+ * Convert an Internet host address given in network byte order
+ * to string in standard numbers and dots notation.
+ */
+PJ_DEF(char*) pj_inet_ntoa(pj_in_addr inaddr)
{
#if !defined(PJ_LINUX) && !defined(PJ_LINUX_KERNEL)
return inet_ntoa(*(struct in_addr*)&inaddr);
-#else
- struct in_addr addr;
- addr.s_addr = inaddr.s_addr;
+#else
+ struct in_addr addr;
+ addr.s_addr = inaddr.s_addr;
return inet_ntoa(addr);
-#endif
-}
-
-/*
- * This function converts the Internet host address cp from the standard
- * numbers-and-dots notation into binary data and stores it in the structure
- * that inp points to.
- */
-PJ_DEF(int) pj_inet_aton(const pj_str_t *cp, struct pj_in_addr *inp)
-{
- char tempaddr[16];
-
- /* Initialize output with PJ_INADDR_NONE.
- * Some apps relies on this instead of the return value
- * (and anyway the return value is quite confusing!)
- */
- inp->s_addr = PJ_INADDR_NONE;
-
- /* Caution:
- * this function might be called with cp->slen >= 16
- * (i.e. when called with hostname to check if it's an IP addr).
- */
- PJ_ASSERT_RETURN(cp && cp->slen && inp, 0);
- if (cp->slen >= 16) {
- return 0;
- }
-
- pj_memcpy(tempaddr, cp->ptr, cp->slen);
- tempaddr[cp->slen] = '\0';
-
-#if defined(PJ_SOCK_HAS_INET_ATON) && PJ_SOCK_HAS_INET_ATON != 0
- return inet_aton(tempaddr, (struct in_addr*)inp);
-#else
- inp->s_addr = inet_addr(tempaddr);
- return inp->s_addr == PJ_INADDR_NONE ? 0 : 1;
-#endif
-}
-
-/*
- * Convert address string with numbers and dots to binary IP address.
- */
-PJ_DEF(pj_in_addr) pj_inet_addr(const pj_str_t *cp)
-{
- pj_in_addr addr;
-
- pj_inet_aton(cp, &addr);
- return addr;
-}
-
-/*
- * Set the IP address of an IP socket address from string address,
- * with resolving the host if necessary. The string address may be in a
- * standard numbers and dots notation or may be a hostname. If hostname
- * is specified, then the function will resolve the host into the IP
- * address.
- */
-PJ_DEF(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr,
- const pj_str_t *str_addr)
-{
- PJ_CHECK_STACK();
-
- PJ_ASSERT_RETURN(str_addr && str_addr->slen < PJ_MAX_HOSTNAME,
- (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL));
-
- addr->sin_family = AF_INET;
-
- if (str_addr && str_addr->slen) {
- addr->sin_addr = pj_inet_addr(str_addr);
- if (addr->sin_addr.s_addr == PJ_INADDR_NONE) {
- pj_hostent he;
- pj_status_t rc;
-
- rc = pj_gethostbyname(str_addr, &he);
- if (rc == 0) {
- addr->sin_addr.s_addr = *(pj_uint32_t*)he.h_addr;
- } else {
- addr->sin_addr.s_addr = PJ_INADDR_NONE;
- return rc;
- }
- }
-
- } else {
- addr->sin_addr.s_addr = 0;
- }
-
- return PJ_SUCCESS;
-}
-
-/*
- * Set the IP address and port of an IP socket address.
- * The string address may be in a standard numbers and dots notation or
- * may be a hostname. If hostname is specified, then the function will
- * resolve the host into the IP address.
- */
-PJ_DEF(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr,
- const pj_str_t *str_addr,
- pj_uint16_t port)
-{
- PJ_ASSERT_RETURN(addr && str_addr,
- (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL));
-
- addr->sin_family = PJ_AF_INET;
- pj_sockaddr_in_set_port(addr, port);
- return pj_sockaddr_in_set_str_addr(addr, str_addr);
-}
-
-
-/*
- * Get hostname.
- */
-PJ_DEF(const pj_str_t*) pj_gethostname(void)
-{
- static char buf[PJ_MAX_HOSTNAME];
- static pj_str_t hostname;
-
- PJ_CHECK_STACK();
-
- if (hostname.ptr == NULL) {
- hostname.ptr = buf;
- if (gethostname(buf, sizeof(buf)) != 0) {
- hostname.ptr[0] = '\0';
- hostname.slen = 0;
- } else {
- hostname.slen = strlen(buf);
- }
- }
- return &hostname;
-}
-
-/*
- * Get first IP address associated with the hostname.
- */
-PJ_DEF(pj_in_addr) pj_gethostaddr(void)
-{
- pj_sockaddr_in addr;
- const pj_str_t *hostname = pj_gethostname();
-
- pj_sockaddr_in_set_str_addr(&addr, hostname);
- return addr.sin_addr;
-}
-
-
-#if defined(PJ_WIN32)
-/*
- * Create new socket/endpoint for communication and returns a descriptor.
- */
-PJ_DEF(pj_status_t) pj_sock_socket(int af,
- int type,
- int proto,
- pj_sock_t *sock)
-{
- PJ_CHECK_STACK();
-
- /* Sanity checks. */
- PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL);
- PJ_ASSERT_RETURN((unsigned)PJ_INVALID_SOCKET==INVALID_SOCKET,
- (*sock=PJ_INVALID_SOCKET, PJ_EINVAL));
-
- *sock = WSASocket(af, type, proto, NULL, 0, WSA_FLAG_OVERLAPPED);
-
- if (*sock == PJ_INVALID_SOCKET)
- return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
- else
- return PJ_SUCCESS;
-}
-
-#else
-/*
- * Create new socket/endpoint for communication and returns a descriptor.
- */
-PJ_DEF(pj_status_t) pj_sock_socket(int af,
- int type,
- int proto,
- pj_sock_t *sock)
-{
-
- PJ_CHECK_STACK();
-
- /* Sanity checks. */
- PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL);
- PJ_ASSERT_RETURN(PJ_INVALID_SOCKET==-1,
- (*sock=PJ_INVALID_SOCKET, PJ_EINVAL));
-
- *sock = socket(af, type, proto);
- if (*sock == PJ_INVALID_SOCKET)
- return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
- else
- return PJ_SUCCESS;
-}
-#endif
-
-
-/*
- * Bind socket.
- */
-PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sock,
- const pj_sockaddr_t *addr,
- int len)
-{
- PJ_CHECK_STACK();
-
- PJ_ASSERT_RETURN(addr && len > 0, PJ_EINVAL);
-
- if (bind(sock, (struct sockaddr*)addr, len) != 0)
- return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
- else
- return PJ_SUCCESS;
-}
-
-
-/*
- * Bind socket.
- */
-PJ_DEF(pj_status_t) pj_sock_bind_in( pj_sock_t sock,
- pj_uint32_t addr32,
- pj_uint16_t port)
-{
- pj_sockaddr_in addr;
-
- PJ_CHECK_STACK();
-
- addr.sin_family = PJ_AF_INET;
- addr.sin_addr.s_addr = pj_htonl(addr32);
- addr.sin_port = pj_htons(port);
-
- return pj_sock_bind(sock, &addr, sizeof(pj_sockaddr_in));
-}
-
-
-/*
- * Close socket.
- */
-PJ_DEF(pj_status_t) pj_sock_close(pj_sock_t sock)
-{
- int rc;
-
- PJ_CHECK_STACK();
-#if defined(PJ_WIN32) && PJ_WIN32==1
- rc = closesocket(sock);
-#else
- rc = close(sock);
-#endif
-
- if (rc != 0)
- return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
- else
- return PJ_SUCCESS;
-}
-
-/*
- * Get remote's name.
- */
-PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sock,
- pj_sockaddr_t *addr,
- int *namelen)
-{
- PJ_CHECK_STACK();
- if (getpeername(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)
- return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
- else
- return PJ_SUCCESS;
-}
-
-/*
- * Get socket name.
- */
-PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sock,
- pj_sockaddr_t *addr,
- int *namelen)
-{
- PJ_CHECK_STACK();
- if (getsockname(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)
- return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
- else
- return PJ_SUCCESS;
-}
-
-/*
- * Send data
- */
-PJ_DEF(pj_status_t) pj_sock_send(pj_sock_t sock,
- const void *buf,
- pj_ssize_t *len,
- unsigned flags)
-{
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(len, PJ_EINVAL);
-
- *len = send(sock, (const char*)buf, *len, flags);
-
- if (*len < 0)
- return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
- else
- return PJ_SUCCESS;
-}
-
-
-/*
- * Send data.
- */
-PJ_DEF(pj_status_t) pj_sock_sendto(pj_sock_t sock,
- const void *buf,
- pj_ssize_t *len,
- unsigned flags,
- const pj_sockaddr_t *to,
- int tolen)
-{
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(len, PJ_EINVAL);
-
- *len = sendto(sock, (const char*)buf, *len, flags,
- (const struct sockaddr*)to, tolen);
-
- if (*len < 0)
- return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
- else
- return PJ_SUCCESS;
-}
-
-/*
- * Receive data.
- */
-PJ_DEF(pj_status_t) pj_sock_recv(pj_sock_t sock,
- void *buf,
- pj_ssize_t *len,
- unsigned flags)
-{
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);
-
- *len = recv(sock, (char*)buf, *len, flags);
-
- if (*len < 0)
- return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
- else
- return PJ_SUCCESS;
-}
-
-/*
- * Receive data.
- */
-PJ_DEF(pj_status_t) pj_sock_recvfrom(pj_sock_t sock,
- void *buf,
- pj_ssize_t *len,
- unsigned flags,
- pj_sockaddr_t *from,
- int *fromlen)
-{
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);
- PJ_ASSERT_RETURN(from && fromlen, (*len=-1, PJ_EINVAL));
-
- *len = recvfrom(sock, (char*)buf, *len, flags,
- (struct sockaddr*)from, (socklen_t*)fromlen);
-
- if (*len < 0)
- return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
- else
- return PJ_SUCCESS;
-}
-
-/*
- * Get socket option.
- */
-PJ_DEF(pj_status_t) pj_sock_getsockopt( pj_sock_t sock,
- pj_uint16_t level,
- pj_uint16_t optname,
- void *optval,
- int *optlen)
-{
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(optval && optlen, PJ_EINVAL);
-
- if (getsockopt(sock, level, optname, (char*)optval, (socklen_t*)optlen)!=0)
- return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
- else
- return PJ_SUCCESS;
-}
-
-/*
- * Set socket option.
- */
-PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sock,
- pj_uint16_t level,
- pj_uint16_t optname,
- const void *optval,
- int optlen)
-{
- PJ_CHECK_STACK();
- if (setsockopt(sock, level, optname, (const char*)optval, optlen) != 0)
- return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
- else
- return PJ_SUCCESS;
-}
-
-/*
- * Shutdown socket.
- */
-#if PJ_HAS_TCP
-PJ_DEF(pj_status_t) pj_sock_shutdown( pj_sock_t sock,
- int how)
-{
- PJ_CHECK_STACK();
- if (shutdown(sock, how) != 0)
- return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
- else
- return PJ_SUCCESS;
-}
-
-/*
- * Start listening to incoming connections.
- */
-PJ_DEF(pj_status_t) pj_sock_listen( pj_sock_t sock,
- int backlog)
-{
- PJ_CHECK_STACK();
- if (listen(sock, backlog) != 0)
- return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
- else
- return PJ_SUCCESS;
-}
-
-/*
- * Connect socket.
- */
-PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sock,
- const pj_sockaddr_t *addr,
- int namelen)
-{
- PJ_CHECK_STACK();
- if (connect(sock, (struct sockaddr*)addr, namelen) != 0)
- return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
- else
- return PJ_SUCCESS;
-}
-
-/*
- * Accept incoming connections
- */
-PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t serverfd,
- pj_sock_t *newsock,
- pj_sockaddr_t *addr,
- int *addrlen)
-{
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(newsock != NULL, PJ_EINVAL);
-
- *newsock = accept(serverfd, (struct sockaddr*)addr, (socklen_t*)addrlen);
- if (*newsock==PJ_INVALID_SOCKET)
- return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
- else
- return PJ_SUCCESS;
-}
-#endif /* PJ_HAS_TCP */
-
-
+#endif
+}
+
+/*
+ * This function converts the Internet host address cp from the standard
+ * numbers-and-dots notation into binary data and stores it in the structure
+ * that inp points to.
+ */
+PJ_DEF(int) pj_inet_aton(const pj_str_t *cp, struct pj_in_addr *inp)
+{
+ char tempaddr[16];
+
+ /* Initialize output with PJ_INADDR_NONE.
+ * Some apps relies on this instead of the return value
+ * (and anyway the return value is quite confusing!)
+ */
+ inp->s_addr = PJ_INADDR_NONE;
+
+ /* Caution:
+ * this function might be called with cp->slen >= 16
+ * (i.e. when called with hostname to check if it's an IP addr).
+ */
+ PJ_ASSERT_RETURN(cp && cp->slen && inp, 0);
+ if (cp->slen >= 16) {
+ return 0;
+ }
+
+ pj_memcpy(tempaddr, cp->ptr, cp->slen);
+ tempaddr[cp->slen] = '\0';
+
+#if defined(PJ_SOCK_HAS_INET_ATON) && PJ_SOCK_HAS_INET_ATON != 0
+ return inet_aton(tempaddr, (struct in_addr*)inp);
+#else
+ inp->s_addr = inet_addr(tempaddr);
+ return inp->s_addr == PJ_INADDR_NONE ? 0 : 1;
+#endif
+}
+
+/*
+ * Convert address string with numbers and dots to binary IP address.
+ */
+PJ_DEF(pj_in_addr) pj_inet_addr(const pj_str_t *cp)
+{
+ pj_in_addr addr;
+
+ pj_inet_aton(cp, &addr);
+ return addr;
+}
+
+/*
+ * Set the IP address of an IP socket address from string address,
+ * with resolving the host if necessary. The string address may be in a
+ * standard numbers and dots notation or may be a hostname. If hostname
+ * is specified, then the function will resolve the host into the IP
+ * address.
+ */
+PJ_DEF(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr,
+ const pj_str_t *str_addr)
+{
+ PJ_CHECK_STACK();
+
+ PJ_ASSERT_RETURN(str_addr && str_addr->slen < PJ_MAX_HOSTNAME,
+ (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL));
+
+ addr->sin_family = AF_INET;
+
+ if (str_addr && str_addr->slen) {
+ addr->sin_addr = pj_inet_addr(str_addr);
+ if (addr->sin_addr.s_addr == PJ_INADDR_NONE) {
+ pj_hostent he;
+ pj_status_t rc;
+
+ rc = pj_gethostbyname(str_addr, &he);
+ if (rc == 0) {
+ addr->sin_addr.s_addr = *(pj_uint32_t*)he.h_addr;
+ } else {
+ addr->sin_addr.s_addr = PJ_INADDR_NONE;
+ return rc;
+ }
+ }
+
+ } else {
+ addr->sin_addr.s_addr = 0;
+ }
+
+ return PJ_SUCCESS;
+}
+
+/*
+ * Set the IP address and port of an IP socket address.
+ * The string address may be in a standard numbers and dots notation or
+ * may be a hostname. If hostname is specified, then the function will
+ * resolve the host into the IP address.
+ */
+PJ_DEF(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr,
+ const pj_str_t *str_addr,
+ pj_uint16_t port)
+{
+ PJ_ASSERT_RETURN(addr && str_addr,
+ (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL));
+
+ addr->sin_family = PJ_AF_INET;
+ pj_sockaddr_in_set_port(addr, port);
+ return pj_sockaddr_in_set_str_addr(addr, str_addr);
+}
+
+
+/*
+ * Get hostname.
+ */
+PJ_DEF(const pj_str_t*) pj_gethostname(void)
+{
+ static char buf[PJ_MAX_HOSTNAME];
+ static pj_str_t hostname;
+
+ PJ_CHECK_STACK();
+
+ if (hostname.ptr == NULL) {
+ hostname.ptr = buf;
+ if (gethostname(buf, sizeof(buf)) != 0) {
+ hostname.ptr[0] = '\0';
+ hostname.slen = 0;
+ } else {
+ hostname.slen = strlen(buf);
+ }
+ }
+ return &hostname;
+}
+
+/*
+ * Get first IP address associated with the hostname.
+ */
+PJ_DEF(pj_in_addr) pj_gethostaddr(void)
+{
+ pj_sockaddr_in addr;
+ const pj_str_t *hostname = pj_gethostname();
+
+ pj_sockaddr_in_set_str_addr(&addr, hostname);
+ return addr.sin_addr;
+}
+
+
+#if defined(PJ_WIN32)
+/*
+ * Create new socket/endpoint for communication and returns a descriptor.
+ */
+PJ_DEF(pj_status_t) pj_sock_socket(int af,
+ int type,
+ int proto,
+ pj_sock_t *sock)
+{
+ PJ_CHECK_STACK();
+
+ /* Sanity checks. */
+ PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL);
+ PJ_ASSERT_RETURN((unsigned)PJ_INVALID_SOCKET==INVALID_SOCKET,
+ (*sock=PJ_INVALID_SOCKET, PJ_EINVAL));
+
+ *sock = WSASocket(af, type, proto, NULL, 0, WSA_FLAG_OVERLAPPED);
+
+ if (*sock == PJ_INVALID_SOCKET)
+ return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
+ else
+ return PJ_SUCCESS;
+}
+
+#else
+/*
+ * Create new socket/endpoint for communication and returns a descriptor.
+ */
+PJ_DEF(pj_status_t) pj_sock_socket(int af,
+ int type,
+ int proto,
+ pj_sock_t *sock)
+{
+
+ PJ_CHECK_STACK();
+
+ /* Sanity checks. */
+ PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL);
+ PJ_ASSERT_RETURN(PJ_INVALID_SOCKET==-1,
+ (*sock=PJ_INVALID_SOCKET, PJ_EINVAL));
+
+ *sock = socket(af, type, proto);
+ if (*sock == PJ_INVALID_SOCKET)
+ return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
+ else
+ return PJ_SUCCESS;
+}
+#endif
+
+
+/*
+ * Bind socket.
+ */
+PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sock,
+ const pj_sockaddr_t *addr,
+ int len)
+{
+ PJ_CHECK_STACK();
+
+ PJ_ASSERT_RETURN(addr && len > 0, PJ_EINVAL);
+
+ if (bind(sock, (struct sockaddr*)addr, len) != 0)
+ return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
+ else
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Bind socket.
+ */
+PJ_DEF(pj_status_t) pj_sock_bind_in( pj_sock_t sock,
+ pj_uint32_t addr32,
+ pj_uint16_t port)
+{
+ pj_sockaddr_in addr;
+
+ PJ_CHECK_STACK();
+
+ addr.sin_family = PJ_AF_INET;
+ addr.sin_addr.s_addr = pj_htonl(addr32);
+ addr.sin_port = pj_htons(port);
+
+ return pj_sock_bind(sock, &addr, sizeof(pj_sockaddr_in));
+}
+
+
+/*
+ * Close socket.
+ */
+PJ_DEF(pj_status_t) pj_sock_close(pj_sock_t sock)
+{
+ int rc;
+
+ PJ_CHECK_STACK();
+#if defined(PJ_WIN32) && PJ_WIN32==1
+ rc = closesocket(sock);
+#else
+ rc = close(sock);
+#endif
+
+ if (rc != 0)
+ return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
+ else
+ return PJ_SUCCESS;
+}
+
+/*
+ * Get remote's name.
+ */
+PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sock,
+ pj_sockaddr_t *addr,
+ int *namelen)
+{
+ PJ_CHECK_STACK();
+ if (getpeername(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)
+ return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
+ else
+ return PJ_SUCCESS;
+}
+
+/*
+ * Get socket name.
+ */
+PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sock,
+ pj_sockaddr_t *addr,
+ int *namelen)
+{
+ PJ_CHECK_STACK();
+ if (getsockname(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)
+ return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
+ else
+ return PJ_SUCCESS;
+}
+
+/*
+ * Send data
+ */
+PJ_DEF(pj_status_t) pj_sock_send(pj_sock_t sock,
+ const void *buf,
+ pj_ssize_t *len,
+ unsigned flags)
+{
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(len, PJ_EINVAL);
+
+ *len = send(sock, (const char*)buf, *len, flags);
+
+ if (*len < 0)
+ return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
+ else
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Send data.
+ */
+PJ_DEF(pj_status_t) pj_sock_sendto(pj_sock_t sock,
+ const void *buf,
+ pj_ssize_t *len,
+ unsigned flags,
+ const pj_sockaddr_t *to,
+ int tolen)
+{
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(len, PJ_EINVAL);
+
+ *len = sendto(sock, (const char*)buf, *len, flags,
+ (const struct sockaddr*)to, tolen);
+
+ if (*len < 0)
+ return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
+ else
+ return PJ_SUCCESS;
+}
+
+/*
+ * Receive data.
+ */
+PJ_DEF(pj_status_t) pj_sock_recv(pj_sock_t sock,
+ void *buf,
+ pj_ssize_t *len,
+ unsigned flags)
+{
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);
+
+ *len = recv(sock, (char*)buf, *len, flags);
+
+ if (*len < 0)
+ return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
+ else
+ return PJ_SUCCESS;
+}
+
+/*
+ * Receive data.
+ */
+PJ_DEF(pj_status_t) pj_sock_recvfrom(pj_sock_t sock,
+ void *buf,
+ pj_ssize_t *len,
+ unsigned flags,
+ pj_sockaddr_t *from,
+ int *fromlen)
+{
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);
+ PJ_ASSERT_RETURN(from && fromlen, (*len=-1, PJ_EINVAL));
+
+ *len = recvfrom(sock, (char*)buf, *len, flags,
+ (struct sockaddr*)from, (socklen_t*)fromlen);
+
+ if (*len < 0)
+ return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
+ else
+ return PJ_SUCCESS;
+}
+
+/*
+ * Get socket option.
+ */
+PJ_DEF(pj_status_t) pj_sock_getsockopt( pj_sock_t sock,
+ pj_uint16_t level,
+ pj_uint16_t optname,
+ void *optval,
+ int *optlen)
+{
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(optval && optlen, PJ_EINVAL);
+
+ if (getsockopt(sock, level, optname, (char*)optval, (socklen_t*)optlen)!=0)
+ return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
+ else
+ return PJ_SUCCESS;
+}
+
+/*
+ * Set socket option.
+ */
+PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sock,
+ pj_uint16_t level,
+ pj_uint16_t optname,
+ const void *optval,
+ int optlen)
+{
+ PJ_CHECK_STACK();
+ if (setsockopt(sock, level, optname, (const char*)optval, optlen) != 0)
+ return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
+ else
+ return PJ_SUCCESS;
+}
+
+/*
+ * Shutdown socket.
+ */
+#if PJ_HAS_TCP
+PJ_DEF(pj_status_t) pj_sock_shutdown( pj_sock_t sock,
+ int how)
+{
+ PJ_CHECK_STACK();
+ if (shutdown(sock, how) != 0)
+ return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
+ else
+ return PJ_SUCCESS;
+}
+
+/*
+ * Start listening to incoming connections.
+ */
+PJ_DEF(pj_status_t) pj_sock_listen( pj_sock_t sock,
+ int backlog)
+{
+ PJ_CHECK_STACK();
+ if (listen(sock, backlog) != 0)
+ return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
+ else
+ return PJ_SUCCESS;
+}
+
+/*
+ * Connect socket.
+ */
+PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sock,
+ const pj_sockaddr_t *addr,
+ int namelen)
+{
+ PJ_CHECK_STACK();
+ if (connect(sock, (struct sockaddr*)addr, namelen) != 0)
+ return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
+ else
+ return PJ_SUCCESS;
+}
+
+/*
+ * Accept incoming connections
+ */
+PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t serverfd,
+ pj_sock_t *newsock,
+ pj_sockaddr_t *addr,
+ int *addrlen)
+{
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(newsock != NULL, PJ_EINVAL);
+
+ *newsock = accept(serverfd, (struct sockaddr*)addr, (socklen_t*)addrlen);
+ if (*newsock==PJ_INVALID_SOCKET)
+ return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
+ else
+ return PJ_SUCCESS;
+}
+#endif /* PJ_HAS_TCP */
+
+
diff --git a/pjlib/src/pj/sock_linux_kernel.c b/pjlib/src/pj/sock_linux_kernel.c
index d7924f91..75e272db 100644
--- a/pjlib/src/pj/sock_linux_kernel.c
+++ b/pjlib/src/pj/sock_linux_kernel.c
@@ -1,739 +1,760 @@
-/* $Id$
- *
- */
-#include <pj/sock.h>
-#include <pj/assert.h>
-#include <pj/string.h> /* pj_memcpy() */
-#include <pj/os.h> /* PJ_CHECK_STACK() */
-#include <pj/addr_resolv.h> /* pj_gethostbyname() */
-#include <pj/ctype.h>
-#include <pj/compat/sprintf.h>
-#include <pj/log.h>
-#include <pj/errno.h>
-
-/* Linux kernel specific. */
-#include <linux/socket.h>
-#include <linux/net.h>
-//#include <net/sock.h>
-#include <linux/security.h>
-#include <linux/syscalls.h> /* sys_xxx() */
-#include <asm/ioctls.h> /* FIONBIO */
-#include <linux/utsname.h> /* for pj_gethostname() */
-
-/*
- * Address families conversion.
- * The values here are indexed based on pj_addr_family-0xFF00.
- */
-const pj_uint16_t PJ_AF_UNIX = AF_UNIX;
-const pj_uint16_t PJ_AF_INET = AF_INET;
-const pj_uint16_t PJ_AF_INET6 = AF_INET6;
-#ifdef AF_PACKET
-const pj_uint16_t PJ_AF_PACKET = AF_PACKET;
-#else
-# error "AF_PACKET undeclared!"
-#endif
-#ifdef AF_IRDA
-const pj_uint16_t PJ_AF_IRDA = AF_IRDA;
-#else
-# error "AF_IRDA undeclared!"
-#endif
-
-/*
- * Socket types conversion.
- * The values here are indexed based on pj_sock_type-0xFF00
- */
-const pj_uint16_t PJ_SOCK_STREAM= SOCK_STREAM;
-const pj_uint16_t PJ_SOCK_DGRAM = SOCK_DGRAM;
-const pj_uint16_t PJ_SOCK_RAW = SOCK_RAW;
-const pj_uint16_t PJ_SOCK_RDM = SOCK_RDM;
-
-/*
- * Socket level values.
- */
-const pj_uint16_t PJ_SOL_SOCKET = SOL_SOCKET;
-#ifdef SOL_IP
-const pj_uint16_t PJ_SOL_IP = SOL_IP;
-#else
-# error "SOL_IP undeclared!"
-#endif /* SOL_IP */
-#if defined(SOL_TCP)
-const pj_uint16_t PJ_SOL_TCP = SOL_TCP;
-#else
-# error "SOL_TCP undeclared!"
-#endif /* SOL_TCP */
-#ifdef SOL_UDP
-const pj_uint16_t PJ_SOL_UDP = SOL_UDP;
-#else
-# error "SOL_UDP undeclared!"
-#endif
-#ifdef SOL_IPV6
-const pj_uint16_t PJ_SOL_IPV6 = SOL_IPV6;
-#else
-# error "SOL_IPV6 undeclared!"
-#endif
+/* $Id$
+ *
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/sock.h>
+#include <pj/assert.h>
+#include <pj/string.h> /* pj_memcpy() */
+#include <pj/os.h> /* PJ_CHECK_STACK() */
+#include <pj/addr_resolv.h> /* pj_gethostbyname() */
+#include <pj/ctype.h>
+#include <pj/compat/sprintf.h>
+#include <pj/log.h>
+#include <pj/errno.h>
+
+/* Linux kernel specific. */
+#include <linux/socket.h>
+#include <linux/net.h>
+//#include <net/sock.h>
+#include <linux/security.h>
+#include <linux/syscalls.h> /* sys_xxx() */
+#include <asm/ioctls.h> /* FIONBIO */
+#include <linux/utsname.h> /* for pj_gethostname() */
+
+/*
+ * Address families conversion.
+ * The values here are indexed based on pj_addr_family-0xFF00.
+ */
+const pj_uint16_t PJ_AF_UNIX = AF_UNIX;
+const pj_uint16_t PJ_AF_INET = AF_INET;
+const pj_uint16_t PJ_AF_INET6 = AF_INET6;
+#ifdef AF_PACKET
+const pj_uint16_t PJ_AF_PACKET = AF_PACKET;
+#else
+# error "AF_PACKET undeclared!"
+#endif
+#ifdef AF_IRDA
+const pj_uint16_t PJ_AF_IRDA = AF_IRDA;
+#else
+# error "AF_IRDA undeclared!"
+#endif
+
+/*
+ * Socket types conversion.
+ * The values here are indexed based on pj_sock_type-0xFF00
+ */
+const pj_uint16_t PJ_SOCK_STREAM= SOCK_STREAM;
+const pj_uint16_t PJ_SOCK_DGRAM = SOCK_DGRAM;
+const pj_uint16_t PJ_SOCK_RAW = SOCK_RAW;
+const pj_uint16_t PJ_SOCK_RDM = SOCK_RDM;
+
+/*
+ * Socket level values.
+ */
+const pj_uint16_t PJ_SOL_SOCKET = SOL_SOCKET;
+#ifdef SOL_IP
+const pj_uint16_t PJ_SOL_IP = SOL_IP;
+#else
+# error "SOL_IP undeclared!"
+#endif /* SOL_IP */
+#if defined(SOL_TCP)
+const pj_uint16_t PJ_SOL_TCP = SOL_TCP;
+#else
+# error "SOL_TCP undeclared!"
+#endif /* SOL_TCP */
+#ifdef SOL_UDP
+const pj_uint16_t PJ_SOL_UDP = SOL_UDP;
+#else
+# error "SOL_UDP undeclared!"
+#endif
+#ifdef SOL_IPV6
+const pj_uint16_t PJ_SOL_IPV6 = SOL_IPV6;
+#else
+# error "SOL_IPV6 undeclared!"
+#endif
/* optname values. */
const pj_uint16_t PJ_SO_TYPE = SO_TYPE;
const pj_uint16_t PJ_SO_RCVBUF = SO_RCVBUF;
const pj_uint16_t PJ_SO_SNDBUF = SO_SNDBUF;
-
-/*
- * Convert 16-bit value from network byte order to host byte order.
- */
-PJ_DEF(pj_uint16_t) pj_ntohs(pj_uint16_t netshort)
-{
- return ntohs(netshort);
-}
-
-/*
- * Convert 16-bit value from host byte order to network byte order.
- */
-PJ_DEF(pj_uint16_t) pj_htons(pj_uint16_t hostshort)
-{
- return htons(hostshort);
-}
-
-/*
- * Convert 32-bit value from network byte order to host byte order.
- */
-PJ_DEF(pj_uint32_t) pj_ntohl(pj_uint32_t netlong)
-{
- return ntohl(netlong);
-}
-
-/*
- * Convert 32-bit value from host byte order to network byte order.
- */
-PJ_DEF(pj_uint32_t) pj_htonl(pj_uint32_t hostlong)
-{
- return htonl(hostlong);
-}
-
-/*
- * Convert an Internet host address given in network byte order
- * to string in standard numbers and dots notation.
- */
-PJ_DEF(char*) pj_inet_ntoa(pj_in_addr in)
-{
-#define UC(b) (((int)b)&0xff)
- static char b[18];
- char *p;
-
- p = (char *)&in;
- pj_snprintf(b, sizeof(b), "%d.%d.%d.%d",
- UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3]));
-
- return b;
-}
-
-/*
- * This function converts the Internet host address ccp from the standard
- * numbers-and-dots notation into binary data and stores it in the structure
- * that inp points to.
- */
-PJ_DEF(int) pj_inet_aton(const pj_str_t *ccp, struct pj_in_addr *addr)
-{
- pj_uint32_t val;
- int base, n;
- char c;
- unsigned parts[4];
- unsigned *pp = parts;
- char cp_copy[18];
- char *cp = cp_copy;
-
- addr->s_addr = PJ_INADDR_NONE;
-
- if (ccp->slen > 15) return 0;
-
- pj_memcpy(cp, ccp->ptr, ccp->slen);
- cp[ccp->slen] = '\0';
-
- c = *cp;
- for (;;) {
- /*
- * Collect number up to ``.''.
- * Values are specified as for C:
- * 0x=hex, 0=octal, isdigit=decimal.
- */
- if (!pj_isdigit((int)c))
- return (0);
- val = 0; base = 10;
- if (c == '0') {
- c = *++cp;
- if (c == 'x' || c == 'X')
- base = 16, c = *++cp;
- else
- base = 8;
- }
-
- for (;;) {
- if (pj_isascii((int)c) && pj_isdigit((int)c)) {
- val = (val * base) + (c - '0');
- c = *++cp;
- } else if (base==16 && pj_isascii((int)c) && pj_isxdigit((int)c)) {
- val = (val << 4) |
- (c + 10 - (pj_islower((int)c) ? 'a' : 'A'));
- c = *++cp;
- } else
- break;
- }
-
- if (c == '.') {
- /*
- * Internet format:
- * a.b.c.d
- * a.b.c (with c treated as 16 bits)
- * a.b (with b treated as 24 bits)
- */
- if (pp >= parts + 3)
- return (0);
- *pp++ = val;
- c = *++cp;
- } else
- break;
- }
-
- /*
- * Check for trailing characters.
- */
- if (c != '\0' && (!pj_isascii((int)c) || !pj_isspace((int)c)))
- return (0);
- /*
- * Concoct the address according to
- * the number of parts specified.
- */
- n = pp - parts + 1;
- switch (n) {
- case 0:
- return (0); /* initial nondigit */
- case 1: /* a -- 32 bits */
- break;
- case 2: /* a.b -- 8.24 bits */
- if (val > 0xffffff)
- return (0);
- val |= parts[0] << 24;
- break;
- case 3: /* a.b.c -- 8.8.16 bits */
- if (val > 0xffff)
- return (0);
- val |= (parts[0] << 24) | (parts[1] << 16);
- break;
- case 4: /* a.b.c.d -- 8.8.8.8 bits */
- if (val > 0xff)
- return (0);
- val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
- break;
- }
-
- if (addr)
- addr->s_addr = pj_htonl(val);
- return (1);
-}
-
-/*
- * Convert address string with numbers and dots to binary IP address.
- */
-PJ_DEF(pj_in_addr) pj_inet_addr(const pj_str_t *cp)
-{
- pj_in_addr addr;
- pj_inet_aton(cp, &addr);
- return addr;
-}
-
-/*
- * Set the IP address of an IP socket address from string address,
- * with resolving the host if necessary. The string address may be in a
- * standard numbers and dots notation or may be a hostname. If hostname
- * is specified, then the function will resolve the host into the IP
- * address.
- */
-PJ_DEF(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr,
- const pj_str_t *str_addr)
-{
- PJ_CHECK_STACK();
-
- pj_assert(str_addr && str_addr->slen < PJ_MAX_HOSTNAME);
-
- addr->sin_family = AF_INET;
-
- if (str_addr && str_addr->slen) {
- addr->sin_addr = pj_inet_addr(str_addr);
- if (addr->sin_addr.s_addr == PJ_INADDR_NONE) {
- pj_hostent he;
- if (pj_gethostbyname(str_addr, &he) == 0) {
- addr->sin_addr.s_addr = *(pj_uint32_t*)he.h_addr;
- } else {
- addr->sin_addr.s_addr = PJ_INADDR_NONE;
- return -1;
- }
- }
-
- } else {
- addr->sin_addr.s_addr = 0;
- }
-
- return PJ_SUCCESS;
-}
-
-/*
- * Set the IP address and port of an IP socket address.
- * The string address may be in a standard numbers and dots notation or
- * may be a hostname. If hostname is specified, then the function will
- * resolve the host into the IP address.
- */
-PJ_DEF(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr,
- const pj_str_t *str_addr,
- pj_uint16_t port)
-{
- pj_assert(addr && str_addr);
-
- addr->sin_family = PJ_AF_INET;
- pj_sockaddr_in_set_port(addr, port);
- return pj_sockaddr_in_set_str_addr(addr, str_addr);
-}
-
-
-/*
- * Get hostname.
- */
-PJ_DEF(const pj_str_t*) pj_gethostname(void)
-{
- static char buf[PJ_MAX_HOSTNAME];
- static pj_str_t hostname;
-
- PJ_CHECK_STACK();
-
- if (hostname.ptr == NULL) {
- hostname.ptr = buf;
- down_read(&uts_sem);
- hostname.slen = strlen(system_utsname.nodename);
- if (hostname.slen > PJ_MAX_HOSTNAME) {
- hostname.ptr[0] = '\0';
- hostname.slen = 0;
- } else {
- pj_memcpy(hostname.ptr, system_utsname.nodename, hostname.slen);
- }
- up_read(&uts_sem);
- }
- return &hostname;
-}
-
-/*
- * Get first IP address associated with the hostname.
- */
-PJ_DEF(pj_in_addr) pj_gethostaddr(void)
-{
- pj_sockaddr_in addr;
- const pj_str_t *hostname = pj_gethostname();
-
- pj_sockaddr_in_set_str_addr(&addr, hostname);
- return addr.sin_addr;
-}
-
-
-/*
- * Create new socket/endpoint for communication and returns a descriptor.
- */
-PJ_DEF(pj_status_t) pj_sock_socket(int af, int type, int proto,
- pj_sock_t *sock_fd)
-{
- long result;
-
- PJ_CHECK_STACK();
-
- /* Sanity checks. */
- PJ_ASSERT_RETURN(PJ_INVALID_SOCKET == -1 && sock_fd != NULL, PJ_EINVAL);
-
- /* Initialize returned socket */
- *sock_fd = PJ_INVALID_SOCKET;
-
- /* Create socket. */
- result = sys_socket(af, type, proto);
- if (result < 0) {
- return PJ_RETURN_OS_ERROR((-result));
- }
-
- *sock_fd = result;
-
- return PJ_SUCCESS;
-}
-
-/*
- * Bind socket.
- */
-PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sockfd,
- const pj_sockaddr_t *addr,
- int len)
-{
- long err;
- mm_segment_t oldfs;
-
- PJ_CHECK_STACK();
-
- PJ_ASSERT_RETURN(addr!=NULL && len >= sizeof(struct pj_sockaddr),
- PJ_EINVAL);
-
- oldfs = get_fs();
- set_fs(KERNEL_DS);
-
- err = sys_bind(sockfd, (struct sockaddr*)addr, len);
-
- set_fs(oldfs);
-
- if (err)
- return PJ_RETURN_OS_ERROR(-err);
- else
- return PJ_SUCCESS;
-}
-
-
-/*
- * Bind socket.
- */
-PJ_DEF(pj_status_t) pj_sock_bind_in( pj_sock_t sockfd,
- pj_uint32_t addr32,
- pj_uint16_t port)
-{
- pj_sockaddr_in addr;
-
- PJ_CHECK_STACK();
-
- addr.sin_family = PJ_AF_INET;
- addr.sin_addr.s_addr = pj_htonl(addr32);
- addr.sin_port = pj_htons(port);
-
- return pj_sock_bind(sockfd, &addr, sizeof(pj_sockaddr_in));
-}
-
-/*
- * Close socket.
- */
-PJ_DEF(pj_status_t) pj_sock_close(pj_sock_t sockfd)
-{
- long err;
-
- err = sys_close(sockfd);
-
- if (err != 0)
- return PJ_RETURN_OS_ERROR(-err);
- else
- return PJ_SUCCESS;
-}
-
-/*
- * Get remote's name.
- */
-PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sockfd,
- pj_sockaddr_t *addr,
- int *namelen)
-{
- mm_segment_t oldfs;
- long err;
-
- PJ_CHECK_STACK();
-
- oldfs = get_fs();
- set_fs(KERNEL_DS);
-
- err = sys_getpeername( sockfd, addr, namelen);
-
- set_fs(oldfs);
-
- if (err)
- return PJ_RETURN_OS_ERROR(-err);
- else
- return PJ_SUCCESS;
-}
-
-/*
- * Get socket name.
- */
-PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sockfd,
- pj_sockaddr_t *addr,
- int *namelen)
-{
- mm_segment_t oldfs;
- int err;
-
- PJ_CHECK_STACK();
-
- oldfs = get_fs();
- set_fs(KERNEL_DS);
-
- err = sys_getsockname( sockfd, addr, namelen );
-
- set_fs(oldfs);
-
- if (err)
- return PJ_RETURN_OS_ERROR(-err);
- else
- return PJ_SUCCESS;
-}
-
-/*
- * Send data
- */
-PJ_DEF(pj_status_t) pj_sock_send( pj_sock_t sockfd,
- const void *buf,
- pj_ssize_t *len,
- unsigned flags)
-{
- return pj_sock_sendto(sockfd, buf, len, flags, NULL, 0);
-}
-
-
-/*
- * Send data.
- */
-PJ_DEF(pj_status_t) pj_sock_sendto( pj_sock_t sockfd,
- const void *buff,
- pj_ssize_t *len,
- unsigned flags,
- const pj_sockaddr_t *addr,
- int addr_len)
-{
- long err;
- mm_segment_t oldfs;
-
- PJ_CHECK_STACK();
-
- oldfs = get_fs();
- set_fs(KERNEL_DS);
-
- err = *len = sys_sendto( sockfd, (void*)buff, *len, flags,
- (void*)addr, addr_len );
-
- set_fs(oldfs);
-
- if (err >= 0) {
- return PJ_SUCCESS;
- }
- else {
- return PJ_RETURN_OS_ERROR(-err);
- }
-}
-
-/*
- * Receive data.
- */
-PJ_DEF(pj_status_t) pj_sock_recv( pj_sock_t sockfd,
- void *buf,
- pj_ssize_t *len,
- unsigned flags)
-{
- return pj_sock_recvfrom(sockfd, buf, len, flags, NULL, NULL);
-}
-
-/*
- * Receive data.
- */
-PJ_DEF(pj_status_t) pj_sock_recvfrom( pj_sock_t sockfd,
- void *buff,
- pj_ssize_t *size,
- unsigned flags,
- pj_sockaddr_t *from,
- int *fromlen)
-{
- mm_segment_t oldfs;
- long err;
-
- PJ_CHECK_STACK();
-
- oldfs = get_fs();
- set_fs(KERNEL_DS);
-
- err = *size = sys_recvfrom( sockfd, buff, *size, flags, from, fromlen);
-
- set_fs(oldfs);
-
- if (err >= 0) {
- return PJ_SUCCESS;
- }
- else {
- return PJ_RETURN_OS_ERROR(-err);
- }
-}
-
-/*
- * Get socket option.
- */
-PJ_DEF(pj_status_t) pj_sock_getsockopt( pj_sock_t sockfd,
- pj_uint16_t level,
- pj_uint16_t optname,
- void *optval,
- int *optlen)
-{
- mm_segment_t oldfs;
- long err;
-
- PJ_CHECK_STACK();
-
- oldfs = get_fs();
- set_fs(KERNEL_DS);
-
- err = sys_getsockopt( sockfd, level, optname, optval, optlen);
-
- set_fs(oldfs);
-
- if (err)
- return PJ_RETURN_OS_ERROR(-err);
- else
- return PJ_SUCCESS;
-}
-
-/*
- * Set socket option.
- */
-PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sockfd,
- pj_uint16_t level,
- pj_uint16_t optname,
- const void *optval,
- int optlen)
-{
- long err;
- mm_segment_t oldfs;
-
- PJ_CHECK_STACK();
-
-
- oldfs = get_fs();
- set_fs(KERNEL_DS);
-
- err = sys_setsockopt( sockfd, level, optname, (void*)optval, optlen);
-
- set_fs(oldfs);
-
- if (err)
- return PJ_RETURN_OS_ERROR(-err);
- else
- return PJ_SUCCESS;
-}
-
-/*
- * Shutdown socket.
- */
-#if PJ_HAS_TCP
-PJ_DEF(pj_status_t) pj_sock_shutdown( pj_sock_t sockfd,
- int how)
-{
- long err;
-
- PJ_CHECK_STACK();
-
- err = sys_shutdown(sockfd, how);
-
- if (err)
- return PJ_RETURN_OS_ERROR(-err);
- else
- return PJ_SUCCESS;
-}
-
-/*
- * Start listening to incoming connections.
- */
-PJ_DEF(pj_status_t) pj_sock_listen( pj_sock_t sockfd,
- int backlog)
-{
- long err;
-
- PJ_CHECK_STACK();
-
- err = sys_listen( sockfd, backlog );
-
- if (err)
- return PJ_RETURN_OS_ERROR(-err);
- else
- return PJ_SUCCESS;
-}
-
-/*
- * Connect socket.
- */
-PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sockfd,
- const pj_sockaddr_t *addr,
- int namelen)
-{
- long err;
- mm_segment_t oldfs;
-
- PJ_CHECK_STACK();
-
- oldfs = get_fs();
- set_fs(KERNEL_DS);
-
- err = sys_connect( sockfd, (void*)addr, namelen );
-
- set_fs(oldfs);
-
- if (err)
- return PJ_RETURN_OS_ERROR(-err);
- else
- return PJ_SUCCESS;
-}
-
-/*
- * Accept incoming connections
- */
-PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t sockfd,
- pj_sock_t *newsockfd,
- pj_sockaddr_t *addr,
- int *addrlen)
-{
- long err;
-
- PJ_CHECK_STACK();
-
- PJ_ASSERT_RETURN(newsockfd != NULL, PJ_EINVAL);
-
- err = sys_accept( sockfd, addr, addrlen);
-
- if (err < 0) {
- *newsockfd = PJ_INVALID_SOCKET;
- return PJ_RETURN_OS_ERROR(-err);
- }
- else {
- *newsockfd = err;
- return PJ_SUCCESS;
- }
-}
-#endif /* PJ_HAS_TCP */
-
-
-
-/*
- * Permission to steal inet_ntoa() and inet_aton() as long as this notice below
- * is included:
- */
-/*
- * Copyright (c) 1983, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
+
+/*
+ * Convert 16-bit value from network byte order to host byte order.
+ */
+PJ_DEF(pj_uint16_t) pj_ntohs(pj_uint16_t netshort)
+{
+ return ntohs(netshort);
+}
+
+/*
+ * Convert 16-bit value from host byte order to network byte order.
+ */
+PJ_DEF(pj_uint16_t) pj_htons(pj_uint16_t hostshort)
+{
+ return htons(hostshort);
+}
+
+/*
+ * Convert 32-bit value from network byte order to host byte order.
+ */
+PJ_DEF(pj_uint32_t) pj_ntohl(pj_uint32_t netlong)
+{
+ return ntohl(netlong);
+}
+
+/*
+ * Convert 32-bit value from host byte order to network byte order.
+ */
+PJ_DEF(pj_uint32_t) pj_htonl(pj_uint32_t hostlong)
+{
+ return htonl(hostlong);
+}
+
+/*
+ * Convert an Internet host address given in network byte order
+ * to string in standard numbers and dots notation.
+ */
+PJ_DEF(char*) pj_inet_ntoa(pj_in_addr in)
+{
+#define UC(b) (((int)b)&0xff)
+ static char b[18];
+ char *p;
+
+ p = (char *)&in;
+ pj_snprintf(b, sizeof(b), "%d.%d.%d.%d",
+ UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3]));
+
+ return b;
+}
+
+/*
+ * This function converts the Internet host address ccp from the standard
+ * numbers-and-dots notation into binary data and stores it in the structure
+ * that inp points to.
+ */
+PJ_DEF(int) pj_inet_aton(const pj_str_t *ccp, struct pj_in_addr *addr)
+{
+ pj_uint32_t val;
+ int base, n;
+ char c;
+ unsigned parts[4];
+ unsigned *pp = parts;
+ char cp_copy[18];
+ char *cp = cp_copy;
+
+ addr->s_addr = PJ_INADDR_NONE;
+
+ if (ccp->slen > 15) return 0;
+
+ pj_memcpy(cp, ccp->ptr, ccp->slen);
+ cp[ccp->slen] = '\0';
+
+ c = *cp;
+ for (;;) {
+ /*
+ * Collect number up to ``.''.
+ * Values are specified as for C:
+ * 0x=hex, 0=octal, isdigit=decimal.
+ */
+ if (!pj_isdigit((int)c))
+ return (0);
+ val = 0; base = 10;
+ if (c == '0') {
+ c = *++cp;
+ if (c == 'x' || c == 'X')
+ base = 16, c = *++cp;
+ else
+ base = 8;
+ }
+
+ for (;;) {
+ if (pj_isascii((int)c) && pj_isdigit((int)c)) {
+ val = (val * base) + (c - '0');
+ c = *++cp;
+ } else if (base==16 && pj_isascii((int)c) && pj_isxdigit((int)c)) {
+ val = (val << 4) |
+ (c + 10 - (pj_islower((int)c) ? 'a' : 'A'));
+ c = *++cp;
+ } else
+ break;
+ }
+
+ if (c == '.') {
+ /*
+ * Internet format:
+ * a.b.c.d
+ * a.b.c (with c treated as 16 bits)
+ * a.b (with b treated as 24 bits)
+ */
+ if (pp >= parts + 3)
+ return (0);
+ *pp++ = val;
+ c = *++cp;
+ } else
+ break;
+ }
+
+ /*
+ * Check for trailing characters.
+ */
+ if (c != '\0' && (!pj_isascii((int)c) || !pj_isspace((int)c)))
+ return (0);
+ /*
+ * Concoct the address according to
+ * the number of parts specified.
+ */
+ n = pp - parts + 1;
+ switch (n) {
+ case 0:
+ return (0); /* initial nondigit */
+ case 1: /* a -- 32 bits */
+ break;
+ case 2: /* a.b -- 8.24 bits */
+ if (val > 0xffffff)
+ return (0);
+ val |= parts[0] << 24;
+ break;
+ case 3: /* a.b.c -- 8.8.16 bits */
+ if (val > 0xffff)
+ return (0);
+ val |= (parts[0] << 24) | (parts[1] << 16);
+ break;
+ case 4: /* a.b.c.d -- 8.8.8.8 bits */
+ if (val > 0xff)
+ return (0);
+ val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
+ break;
+ }
+
+ if (addr)
+ addr->s_addr = pj_htonl(val);
+ return (1);
+}
+
+/*
+ * Convert address string with numbers and dots to binary IP address.
+ */
+PJ_DEF(pj_in_addr) pj_inet_addr(const pj_str_t *cp)
+{
+ pj_in_addr addr;
+ pj_inet_aton(cp, &addr);
+ return addr;
+}
+
+/*
+ * Set the IP address of an IP socket address from string address,
+ * with resolving the host if necessary. The string address may be in a
+ * standard numbers and dots notation or may be a hostname. If hostname
+ * is specified, then the function will resolve the host into the IP
+ * address.
+ */
+PJ_DEF(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr,
+ const pj_str_t *str_addr)
+{
+ PJ_CHECK_STACK();
+
+ pj_assert(str_addr && str_addr->slen < PJ_MAX_HOSTNAME);
+
+ addr->sin_family = AF_INET;
+
+ if (str_addr && str_addr->slen) {
+ addr->sin_addr = pj_inet_addr(str_addr);
+ if (addr->sin_addr.s_addr == PJ_INADDR_NONE) {
+ pj_hostent he;
+ if (pj_gethostbyname(str_addr, &he) == 0) {
+ addr->sin_addr.s_addr = *(pj_uint32_t*)he.h_addr;
+ } else {
+ addr->sin_addr.s_addr = PJ_INADDR_NONE;
+ return -1;
+ }
+ }
+
+ } else {
+ addr->sin_addr.s_addr = 0;
+ }
+
+ return PJ_SUCCESS;
+}
+
+/*
+ * Set the IP address and port of an IP socket address.
+ * The string address may be in a standard numbers and dots notation or
+ * may be a hostname. If hostname is specified, then the function will
+ * resolve the host into the IP address.
+ */
+PJ_DEF(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr,
+ const pj_str_t *str_addr,
+ pj_uint16_t port)
+{
+ pj_assert(addr && str_addr);
+
+ addr->sin_family = PJ_AF_INET;
+ pj_sockaddr_in_set_port(addr, port);
+ return pj_sockaddr_in_set_str_addr(addr, str_addr);
+}
+
+
+/*
+ * Get hostname.
+ */
+PJ_DEF(const pj_str_t*) pj_gethostname(void)
+{
+ static char buf[PJ_MAX_HOSTNAME];
+ static pj_str_t hostname;
+
+ PJ_CHECK_STACK();
+
+ if (hostname.ptr == NULL) {
+ hostname.ptr = buf;
+ down_read(&uts_sem);
+ hostname.slen = strlen(system_utsname.nodename);
+ if (hostname.slen > PJ_MAX_HOSTNAME) {
+ hostname.ptr[0] = '\0';
+ hostname.slen = 0;
+ } else {
+ pj_memcpy(hostname.ptr, system_utsname.nodename, hostname.slen);
+ }
+ up_read(&uts_sem);
+ }
+ return &hostname;
+}
+
+/*
+ * Get first IP address associated with the hostname.
+ */
+PJ_DEF(pj_in_addr) pj_gethostaddr(void)
+{
+ pj_sockaddr_in addr;
+ const pj_str_t *hostname = pj_gethostname();
+
+ pj_sockaddr_in_set_str_addr(&addr, hostname);
+ return addr.sin_addr;
+}
+
+
+/*
+ * Create new socket/endpoint for communication and returns a descriptor.
+ */
+PJ_DEF(pj_status_t) pj_sock_socket(int af, int type, int proto,
+ pj_sock_t *sock_fd)
+{
+ long result;
+
+ PJ_CHECK_STACK();
+
+ /* Sanity checks. */
+ PJ_ASSERT_RETURN(PJ_INVALID_SOCKET == -1 && sock_fd != NULL, PJ_EINVAL);
+
+ /* Initialize returned socket */
+ *sock_fd = PJ_INVALID_SOCKET;
+
+ /* Create socket. */
+ result = sys_socket(af, type, proto);
+ if (result < 0) {
+ return PJ_RETURN_OS_ERROR((-result));
+ }
+
+ *sock_fd = result;
+
+ return PJ_SUCCESS;
+}
+
+/*
+ * Bind socket.
+ */
+PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sockfd,
+ const pj_sockaddr_t *addr,
+ int len)
+{
+ long err;
+ mm_segment_t oldfs;
+
+ PJ_CHECK_STACK();
+
+ PJ_ASSERT_RETURN(addr!=NULL && len >= sizeof(struct pj_sockaddr),
+ PJ_EINVAL);
+
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+
+ err = sys_bind(sockfd, (struct sockaddr*)addr, len);
+
+ set_fs(oldfs);
+
+ if (err)
+ return PJ_RETURN_OS_ERROR(-err);
+ else
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Bind socket.
+ */
+PJ_DEF(pj_status_t) pj_sock_bind_in( pj_sock_t sockfd,
+ pj_uint32_t addr32,
+ pj_uint16_t port)
+{
+ pj_sockaddr_in addr;
+
+ PJ_CHECK_STACK();
+
+ addr.sin_family = PJ_AF_INET;
+ addr.sin_addr.s_addr = pj_htonl(addr32);
+ addr.sin_port = pj_htons(port);
+
+ return pj_sock_bind(sockfd, &addr, sizeof(pj_sockaddr_in));
+}
+
+/*
+ * Close socket.
+ */
+PJ_DEF(pj_status_t) pj_sock_close(pj_sock_t sockfd)
+{
+ long err;
+
+ err = sys_close(sockfd);
+
+ if (err != 0)
+ return PJ_RETURN_OS_ERROR(-err);
+ else
+ return PJ_SUCCESS;
+}
+
+/*
+ * Get remote's name.
+ */
+PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sockfd,
+ pj_sockaddr_t *addr,
+ int *namelen)
+{
+ mm_segment_t oldfs;
+ long err;
+
+ PJ_CHECK_STACK();
+
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+
+ err = sys_getpeername( sockfd, addr, namelen);
+
+ set_fs(oldfs);
+
+ if (err)
+ return PJ_RETURN_OS_ERROR(-err);
+ else
+ return PJ_SUCCESS;
+}
+
+/*
+ * Get socket name.
+ */
+PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sockfd,
+ pj_sockaddr_t *addr,
+ int *namelen)
+{
+ mm_segment_t oldfs;
+ int err;
+
+ PJ_CHECK_STACK();
+
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+
+ err = sys_getsockname( sockfd, addr, namelen );
+
+ set_fs(oldfs);
+
+ if (err)
+ return PJ_RETURN_OS_ERROR(-err);
+ else
+ return PJ_SUCCESS;
+}
+
+/*
+ * Send data
+ */
+PJ_DEF(pj_status_t) pj_sock_send( pj_sock_t sockfd,
+ const void *buf,
+ pj_ssize_t *len,
+ unsigned flags)
+{
+ return pj_sock_sendto(sockfd, buf, len, flags, NULL, 0);
+}
+
+
+/*
+ * Send data.
+ */
+PJ_DEF(pj_status_t) pj_sock_sendto( pj_sock_t sockfd,
+ const void *buff,
+ pj_ssize_t *len,
+ unsigned flags,
+ const pj_sockaddr_t *addr,
+ int addr_len)
+{
+ long err;
+ mm_segment_t oldfs;
+
+ PJ_CHECK_STACK();
+
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+
+ err = *len = sys_sendto( sockfd, (void*)buff, *len, flags,
+ (void*)addr, addr_len );
+
+ set_fs(oldfs);
+
+ if (err >= 0) {
+ return PJ_SUCCESS;
+ }
+ else {
+ return PJ_RETURN_OS_ERROR(-err);
+ }
+}
+
+/*
+ * Receive data.
+ */
+PJ_DEF(pj_status_t) pj_sock_recv( pj_sock_t sockfd,
+ void *buf,
+ pj_ssize_t *len,
+ unsigned flags)
+{
+ return pj_sock_recvfrom(sockfd, buf, len, flags, NULL, NULL);
+}
+
+/*
+ * Receive data.
+ */
+PJ_DEF(pj_status_t) pj_sock_recvfrom( pj_sock_t sockfd,
+ void *buff,
+ pj_ssize_t *size,
+ unsigned flags,
+ pj_sockaddr_t *from,
+ int *fromlen)
+{
+ mm_segment_t oldfs;
+ long err;
+
+ PJ_CHECK_STACK();
+
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+
+ err = *size = sys_recvfrom( sockfd, buff, *size, flags, from, fromlen);
+
+ set_fs(oldfs);
+
+ if (err >= 0) {
+ return PJ_SUCCESS;
+ }
+ else {
+ return PJ_RETURN_OS_ERROR(-err);
+ }
+}
+
+/*
+ * Get socket option.
+ */
+PJ_DEF(pj_status_t) pj_sock_getsockopt( pj_sock_t sockfd,
+ pj_uint16_t level,
+ pj_uint16_t optname,
+ void *optval,
+ int *optlen)
+{
+ mm_segment_t oldfs;
+ long err;
+
+ PJ_CHECK_STACK();
+
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+
+ err = sys_getsockopt( sockfd, level, optname, optval, optlen);
+
+ set_fs(oldfs);
+
+ if (err)
+ return PJ_RETURN_OS_ERROR(-err);
+ else
+ return PJ_SUCCESS;
+}
+
+/*
+ * Set socket option.
+ */
+PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sockfd,
+ pj_uint16_t level,
+ pj_uint16_t optname,
+ const void *optval,
+ int optlen)
+{
+ long err;
+ mm_segment_t oldfs;
+
+ PJ_CHECK_STACK();
+
+
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+
+ err = sys_setsockopt( sockfd, level, optname, (void*)optval, optlen);
+
+ set_fs(oldfs);
+
+ if (err)
+ return PJ_RETURN_OS_ERROR(-err);
+ else
+ return PJ_SUCCESS;
+}
+
+/*
+ * Shutdown socket.
+ */
+#if PJ_HAS_TCP
+PJ_DEF(pj_status_t) pj_sock_shutdown( pj_sock_t sockfd,
+ int how)
+{
+ long err;
+
+ PJ_CHECK_STACK();
+
+ err = sys_shutdown(sockfd, how);
+
+ if (err)
+ return PJ_RETURN_OS_ERROR(-err);
+ else
+ return PJ_SUCCESS;
+}
+
+/*
+ * Start listening to incoming connections.
+ */
+PJ_DEF(pj_status_t) pj_sock_listen( pj_sock_t sockfd,
+ int backlog)
+{
+ long err;
+
+ PJ_CHECK_STACK();
+
+ err = sys_listen( sockfd, backlog );
+
+ if (err)
+ return PJ_RETURN_OS_ERROR(-err);
+ else
+ return PJ_SUCCESS;
+}
+
+/*
+ * Connect socket.
+ */
+PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sockfd,
+ const pj_sockaddr_t *addr,
+ int namelen)
+{
+ long err;
+ mm_segment_t oldfs;
+
+ PJ_CHECK_STACK();
+
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+
+ err = sys_connect( sockfd, (void*)addr, namelen );
+
+ set_fs(oldfs);
+
+ if (err)
+ return PJ_RETURN_OS_ERROR(-err);
+ else
+ return PJ_SUCCESS;
+}
+
+/*
+ * Accept incoming connections
+ */
+PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t sockfd,
+ pj_sock_t *newsockfd,
+ pj_sockaddr_t *addr,
+ int *addrlen)
+{
+ long err;
+
+ PJ_CHECK_STACK();
+
+ PJ_ASSERT_RETURN(newsockfd != NULL, PJ_EINVAL);
+
+ err = sys_accept( sockfd, addr, addrlen);
+
+ if (err < 0) {
+ *newsockfd = PJ_INVALID_SOCKET;
+ return PJ_RETURN_OS_ERROR(-err);
+ }
+ else {
+ *newsockfd = err;
+ return PJ_SUCCESS;
+ }
+}
+#endif /* PJ_HAS_TCP */
+
+
+
+/*
+ * Permission to steal inet_ntoa() and inet_aton() as long as this notice below
+ * is included:
+ */
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
diff --git a/pjlib/src/pj/sock_select.c b/pjlib/src/pj/sock_select.c
index 5b3d0a66..57d2f8eb 100644
--- a/pjlib/src/pj/sock_select.c
+++ b/pjlib/src/pj/sock_select.c
@@ -1,92 +1,113 @@
-/* $Id$
- */
-#include <pj/sock_select.h>
-#include <pj/compat/socket.h>
-#include <pj/os.h>
-#include <pj/assert.h>
-#include <pj/errno.h>
-
-#if defined(PJ_HAS_STRING_H) && PJ_HAS_STRING_H!=0
-# include <string.h>
-#endif
-
-#ifdef _MSC_VER
-# pragma warning(disable: 4018) // Signed/unsigned mismatch in FD_*
-# pragma warning(disable: 4389) // Signed/unsigned mismatch in FD_*
-#endif
-
-#define PART_FDSET(ps) ((fd_set*)&ps->data[1])
-#define PART_FDSET_OR_NULL(ps) (ps ? PART_FDSET(ps) : NULL)
-#define PART_COUNT(ps) (ps->data[0])
-
-PJ_DEF(void) PJ_FD_ZERO(pj_fd_set_t *fdsetp)
-{
- PJ_CHECK_STACK();
- pj_assert(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set));
-
- FD_ZERO(PART_FDSET(fdsetp));
- PART_COUNT(fdsetp) = 0;
-}
-
-
-PJ_DEF(void) PJ_FD_SET(pj_sock_t fd, pj_fd_set_t *fdsetp)
-{
- PJ_CHECK_STACK();
- pj_assert(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set));
-
- if (!PJ_FD_ISSET(fd, fdsetp))
- ++PART_COUNT(fdsetp);
- FD_SET(fd, PART_FDSET(fdsetp));
-}
-
-
-PJ_DEF(void) PJ_FD_CLR(pj_sock_t fd, pj_fd_set_t *fdsetp)
-{
- PJ_CHECK_STACK();
- pj_assert(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set));
-
- if (PJ_FD_ISSET(fd, fdsetp))
- --PART_COUNT(fdsetp);
- FD_CLR(fd, PART_FDSET(fdsetp));
-}
-
-
-PJ_DEF(pj_bool_t) PJ_FD_ISSET(pj_sock_t fd, const pj_fd_set_t *fdsetp)
-{
- PJ_CHECK_STACK();
- PJ_ASSERT_RETURN(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set),
- 0);
-
- return FD_ISSET(fd, PART_FDSET(fdsetp));
-}
-
-PJ_DEF(pj_size_t) PJ_FD_COUNT(const pj_fd_set_t *fdsetp)
-{
- return PART_COUNT(fdsetp);
-}
-
-PJ_DEF(int) pj_sock_select( int n,
- pj_fd_set_t *readfds,
- pj_fd_set_t *writefds,
- pj_fd_set_t *exceptfds,
- const pj_time_val *timeout)
-{
- struct timeval os_timeout, *p_os_timeout;
-
- PJ_CHECK_STACK();
-
- PJ_ASSERT_RETURN(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set),
- PJ_EBUG);
-
- if (timeout) {
- os_timeout.tv_sec = timeout->sec;
- os_timeout.tv_usec = timeout->msec * 1000;
- p_os_timeout = &os_timeout;
- } else {
- p_os_timeout = NULL;
- }
-
- return select(n, PART_FDSET_OR_NULL(readfds), PART_FDSET_OR_NULL(writefds),
- PART_FDSET_OR_NULL(exceptfds), p_os_timeout);
-}
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/sock_select.h>
+#include <pj/compat/socket.h>
+#include <pj/os.h>
+#include <pj/assert.h>
+#include <pj/errno.h>
+
+#if defined(PJ_HAS_STRING_H) && PJ_HAS_STRING_H!=0
+# include <string.h>
+#endif
+
+#ifdef _MSC_VER
+# pragma warning(disable: 4018) // Signed/unsigned mismatch in FD_*
+# pragma warning(disable: 4389) // Signed/unsigned mismatch in FD_*
+#endif
+
+#define PART_FDSET(ps) ((fd_set*)&ps->data[1])
+#define PART_FDSET_OR_NULL(ps) (ps ? PART_FDSET(ps) : NULL)
+#define PART_COUNT(ps) (ps->data[0])
+
+PJ_DEF(void) PJ_FD_ZERO(pj_fd_set_t *fdsetp)
+{
+ PJ_CHECK_STACK();
+ pj_assert(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set));
+
+ FD_ZERO(PART_FDSET(fdsetp));
+ PART_COUNT(fdsetp) = 0;
+}
+
+
+PJ_DEF(void) PJ_FD_SET(pj_sock_t fd, pj_fd_set_t *fdsetp)
+{
+ PJ_CHECK_STACK();
+ pj_assert(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set));
+
+ if (!PJ_FD_ISSET(fd, fdsetp))
+ ++PART_COUNT(fdsetp);
+ FD_SET(fd, PART_FDSET(fdsetp));
+}
+
+
+PJ_DEF(void) PJ_FD_CLR(pj_sock_t fd, pj_fd_set_t *fdsetp)
+{
+ PJ_CHECK_STACK();
+ pj_assert(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set));
+
+ if (PJ_FD_ISSET(fd, fdsetp))
+ --PART_COUNT(fdsetp);
+ FD_CLR(fd, PART_FDSET(fdsetp));
+}
+
+
+PJ_DEF(pj_bool_t) PJ_FD_ISSET(pj_sock_t fd, const pj_fd_set_t *fdsetp)
+{
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set),
+ 0);
+
+ return FD_ISSET(fd, PART_FDSET(fdsetp));
+}
+
+PJ_DEF(pj_size_t) PJ_FD_COUNT(const pj_fd_set_t *fdsetp)
+{
+ return PART_COUNT(fdsetp);
+}
+
+PJ_DEF(int) pj_sock_select( int n,
+ pj_fd_set_t *readfds,
+ pj_fd_set_t *writefds,
+ pj_fd_set_t *exceptfds,
+ const pj_time_val *timeout)
+{
+ struct timeval os_timeout, *p_os_timeout;
+
+ PJ_CHECK_STACK();
+
+ PJ_ASSERT_RETURN(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set),
+ PJ_EBUG);
+
+ if (timeout) {
+ os_timeout.tv_sec = timeout->sec;
+ os_timeout.tv_usec = timeout->msec * 1000;
+ p_os_timeout = &os_timeout;
+ } else {
+ p_os_timeout = NULL;
+ }
+
+ return select(n, PART_FDSET_OR_NULL(readfds), PART_FDSET_OR_NULL(writefds),
+ PART_FDSET_OR_NULL(exceptfds), p_os_timeout);
+}
+
diff --git a/pjlib/src/pj/string.c b/pjlib/src/pj/string.c
index 73313f9d..9c87d153 100644
--- a/pjlib/src/pj/string.c
+++ b/pjlib/src/pj/string.c
@@ -1,115 +1,136 @@
-/* $Id$
- */
-#include <pj/string.h>
-#include <pj/pool.h>
-#include <pj/ctype.h>
-#include <pj/rand.h>
-#include <pj/os.h>
-
-#if PJ_FUNCTIONS_ARE_INLINED==0
-# include <pj/string_i.h>
-#endif
-
-
-static char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
-
-PJ_DEF(pj_str_t*) pj_strltrim( pj_str_t *str )
-{
- register char *p = str->ptr;
- while (pj_isspace(*p))
- ++p;
- str->slen -= (p - str->ptr);
- str->ptr = p;
- return str;
-}
-
-PJ_DEF(pj_str_t*) pj_strrtrim( pj_str_t *str )
-{
- char *end = str->ptr + str->slen;
- register char *p = end - 1;
- while (p >= str->ptr && pj_isspace(*p))
- --p;
- str->slen -= ((end - p) - 1);
- return str;
-}
-
-PJ_INLINE(void) pj_val_to_hex_digit(unsigned value, char *p)
-{
- *p++ = hex[ (value & 0xF0) >> 4 ];
- *p++ = hex[ (value & 0x0F) ];
-}
-
-PJ_DEF(char*) pj_create_random_string(char *str, pj_size_t len)
-{
- unsigned i;
- char *p = str;
-
- PJ_CHECK_STACK();
-
- for (i=0; i<len/8; ++i) {
- unsigned val = pj_rand();
- pj_val_to_hex_digit( (val & 0xFF000000) >> 24, p+0 );
- pj_val_to_hex_digit( (val & 0x00FF0000) >> 16, p+2 );
- pj_val_to_hex_digit( (val & 0x0000FF00) >> 8, p+4 );
- pj_val_to_hex_digit( (val & 0x000000FF) >> 0, p+6 );
- p += 8;
- }
- for (i=i * 8; i<len; ++i) {
- *p++ = hex[ pj_rand() & 0x0F ];
- }
- return str;
-}
-
-
-PJ_DEF(unsigned long) pj_strtoul(const pj_str_t *str)
-{
- unsigned long value;
- unsigned i;
-
- PJ_CHECK_STACK();
-
- value = 0;
- for (i=0; i<(unsigned)str->slen; ++i) {
- value = value * 10 + (str->ptr[i] - '0');
- }
- return value;
-}
-
-PJ_DEF(int) pj_utoa(unsigned long val, char *buf)
-{
- return pj_utoa_pad(val, buf, 0, 0);
-}
-
-PJ_DEF(int) pj_utoa_pad( unsigned long val, char *buf, int min_dig, int pad)
-{
- char *p;
- int len;
-
- PJ_CHECK_STACK();
-
- p = buf;
- do {
- unsigned long digval = (unsigned long) (val % 10);
- val /= 10;
- *p++ = (char) (digval + '0');
- } while (val > 0);
-
- len = p-buf;
- while (len < min_dig) {
- *p++ = (char)pad;
- ++len;
- }
- *p-- = '\0';
-
- do {
- char temp = *p;
- *p = *buf;
- *buf = temp;
- --p;
- ++buf;
- } while (buf < p);
-
- return len;
-}
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/string.h>
+#include <pj/pool.h>
+#include <pj/ctype.h>
+#include <pj/rand.h>
+#include <pj/os.h>
+
+#if PJ_FUNCTIONS_ARE_INLINED==0
+# include <pj/string_i.h>
+#endif
+
+
+static char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+PJ_DEF(pj_str_t*) pj_strltrim( pj_str_t *str )
+{
+ register char *p = str->ptr;
+ while (pj_isspace(*p))
+ ++p;
+ str->slen -= (p - str->ptr);
+ str->ptr = p;
+ return str;
+}
+
+PJ_DEF(pj_str_t*) pj_strrtrim( pj_str_t *str )
+{
+ char *end = str->ptr + str->slen;
+ register char *p = end - 1;
+ while (p >= str->ptr && pj_isspace(*p))
+ --p;
+ str->slen -= ((end - p) - 1);
+ return str;
+}
+
+PJ_INLINE(void) pj_val_to_hex_digit(unsigned value, char *p)
+{
+ *p++ = hex[ (value & 0xF0) >> 4 ];
+ *p++ = hex[ (value & 0x0F) ];
+}
+
+PJ_DEF(char*) pj_create_random_string(char *str, pj_size_t len)
+{
+ unsigned i;
+ char *p = str;
+
+ PJ_CHECK_STACK();
+
+ for (i=0; i<len/8; ++i) {
+ unsigned val = pj_rand();
+ pj_val_to_hex_digit( (val & 0xFF000000) >> 24, p+0 );
+ pj_val_to_hex_digit( (val & 0x00FF0000) >> 16, p+2 );
+ pj_val_to_hex_digit( (val & 0x0000FF00) >> 8, p+4 );
+ pj_val_to_hex_digit( (val & 0x000000FF) >> 0, p+6 );
+ p += 8;
+ }
+ for (i=i * 8; i<len; ++i) {
+ *p++ = hex[ pj_rand() & 0x0F ];
+ }
+ return str;
+}
+
+
+PJ_DEF(unsigned long) pj_strtoul(const pj_str_t *str)
+{
+ unsigned long value;
+ unsigned i;
+
+ PJ_CHECK_STACK();
+
+ value = 0;
+ for (i=0; i<(unsigned)str->slen; ++i) {
+ value = value * 10 + (str->ptr[i] - '0');
+ }
+ return value;
+}
+
+PJ_DEF(int) pj_utoa(unsigned long val, char *buf)
+{
+ return pj_utoa_pad(val, buf, 0, 0);
+}
+
+PJ_DEF(int) pj_utoa_pad( unsigned long val, char *buf, int min_dig, int pad)
+{
+ char *p;
+ int len;
+
+ PJ_CHECK_STACK();
+
+ p = buf;
+ do {
+ unsigned long digval = (unsigned long) (val % 10);
+ val /= 10;
+ *p++ = (char) (digval + '0');
+ } while (val > 0);
+
+ len = p-buf;
+ while (len < min_dig) {
+ *p++ = (char)pad;
+ ++len;
+ }
+ *p-- = '\0';
+
+ do {
+ char temp = *p;
+ *p = *buf;
+ *buf = temp;
+ --p;
+ ++buf;
+ } while (buf < p);
+
+ return len;
+}
+
diff --git a/pjlib/src/pj/symbols.c b/pjlib/src/pj/symbols.c
index fc434adb..8d0ba559 100644
--- a/pjlib/src/pj/symbols.c
+++ b/pjlib/src/pj/symbols.c
@@ -1,330 +1,351 @@
-/* $Id$
- */
-#include <pjlib.h>
-
-/*
- * addr_resolv.h
- */
-PJ_EXPORT_SYMBOL(pj_gethostbyname)
-
-/*
- * array.h
- */
-PJ_EXPORT_SYMBOL(pj_array_insert)
-PJ_EXPORT_SYMBOL(pj_array_erase)
-PJ_EXPORT_SYMBOL(pj_array_find)
-
-/*
- * config.h
- */
-PJ_EXPORT_SYMBOL(pj_dump_config)
-
-/*
- * errno.h
- */
-PJ_EXPORT_SYMBOL(pj_get_os_error)
-PJ_EXPORT_SYMBOL(pj_set_os_error)
-PJ_EXPORT_SYMBOL(pj_get_netos_error)
-PJ_EXPORT_SYMBOL(pj_set_netos_error)
-PJ_EXPORT_SYMBOL(pj_strerror)
-
-/*
- * except.h
- */
-PJ_EXPORT_SYMBOL(pj_throw_exception_)
-PJ_EXPORT_SYMBOL(pj_push_exception_handler_)
-PJ_EXPORT_SYMBOL(pj_pop_exception_handler_)
-PJ_EXPORT_SYMBOL(pj_setjmp)
-PJ_EXPORT_SYMBOL(pj_longjmp)
-PJ_EXPORT_SYMBOL(pj_exception_id_alloc)
-PJ_EXPORT_SYMBOL(pj_exception_id_free)
-PJ_EXPORT_SYMBOL(pj_exception_id_name)
-
-
-/*
- * fifobuf.h
- */
-PJ_EXPORT_SYMBOL(pj_fifobuf_init)
-PJ_EXPORT_SYMBOL(pj_fifobuf_max_size)
-PJ_EXPORT_SYMBOL(pj_fifobuf_alloc)
-PJ_EXPORT_SYMBOL(pj_fifobuf_unalloc)
-PJ_EXPORT_SYMBOL(pj_fifobuf_free)
-
-/*
- * guid.h
- */
-PJ_EXPORT_SYMBOL(pj_generate_unique_string)
-PJ_EXPORT_SYMBOL(pj_create_unique_string)
-
-/*
- * hash.h
- */
-PJ_EXPORT_SYMBOL(pj_hash_calc)
-PJ_EXPORT_SYMBOL(pj_hash_create)
-PJ_EXPORT_SYMBOL(pj_hash_get)
-PJ_EXPORT_SYMBOL(pj_hash_set)
-PJ_EXPORT_SYMBOL(pj_hash_count)
-PJ_EXPORT_SYMBOL(pj_hash_first)
-PJ_EXPORT_SYMBOL(pj_hash_next)
-PJ_EXPORT_SYMBOL(pj_hash_this)
-
-/*
- * ioqueue.h
- */
-PJ_EXPORT_SYMBOL(pj_ioqueue_create)
-PJ_EXPORT_SYMBOL(pj_ioqueue_destroy)
-PJ_EXPORT_SYMBOL(pj_ioqueue_set_lock)
-PJ_EXPORT_SYMBOL(pj_ioqueue_register_sock)
-PJ_EXPORT_SYMBOL(pj_ioqueue_unregister)
-PJ_EXPORT_SYMBOL(pj_ioqueue_get_user_data)
-PJ_EXPORT_SYMBOL(pj_ioqueue_poll)
-PJ_EXPORT_SYMBOL(pj_ioqueue_read)
-PJ_EXPORT_SYMBOL(pj_ioqueue_recv)
-PJ_EXPORT_SYMBOL(pj_ioqueue_recvfrom)
-PJ_EXPORT_SYMBOL(pj_ioqueue_write)
-PJ_EXPORT_SYMBOL(pj_ioqueue_send)
-PJ_EXPORT_SYMBOL(pj_ioqueue_sendto)
-#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
-PJ_EXPORT_SYMBOL(pj_ioqueue_accept)
-PJ_EXPORT_SYMBOL(pj_ioqueue_connect)
-#endif
-
-/*
- * list.h
- */
-PJ_EXPORT_SYMBOL(pj_list_insert_before)
-PJ_EXPORT_SYMBOL(pj_list_insert_nodes_before)
-PJ_EXPORT_SYMBOL(pj_list_insert_after)
-PJ_EXPORT_SYMBOL(pj_list_insert_nodes_after)
-PJ_EXPORT_SYMBOL(pj_list_merge_first)
-PJ_EXPORT_SYMBOL(pj_list_merge_last)
-PJ_EXPORT_SYMBOL(pj_list_erase)
-PJ_EXPORT_SYMBOL(pj_list_find_node)
-PJ_EXPORT_SYMBOL(pj_list_search)
-
-
-/*
- * log.h
- */
-PJ_EXPORT_SYMBOL(pj_log_write)
-#if PJ_LOG_MAX_LEVEL >= 1
-PJ_EXPORT_SYMBOL(pj_log_set_log_func)
-PJ_EXPORT_SYMBOL(pj_log_get_log_func)
-PJ_EXPORT_SYMBOL(pj_log_set_level)
-PJ_EXPORT_SYMBOL(pj_log_get_level)
-PJ_EXPORT_SYMBOL(pj_log_set_decor)
-PJ_EXPORT_SYMBOL(pj_log_get_decor)
-PJ_EXPORT_SYMBOL(pj_log_1)
-#endif
-#if PJ_LOG_MAX_LEVEL >= 2
-PJ_EXPORT_SYMBOL(pj_log_2)
-#endif
-#if PJ_LOG_MAX_LEVEL >= 3
-PJ_EXPORT_SYMBOL(pj_log_3)
-#endif
-#if PJ_LOG_MAX_LEVEL >= 4
-PJ_EXPORT_SYMBOL(pj_log_4)
-#endif
-#if PJ_LOG_MAX_LEVEL >= 5
-PJ_EXPORT_SYMBOL(pj_log_5)
-#endif
-#if PJ_LOG_MAX_LEVEL >= 6
-PJ_EXPORT_SYMBOL(pj_log_6)
-#endif
-
-/*
- * os.h
- */
-PJ_EXPORT_SYMBOL(pj_init)
-PJ_EXPORT_SYMBOL(pj_getpid)
-PJ_EXPORT_SYMBOL(pj_thread_register)
-PJ_EXPORT_SYMBOL(pj_thread_create)
-PJ_EXPORT_SYMBOL(pj_thread_get_name)
-PJ_EXPORT_SYMBOL(pj_thread_resume)
-PJ_EXPORT_SYMBOL(pj_thread_this)
-PJ_EXPORT_SYMBOL(pj_thread_join)
-PJ_EXPORT_SYMBOL(pj_thread_destroy)
-PJ_EXPORT_SYMBOL(pj_thread_sleep)
-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK != 0
-PJ_EXPORT_SYMBOL(pj_thread_check_stack)
-PJ_EXPORT_SYMBOL(pj_thread_get_stack_max_usage)
-PJ_EXPORT_SYMBOL(pj_thread_get_stack_info)
-#endif
-PJ_EXPORT_SYMBOL(pj_atomic_create)
-PJ_EXPORT_SYMBOL(pj_atomic_destroy)
-PJ_EXPORT_SYMBOL(pj_atomic_set)
-PJ_EXPORT_SYMBOL(pj_atomic_get)
-PJ_EXPORT_SYMBOL(pj_atomic_inc)
-PJ_EXPORT_SYMBOL(pj_atomic_dec)
-PJ_EXPORT_SYMBOL(pj_thread_local_alloc)
-PJ_EXPORT_SYMBOL(pj_thread_local_free)
-PJ_EXPORT_SYMBOL(pj_thread_local_set)
-PJ_EXPORT_SYMBOL(pj_thread_local_get)
-PJ_EXPORT_SYMBOL(pj_enter_critical_section)
-PJ_EXPORT_SYMBOL(pj_leave_critical_section)
-PJ_EXPORT_SYMBOL(pj_mutex_create)
-PJ_EXPORT_SYMBOL(pj_mutex_lock)
-PJ_EXPORT_SYMBOL(pj_mutex_unlock)
-PJ_EXPORT_SYMBOL(pj_mutex_trylock)
-PJ_EXPORT_SYMBOL(pj_mutex_destroy)
-#if defined(PJ_DEBUG) && PJ_DEBUG != 0
-PJ_EXPORT_SYMBOL(pj_mutex_is_locked)
-#endif
-#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
-PJ_EXPORT_SYMBOL(pj_sem_create)
-PJ_EXPORT_SYMBOL(pj_sem_wait)
-PJ_EXPORT_SYMBOL(pj_sem_trywait)
-PJ_EXPORT_SYMBOL(pj_sem_post)
-PJ_EXPORT_SYMBOL(pj_sem_destroy)
-#endif
-PJ_EXPORT_SYMBOL(pj_gettimeofday)
-PJ_EXPORT_SYMBOL(pj_time_decode)
-#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0
-PJ_EXPORT_SYMBOL(pj_get_timestamp)
-PJ_EXPORT_SYMBOL(pj_get_timestamp_freq)
-PJ_EXPORT_SYMBOL(pj_elapsed_time)
-PJ_EXPORT_SYMBOL(pj_elapsed_usec)
-PJ_EXPORT_SYMBOL(pj_elapsed_nanosec)
-PJ_EXPORT_SYMBOL(pj_elapsed_cycle)
-#endif
-
-
-/*
- * pool.h
- */
-PJ_EXPORT_SYMBOL(pj_pool_create)
-PJ_EXPORT_SYMBOL(pj_pool_release)
-PJ_EXPORT_SYMBOL(pj_pool_getobjname)
-PJ_EXPORT_SYMBOL(pj_pool_reset)
-PJ_EXPORT_SYMBOL(pj_pool_get_capacity)
-PJ_EXPORT_SYMBOL(pj_pool_get_used_size)
-PJ_EXPORT_SYMBOL(pj_pool_alloc)
-PJ_EXPORT_SYMBOL(pj_pool_calloc)
-PJ_EXPORT_SYMBOL(pj_pool_factory_default_policy)
-PJ_EXPORT_SYMBOL(pj_pool_create_int)
-PJ_EXPORT_SYMBOL(pj_pool_init_int)
-PJ_EXPORT_SYMBOL(pj_pool_destroy_int)
-PJ_EXPORT_SYMBOL(pj_caching_pool_init)
-PJ_EXPORT_SYMBOL(pj_caching_pool_destroy)
-
-/*
- * rand.h
- */
-PJ_EXPORT_SYMBOL(pj_rand)
-PJ_EXPORT_SYMBOL(pj_srand)
-
-/*
- * rbtree.h
- */
-PJ_EXPORT_SYMBOL(pj_rbtree_init)
-PJ_EXPORT_SYMBOL(pj_rbtree_first)
-PJ_EXPORT_SYMBOL(pj_rbtree_last)
-PJ_EXPORT_SYMBOL(pj_rbtree_next)
-PJ_EXPORT_SYMBOL(pj_rbtree_prev)
-PJ_EXPORT_SYMBOL(pj_rbtree_insert)
-PJ_EXPORT_SYMBOL(pj_rbtree_find)
-PJ_EXPORT_SYMBOL(pj_rbtree_erase)
-PJ_EXPORT_SYMBOL(pj_rbtree_max_height)
-PJ_EXPORT_SYMBOL(pj_rbtree_min_height)
-
-/*
- * sock.h
- */
-PJ_EXPORT_SYMBOL(PJ_AF_UNIX)
-PJ_EXPORT_SYMBOL(PJ_AF_INET)
-PJ_EXPORT_SYMBOL(PJ_AF_INET6)
-PJ_EXPORT_SYMBOL(PJ_AF_PACKET)
-PJ_EXPORT_SYMBOL(PJ_AF_IRDA)
-PJ_EXPORT_SYMBOL(PJ_SOCK_STREAM)
-PJ_EXPORT_SYMBOL(PJ_SOCK_DGRAM)
-PJ_EXPORT_SYMBOL(PJ_SOCK_RAW)
-PJ_EXPORT_SYMBOL(PJ_SOCK_RDM)
-PJ_EXPORT_SYMBOL(PJ_SOL_SOCKET)
-PJ_EXPORT_SYMBOL(PJ_SOL_IP)
-PJ_EXPORT_SYMBOL(PJ_SOL_TCP)
-PJ_EXPORT_SYMBOL(PJ_SOL_UDP)
-PJ_EXPORT_SYMBOL(PJ_SOL_IPV6)
-PJ_EXPORT_SYMBOL(pj_ntohs)
-PJ_EXPORT_SYMBOL(pj_htons)
-PJ_EXPORT_SYMBOL(pj_ntohl)
-PJ_EXPORT_SYMBOL(pj_htonl)
-PJ_EXPORT_SYMBOL(pj_inet_ntoa)
-PJ_EXPORT_SYMBOL(pj_inet_aton)
-PJ_EXPORT_SYMBOL(pj_inet_addr)
-PJ_EXPORT_SYMBOL(pj_sockaddr_in_set_str_addr)
-PJ_EXPORT_SYMBOL(pj_sockaddr_in_init)
-PJ_EXPORT_SYMBOL(pj_gethostname)
-PJ_EXPORT_SYMBOL(pj_gethostaddr)
-PJ_EXPORT_SYMBOL(pj_sock_socket)
-PJ_EXPORT_SYMBOL(pj_sock_close)
-PJ_EXPORT_SYMBOL(pj_sock_bind)
-PJ_EXPORT_SYMBOL(pj_sock_bind_in)
-#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
-PJ_EXPORT_SYMBOL(pj_sock_listen)
-PJ_EXPORT_SYMBOL(pj_sock_accept)
-PJ_EXPORT_SYMBOL(pj_sock_shutdown)
-#endif
-PJ_EXPORT_SYMBOL(pj_sock_connect)
-PJ_EXPORT_SYMBOL(pj_sock_getpeername)
-PJ_EXPORT_SYMBOL(pj_sock_getsockname)
-PJ_EXPORT_SYMBOL(pj_sock_getsockopt)
-PJ_EXPORT_SYMBOL(pj_sock_setsockopt)
-PJ_EXPORT_SYMBOL(pj_sock_recv)
-PJ_EXPORT_SYMBOL(pj_sock_recvfrom)
-PJ_EXPORT_SYMBOL(pj_sock_send)
-PJ_EXPORT_SYMBOL(pj_sock_sendto)
-
-/*
- * sock_select.h
- */
-PJ_EXPORT_SYMBOL(PJ_FD_ZERO)
-PJ_EXPORT_SYMBOL(PJ_FD_SET)
-PJ_EXPORT_SYMBOL(PJ_FD_CLR)
-PJ_EXPORT_SYMBOL(PJ_FD_ISSET)
-PJ_EXPORT_SYMBOL(pj_sock_select)
-
-/*
- * string.h
- */
-PJ_EXPORT_SYMBOL(pj_str)
-PJ_EXPORT_SYMBOL(pj_strassign)
-PJ_EXPORT_SYMBOL(pj_strcpy)
-PJ_EXPORT_SYMBOL(pj_strcpy2)
-PJ_EXPORT_SYMBOL(pj_strdup)
-PJ_EXPORT_SYMBOL(pj_strdup_with_null)
-PJ_EXPORT_SYMBOL(pj_strdup2)
-PJ_EXPORT_SYMBOL(pj_strdup3)
-PJ_EXPORT_SYMBOL(pj_strcmp)
-PJ_EXPORT_SYMBOL(pj_strcmp2)
-PJ_EXPORT_SYMBOL(pj_strncmp)
-PJ_EXPORT_SYMBOL(pj_strncmp2)
-PJ_EXPORT_SYMBOL(pj_stricmp)
-PJ_EXPORT_SYMBOL(pj_stricmp2)
-PJ_EXPORT_SYMBOL(pj_strnicmp)
-PJ_EXPORT_SYMBOL(pj_strnicmp2)
-PJ_EXPORT_SYMBOL(pj_strcat)
-PJ_EXPORT_SYMBOL(pj_strltrim)
-PJ_EXPORT_SYMBOL(pj_strrtrim)
-PJ_EXPORT_SYMBOL(pj_strtrim)
-PJ_EXPORT_SYMBOL(pj_create_random_string)
-PJ_EXPORT_SYMBOL(pj_strtoul)
-PJ_EXPORT_SYMBOL(pj_utoa)
-PJ_EXPORT_SYMBOL(pj_utoa_pad)
-
-/*
- * timer.h
- */
-PJ_EXPORT_SYMBOL(pj_timer_heap_mem_size)
-PJ_EXPORT_SYMBOL(pj_timer_heap_create)
-PJ_EXPORT_SYMBOL(pj_timer_entry_init)
-PJ_EXPORT_SYMBOL(pj_timer_heap_schedule)
-PJ_EXPORT_SYMBOL(pj_timer_heap_cancel)
-PJ_EXPORT_SYMBOL(pj_timer_heap_count)
-PJ_EXPORT_SYMBOL(pj_timer_heap_earliest_time)
-PJ_EXPORT_SYMBOL(pj_timer_heap_poll)
-
-/*
- * types.h
- */
-PJ_EXPORT_SYMBOL(pj_time_val_normalize)
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pjlib.h>
+
+/*
+ * addr_resolv.h
+ */
+PJ_EXPORT_SYMBOL(pj_gethostbyname)
+
+/*
+ * array.h
+ */
+PJ_EXPORT_SYMBOL(pj_array_insert)
+PJ_EXPORT_SYMBOL(pj_array_erase)
+PJ_EXPORT_SYMBOL(pj_array_find)
+
+/*
+ * config.h
+ */
+PJ_EXPORT_SYMBOL(pj_dump_config)
+
+/*
+ * errno.h
+ */
+PJ_EXPORT_SYMBOL(pj_get_os_error)
+PJ_EXPORT_SYMBOL(pj_set_os_error)
+PJ_EXPORT_SYMBOL(pj_get_netos_error)
+PJ_EXPORT_SYMBOL(pj_set_netos_error)
+PJ_EXPORT_SYMBOL(pj_strerror)
+
+/*
+ * except.h
+ */
+PJ_EXPORT_SYMBOL(pj_throw_exception_)
+PJ_EXPORT_SYMBOL(pj_push_exception_handler_)
+PJ_EXPORT_SYMBOL(pj_pop_exception_handler_)
+PJ_EXPORT_SYMBOL(pj_setjmp)
+PJ_EXPORT_SYMBOL(pj_longjmp)
+PJ_EXPORT_SYMBOL(pj_exception_id_alloc)
+PJ_EXPORT_SYMBOL(pj_exception_id_free)
+PJ_EXPORT_SYMBOL(pj_exception_id_name)
+
+
+/*
+ * fifobuf.h
+ */
+PJ_EXPORT_SYMBOL(pj_fifobuf_init)
+PJ_EXPORT_SYMBOL(pj_fifobuf_max_size)
+PJ_EXPORT_SYMBOL(pj_fifobuf_alloc)
+PJ_EXPORT_SYMBOL(pj_fifobuf_unalloc)
+PJ_EXPORT_SYMBOL(pj_fifobuf_free)
+
+/*
+ * guid.h
+ */
+PJ_EXPORT_SYMBOL(pj_generate_unique_string)
+PJ_EXPORT_SYMBOL(pj_create_unique_string)
+
+/*
+ * hash.h
+ */
+PJ_EXPORT_SYMBOL(pj_hash_calc)
+PJ_EXPORT_SYMBOL(pj_hash_create)
+PJ_EXPORT_SYMBOL(pj_hash_get)
+PJ_EXPORT_SYMBOL(pj_hash_set)
+PJ_EXPORT_SYMBOL(pj_hash_count)
+PJ_EXPORT_SYMBOL(pj_hash_first)
+PJ_EXPORT_SYMBOL(pj_hash_next)
+PJ_EXPORT_SYMBOL(pj_hash_this)
+
+/*
+ * ioqueue.h
+ */
+PJ_EXPORT_SYMBOL(pj_ioqueue_create)
+PJ_EXPORT_SYMBOL(pj_ioqueue_destroy)
+PJ_EXPORT_SYMBOL(pj_ioqueue_set_lock)
+PJ_EXPORT_SYMBOL(pj_ioqueue_register_sock)
+PJ_EXPORT_SYMBOL(pj_ioqueue_unregister)
+PJ_EXPORT_SYMBOL(pj_ioqueue_get_user_data)
+PJ_EXPORT_SYMBOL(pj_ioqueue_poll)
+PJ_EXPORT_SYMBOL(pj_ioqueue_read)
+PJ_EXPORT_SYMBOL(pj_ioqueue_recv)
+PJ_EXPORT_SYMBOL(pj_ioqueue_recvfrom)
+PJ_EXPORT_SYMBOL(pj_ioqueue_write)
+PJ_EXPORT_SYMBOL(pj_ioqueue_send)
+PJ_EXPORT_SYMBOL(pj_ioqueue_sendto)
+#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
+PJ_EXPORT_SYMBOL(pj_ioqueue_accept)
+PJ_EXPORT_SYMBOL(pj_ioqueue_connect)
+#endif
+
+/*
+ * list.h
+ */
+PJ_EXPORT_SYMBOL(pj_list_insert_before)
+PJ_EXPORT_SYMBOL(pj_list_insert_nodes_before)
+PJ_EXPORT_SYMBOL(pj_list_insert_after)
+PJ_EXPORT_SYMBOL(pj_list_insert_nodes_after)
+PJ_EXPORT_SYMBOL(pj_list_merge_first)
+PJ_EXPORT_SYMBOL(pj_list_merge_last)
+PJ_EXPORT_SYMBOL(pj_list_erase)
+PJ_EXPORT_SYMBOL(pj_list_find_node)
+PJ_EXPORT_SYMBOL(pj_list_search)
+
+
+/*
+ * log.h
+ */
+PJ_EXPORT_SYMBOL(pj_log_write)
+#if PJ_LOG_MAX_LEVEL >= 1
+PJ_EXPORT_SYMBOL(pj_log_set_log_func)
+PJ_EXPORT_SYMBOL(pj_log_get_log_func)
+PJ_EXPORT_SYMBOL(pj_log_set_level)
+PJ_EXPORT_SYMBOL(pj_log_get_level)
+PJ_EXPORT_SYMBOL(pj_log_set_decor)
+PJ_EXPORT_SYMBOL(pj_log_get_decor)
+PJ_EXPORT_SYMBOL(pj_log_1)
+#endif
+#if PJ_LOG_MAX_LEVEL >= 2
+PJ_EXPORT_SYMBOL(pj_log_2)
+#endif
+#if PJ_LOG_MAX_LEVEL >= 3
+PJ_EXPORT_SYMBOL(pj_log_3)
+#endif
+#if PJ_LOG_MAX_LEVEL >= 4
+PJ_EXPORT_SYMBOL(pj_log_4)
+#endif
+#if PJ_LOG_MAX_LEVEL >= 5
+PJ_EXPORT_SYMBOL(pj_log_5)
+#endif
+#if PJ_LOG_MAX_LEVEL >= 6
+PJ_EXPORT_SYMBOL(pj_log_6)
+#endif
+
+/*
+ * os.h
+ */
+PJ_EXPORT_SYMBOL(pj_init)
+PJ_EXPORT_SYMBOL(pj_getpid)
+PJ_EXPORT_SYMBOL(pj_thread_register)
+PJ_EXPORT_SYMBOL(pj_thread_create)
+PJ_EXPORT_SYMBOL(pj_thread_get_name)
+PJ_EXPORT_SYMBOL(pj_thread_resume)
+PJ_EXPORT_SYMBOL(pj_thread_this)
+PJ_EXPORT_SYMBOL(pj_thread_join)
+PJ_EXPORT_SYMBOL(pj_thread_destroy)
+PJ_EXPORT_SYMBOL(pj_thread_sleep)
+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK != 0
+PJ_EXPORT_SYMBOL(pj_thread_check_stack)
+PJ_EXPORT_SYMBOL(pj_thread_get_stack_max_usage)
+PJ_EXPORT_SYMBOL(pj_thread_get_stack_info)
+#endif
+PJ_EXPORT_SYMBOL(pj_atomic_create)
+PJ_EXPORT_SYMBOL(pj_atomic_destroy)
+PJ_EXPORT_SYMBOL(pj_atomic_set)
+PJ_EXPORT_SYMBOL(pj_atomic_get)
+PJ_EXPORT_SYMBOL(pj_atomic_inc)
+PJ_EXPORT_SYMBOL(pj_atomic_dec)
+PJ_EXPORT_SYMBOL(pj_thread_local_alloc)
+PJ_EXPORT_SYMBOL(pj_thread_local_free)
+PJ_EXPORT_SYMBOL(pj_thread_local_set)
+PJ_EXPORT_SYMBOL(pj_thread_local_get)
+PJ_EXPORT_SYMBOL(pj_enter_critical_section)
+PJ_EXPORT_SYMBOL(pj_leave_critical_section)
+PJ_EXPORT_SYMBOL(pj_mutex_create)
+PJ_EXPORT_SYMBOL(pj_mutex_lock)
+PJ_EXPORT_SYMBOL(pj_mutex_unlock)
+PJ_EXPORT_SYMBOL(pj_mutex_trylock)
+PJ_EXPORT_SYMBOL(pj_mutex_destroy)
+#if defined(PJ_DEBUG) && PJ_DEBUG != 0
+PJ_EXPORT_SYMBOL(pj_mutex_is_locked)
+#endif
+#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
+PJ_EXPORT_SYMBOL(pj_sem_create)
+PJ_EXPORT_SYMBOL(pj_sem_wait)
+PJ_EXPORT_SYMBOL(pj_sem_trywait)
+PJ_EXPORT_SYMBOL(pj_sem_post)
+PJ_EXPORT_SYMBOL(pj_sem_destroy)
+#endif
+PJ_EXPORT_SYMBOL(pj_gettimeofday)
+PJ_EXPORT_SYMBOL(pj_time_decode)
+#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0
+PJ_EXPORT_SYMBOL(pj_get_timestamp)
+PJ_EXPORT_SYMBOL(pj_get_timestamp_freq)
+PJ_EXPORT_SYMBOL(pj_elapsed_time)
+PJ_EXPORT_SYMBOL(pj_elapsed_usec)
+PJ_EXPORT_SYMBOL(pj_elapsed_nanosec)
+PJ_EXPORT_SYMBOL(pj_elapsed_cycle)
+#endif
+
+
+/*
+ * pool.h
+ */
+PJ_EXPORT_SYMBOL(pj_pool_create)
+PJ_EXPORT_SYMBOL(pj_pool_release)
+PJ_EXPORT_SYMBOL(pj_pool_getobjname)
+PJ_EXPORT_SYMBOL(pj_pool_reset)
+PJ_EXPORT_SYMBOL(pj_pool_get_capacity)
+PJ_EXPORT_SYMBOL(pj_pool_get_used_size)
+PJ_EXPORT_SYMBOL(pj_pool_alloc)
+PJ_EXPORT_SYMBOL(pj_pool_calloc)
+PJ_EXPORT_SYMBOL(pj_pool_factory_default_policy)
+PJ_EXPORT_SYMBOL(pj_pool_create_int)
+PJ_EXPORT_SYMBOL(pj_pool_init_int)
+PJ_EXPORT_SYMBOL(pj_pool_destroy_int)
+PJ_EXPORT_SYMBOL(pj_caching_pool_init)
+PJ_EXPORT_SYMBOL(pj_caching_pool_destroy)
+
+/*
+ * rand.h
+ */
+PJ_EXPORT_SYMBOL(pj_rand)
+PJ_EXPORT_SYMBOL(pj_srand)
+
+/*
+ * rbtree.h
+ */
+PJ_EXPORT_SYMBOL(pj_rbtree_init)
+PJ_EXPORT_SYMBOL(pj_rbtree_first)
+PJ_EXPORT_SYMBOL(pj_rbtree_last)
+PJ_EXPORT_SYMBOL(pj_rbtree_next)
+PJ_EXPORT_SYMBOL(pj_rbtree_prev)
+PJ_EXPORT_SYMBOL(pj_rbtree_insert)
+PJ_EXPORT_SYMBOL(pj_rbtree_find)
+PJ_EXPORT_SYMBOL(pj_rbtree_erase)
+PJ_EXPORT_SYMBOL(pj_rbtree_max_height)
+PJ_EXPORT_SYMBOL(pj_rbtree_min_height)
+
+/*
+ * sock.h
+ */
+PJ_EXPORT_SYMBOL(PJ_AF_UNIX)
+PJ_EXPORT_SYMBOL(PJ_AF_INET)
+PJ_EXPORT_SYMBOL(PJ_AF_INET6)
+PJ_EXPORT_SYMBOL(PJ_AF_PACKET)
+PJ_EXPORT_SYMBOL(PJ_AF_IRDA)
+PJ_EXPORT_SYMBOL(PJ_SOCK_STREAM)
+PJ_EXPORT_SYMBOL(PJ_SOCK_DGRAM)
+PJ_EXPORT_SYMBOL(PJ_SOCK_RAW)
+PJ_EXPORT_SYMBOL(PJ_SOCK_RDM)
+PJ_EXPORT_SYMBOL(PJ_SOL_SOCKET)
+PJ_EXPORT_SYMBOL(PJ_SOL_IP)
+PJ_EXPORT_SYMBOL(PJ_SOL_TCP)
+PJ_EXPORT_SYMBOL(PJ_SOL_UDP)
+PJ_EXPORT_SYMBOL(PJ_SOL_IPV6)
+PJ_EXPORT_SYMBOL(pj_ntohs)
+PJ_EXPORT_SYMBOL(pj_htons)
+PJ_EXPORT_SYMBOL(pj_ntohl)
+PJ_EXPORT_SYMBOL(pj_htonl)
+PJ_EXPORT_SYMBOL(pj_inet_ntoa)
+PJ_EXPORT_SYMBOL(pj_inet_aton)
+PJ_EXPORT_SYMBOL(pj_inet_addr)
+PJ_EXPORT_SYMBOL(pj_sockaddr_in_set_str_addr)
+PJ_EXPORT_SYMBOL(pj_sockaddr_in_init)
+PJ_EXPORT_SYMBOL(pj_gethostname)
+PJ_EXPORT_SYMBOL(pj_gethostaddr)
+PJ_EXPORT_SYMBOL(pj_sock_socket)
+PJ_EXPORT_SYMBOL(pj_sock_close)
+PJ_EXPORT_SYMBOL(pj_sock_bind)
+PJ_EXPORT_SYMBOL(pj_sock_bind_in)
+#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
+PJ_EXPORT_SYMBOL(pj_sock_listen)
+PJ_EXPORT_SYMBOL(pj_sock_accept)
+PJ_EXPORT_SYMBOL(pj_sock_shutdown)
+#endif
+PJ_EXPORT_SYMBOL(pj_sock_connect)
+PJ_EXPORT_SYMBOL(pj_sock_getpeername)
+PJ_EXPORT_SYMBOL(pj_sock_getsockname)
+PJ_EXPORT_SYMBOL(pj_sock_getsockopt)
+PJ_EXPORT_SYMBOL(pj_sock_setsockopt)
+PJ_EXPORT_SYMBOL(pj_sock_recv)
+PJ_EXPORT_SYMBOL(pj_sock_recvfrom)
+PJ_EXPORT_SYMBOL(pj_sock_send)
+PJ_EXPORT_SYMBOL(pj_sock_sendto)
+
+/*
+ * sock_select.h
+ */
+PJ_EXPORT_SYMBOL(PJ_FD_ZERO)
+PJ_EXPORT_SYMBOL(PJ_FD_SET)
+PJ_EXPORT_SYMBOL(PJ_FD_CLR)
+PJ_EXPORT_SYMBOL(PJ_FD_ISSET)
+PJ_EXPORT_SYMBOL(pj_sock_select)
+
+/*
+ * string.h
+ */
+PJ_EXPORT_SYMBOL(pj_str)
+PJ_EXPORT_SYMBOL(pj_strassign)
+PJ_EXPORT_SYMBOL(pj_strcpy)
+PJ_EXPORT_SYMBOL(pj_strcpy2)
+PJ_EXPORT_SYMBOL(pj_strdup)
+PJ_EXPORT_SYMBOL(pj_strdup_with_null)
+PJ_EXPORT_SYMBOL(pj_strdup2)
+PJ_EXPORT_SYMBOL(pj_strdup3)
+PJ_EXPORT_SYMBOL(pj_strcmp)
+PJ_EXPORT_SYMBOL(pj_strcmp2)
+PJ_EXPORT_SYMBOL(pj_strncmp)
+PJ_EXPORT_SYMBOL(pj_strncmp2)
+PJ_EXPORT_SYMBOL(pj_stricmp)
+PJ_EXPORT_SYMBOL(pj_stricmp2)
+PJ_EXPORT_SYMBOL(pj_strnicmp)
+PJ_EXPORT_SYMBOL(pj_strnicmp2)
+PJ_EXPORT_SYMBOL(pj_strcat)
+PJ_EXPORT_SYMBOL(pj_strltrim)
+PJ_EXPORT_SYMBOL(pj_strrtrim)
+PJ_EXPORT_SYMBOL(pj_strtrim)
+PJ_EXPORT_SYMBOL(pj_create_random_string)
+PJ_EXPORT_SYMBOL(pj_strtoul)
+PJ_EXPORT_SYMBOL(pj_utoa)
+PJ_EXPORT_SYMBOL(pj_utoa_pad)
+
+/*
+ * timer.h
+ */
+PJ_EXPORT_SYMBOL(pj_timer_heap_mem_size)
+PJ_EXPORT_SYMBOL(pj_timer_heap_create)
+PJ_EXPORT_SYMBOL(pj_timer_entry_init)
+PJ_EXPORT_SYMBOL(pj_timer_heap_schedule)
+PJ_EXPORT_SYMBOL(pj_timer_heap_cancel)
+PJ_EXPORT_SYMBOL(pj_timer_heap_count)
+PJ_EXPORT_SYMBOL(pj_timer_heap_earliest_time)
+PJ_EXPORT_SYMBOL(pj_timer_heap_poll)
+
+/*
+ * types.h
+ */
+PJ_EXPORT_SYMBOL(pj_time_val_normalize)
+
diff --git a/pjlib/src/pj/timer.c b/pjlib/src/pj/timer.c
index ffec1f4d..c3e4f95f 100644
--- a/pjlib/src/pj/timer.c
+++ b/pjlib/src/pj/timer.c
@@ -1,390 +1,411 @@
-/* $Id$
- */
-/* (C)1993-2003 Douglas C. Schmidt
- *
- * This file is originaly from ACE library by Doug Schmidt
- * ACE(TM), TAO(TM) and CIAO(TM) are copyrighted by Douglas C. Schmidt and
- * his research group at Washington University, University of California,
- * Irvine, and Vanderbilt University Copyright
- * (c) 1993-2003, all rights reserved.
- */
-#include <pj/timer.h>
-#include <pj/pool.h>
-#include <pj/os.h>
-#include <pj/string.h>
-#include <pj/assert.h>
-#include <pj/errno.h>
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/* (C)1993-2003 Douglas C. Schmidt
+ *
+ * This file is originaly from ACE library by Doug Schmidt
+ * ACE(TM), TAO(TM) and CIAO(TM) are copyrighted by Douglas C. Schmidt and
+ * his research group at Washington University, University of California,
+ * Irvine, and Vanderbilt University Copyright
+ * (c) 1993-2003, all rights reserved.
+ */
+#include <pj/timer.h>
+#include <pj/pool.h>
+#include <pj/os.h>
+#include <pj/string.h>
+#include <pj/assert.h>
+#include <pj/errno.h>
#include <pj/lock.h>
-
-#define HEAP_PARENT(X) (X == 0 ? 0 : (((X) - 1) / 2))
-#define HEAP_LEFT(X) (((X)+(X))+1)
+
+#define HEAP_PARENT(X) (X == 0 ? 0 : (((X) - 1) / 2))
+#define HEAP_LEFT(X) (((X)+(X))+1)
#define DEFAULT_MAX_TIMED_OUT_PER_POLL (64)
-
-
-/**
- * The implementation of timer heap.
- */
-struct pj_timer_heap_t
-{
- /** Pool from which the timer heap resize will get the storage from */
- pj_pool_t *pool;
-
- /** Maximum size of the heap. */
- pj_size_t max_size;
-
- /** Current size of the heap. */
- pj_size_t cur_size;
+
+
+/**
+ * The implementation of timer heap.
+ */
+struct pj_timer_heap_t
+{
+ /** Pool from which the timer heap resize will get the storage from */
+ pj_pool_t *pool;
+
+ /** Maximum size of the heap. */
+ pj_size_t max_size;
+
+ /** Current size of the heap. */
+ pj_size_t cur_size;
/** Max timed out entries to process per poll. */
unsigned max_entries_per_poll;
-
- /** Lock object. */
- pj_lock_t *lock;
+
+ /** Lock object. */
+ pj_lock_t *lock;
/** Autodelete lock. */
pj_bool_t auto_delete_lock;
-
- /**
- * Current contents of the Heap, which is organized as a "heap" of
- * pj_timer_entry *'s. In this context, a heap is a "partially
- * ordered, almost complete" binary tree, which is stored in an
- * array.
- */
- pj_timer_entry **heap;
-
- /**
- * An array of "pointers" that allows each pj_timer_entry in the
- * <heap_> to be located in O(1) time. Basically, <timer_id_[i]>
- * contains the slot in the <heap_> array where an pj_timer_entry
- * with timer id <i> resides. Thus, the timer id passed back from
- * <schedule_entry> is really an slot into the <timer_ids> array. The
- * <timer_ids_> array serves two purposes: negative values are
- * treated as "pointers" for the <freelist_>, whereas positive
- * values are treated as "pointers" into the <heap_> array.
- */
- pj_timer_id_t *timer_ids;
-
- /**
- * "Pointer" to the first element in the freelist contained within
- * the <timer_ids_> array, which is organized as a stack.
- */
- pj_timer_id_t timer_ids_freelist;
-
- /** Callback to be called when a timer expires. */
- pj_timer_heap_callback *callback;
-
-};
-
-
-
-PJ_INLINE(void) lock_timer_heap( pj_timer_heap_t *ht )
-{
- if (ht->lock) {
- pj_lock_acquire(ht->lock);
- }
-}
-
-PJ_INLINE(void) unlock_timer_heap( pj_timer_heap_t *ht )
-{
- if (ht->lock) {
- pj_lock_release(ht->lock);
- }
-}
-
-
-static void copy_node( pj_timer_heap_t *ht, int slot, pj_timer_entry *moved_node )
-{
- PJ_CHECK_STACK();
-
- // Insert <moved_node> into its new location in the heap.
- ht->heap[slot] = moved_node;
-
- // Update the corresponding slot in the parallel <timer_ids_> array.
- ht->timer_ids[moved_node->_timer_id] = slot;
-}
-
-static pj_timer_id_t pop_freelist( pj_timer_heap_t *ht )
-{
- // We need to truncate this to <int> for backwards compatibility.
- pj_timer_id_t new_id = ht->timer_ids_freelist;
-
- PJ_CHECK_STACK();
-
- // The freelist values in the <timer_ids_> are negative, so we need
- // to negate them to get the next freelist "pointer."
- ht->timer_ids_freelist =
- -ht->timer_ids[ht->timer_ids_freelist];
-
- return new_id;
-
-}
-
-static void push_freelist (pj_timer_heap_t *ht, pj_timer_id_t old_id)
-{
- PJ_CHECK_STACK();
-
- // The freelist values in the <timer_ids_> are negative, so we need
- // to negate them to get the next freelist "pointer."
- ht->timer_ids[old_id] = -ht->timer_ids_freelist;
- ht->timer_ids_freelist = old_id;
-}
-
-
-static void reheap_down(pj_timer_heap_t *ht, pj_timer_entry *moved_node,
- size_t slot, size_t child)
-{
- PJ_CHECK_STACK();
-
- // Restore the heap property after a deletion.
-
- while (child < ht->cur_size)
- {
- // Choose the smaller of the two children.
- if (child + 1 < ht->cur_size
- && PJ_TIME_VAL_LT(ht->heap[child + 1]->_timer_value, ht->heap[child]->_timer_value))
- child++;
-
- // Perform a <copy> if the child has a larger timeout value than
- // the <moved_node>.
- if (PJ_TIME_VAL_LT(ht->heap[child]->_timer_value, moved_node->_timer_value))
- {
- copy_node( ht, slot, ht->heap[child]);
- slot = child;
- child = HEAP_LEFT(child);
- }
- else
- // We've found our location in the heap.
- break;
- }
-
- copy_node( ht, slot, moved_node);
-}
-
-static void reheap_up( pj_timer_heap_t *ht, pj_timer_entry *moved_node,
- size_t slot, size_t parent)
-{
- // Restore the heap property after an insertion.
-
- while (slot > 0)
- {
- // If the parent node is greater than the <moved_node> we need
- // to copy it down.
- if (PJ_TIME_VAL_LT(moved_node->_timer_value, ht->heap[parent]->_timer_value))
- {
- copy_node(ht, slot, ht->heap[parent]);
- slot = parent;
- parent = HEAP_PARENT(slot);
- }
- else
- break;
- }
-
- // Insert the new node into its proper resting place in the heap and
- // update the corresponding slot in the parallel <timer_ids> array.
- copy_node(ht, slot, moved_node);
-}
-
-
-static pj_timer_entry * remove_node( pj_timer_heap_t *ht, size_t slot)
-{
- pj_timer_entry *removed_node = ht->heap[slot];
-
- // Return this timer id to the freelist.
- push_freelist( ht, removed_node->_timer_id );
-
- // Decrement the size of the heap by one since we're removing the
- // "slot"th node.
- ht->cur_size--;
-
- // Set the ID
- removed_node->_timer_id = -1;
-
- // Only try to reheapify if we're not deleting the last entry.
-
- if (slot < ht->cur_size)
- {
- int parent;
- pj_timer_entry *moved_node = ht->heap[ht->cur_size];
-
- // Move the end node to the location being removed and update
- // the corresponding slot in the parallel <timer_ids> array.
- copy_node( ht, slot, moved_node);
-
- // If the <moved_node->time_value_> is great than or equal its
- // parent it needs be moved down the heap.
- parent = HEAP_PARENT (slot);
-
- if (PJ_TIME_VAL_GTE(moved_node->_timer_value, ht->heap[parent]->_timer_value))
- reheap_down( ht, moved_node, slot, HEAP_LEFT(slot));
- else
- reheap_up( ht, moved_node, slot, parent);
- }
-
- return removed_node;
-}
-
-static void grow_heap(pj_timer_heap_t *ht)
-{
- // All the containers will double in size from max_size_
- size_t new_size = ht->max_size * 2;
- pj_timer_id_t *new_timer_ids;
- pj_size_t i;
-
- // First grow the heap itself.
-
- pj_timer_entry **new_heap = 0;
-
- new_heap = pj_pool_alloc(ht->pool, sizeof(pj_timer_entry*) * new_size);
- memcpy(new_heap, ht->heap, ht->max_size * sizeof(pj_timer_entry*));
- //delete [] this->heap_;
- ht->heap = new_heap;
-
- // Grow the array of timer ids.
-
- new_timer_ids = 0;
- new_timer_ids = pj_pool_alloc(ht->pool, new_size * sizeof(pj_timer_id_t));
-
- memcpy( new_timer_ids, ht->timer_ids, ht->max_size * sizeof(pj_timer_id_t));
-
- //delete [] timer_ids_;
- ht->timer_ids = new_timer_ids;
-
- // And add the new elements to the end of the "freelist".
- for (i = ht->max_size; i < new_size; i++)
- ht->timer_ids[i] = -((pj_timer_id_t) (i + 1));
-
- ht->max_size = new_size;
-}
-
-static void insert_node(pj_timer_heap_t *ht, pj_timer_entry *new_node)
-{
- if (ht->cur_size + 2 >= ht->max_size)
- grow_heap(ht);
-
- reheap_up( ht, new_node, ht->cur_size, HEAP_PARENT(ht->cur_size));
- ht->cur_size++;
-}
-
-
-static pj_status_t schedule_entry( pj_timer_heap_t *ht,
- pj_timer_entry *entry,
- const pj_time_val *future_time )
-{
- if (ht->cur_size < ht->max_size)
- {
- // Obtain the next unique sequence number.
- // Set the entry
- entry->_timer_id = pop_freelist(ht);
- entry->_timer_value = *future_time;
- insert_node( ht, entry);
- return 0;
- }
- else
- return -1;
-}
-
-
-static int cancel( pj_timer_heap_t *ht,
- pj_timer_entry *entry,
- int dont_call)
-{
- long timer_node_slot;
-
- PJ_CHECK_STACK();
-
- // Check to see if the timer_id is out of range
- if (entry->_timer_id < 0 || (pj_size_t)entry->_timer_id > ht->max_size)
- return 0;
-
- timer_node_slot = ht->timer_ids[entry->_timer_id];
-
- if (timer_node_slot < 0) // Check to see if timer_id is still valid.
- return 0;
-
- if (entry != ht->heap[timer_node_slot])
- {
- pj_assert(entry == ht->heap[timer_node_slot]);
- return 0;
- }
- else
- {
- remove_node( ht, timer_node_slot);
-
- if (dont_call == 0)
- // Call the close hook.
- (*ht->callback)(ht, entry);
- return 1;
- }
-}
-
-
-/*
- * Calculate memory size required to create a timer heap.
- */
-PJ_DEF(pj_size_t) pj_timer_heap_mem_size(pj_size_t count)
-{
- return /* size of the timer heap itself: */
- sizeof(pj_timer_heap_t) +
- /* size of each entry: */
- (count+2) * (sizeof(pj_timer_entry*)+sizeof(pj_timer_id_t)) +
- /* lock, pool etc: */
- 132;
-}
-
-/*
- * Create a new timer heap.
- */
-PJ_DEF(pj_status_t) pj_timer_heap_create( pj_pool_t *pool,
- pj_size_t size,
- pj_timer_heap_t **p_heap)
-{
- pj_timer_heap_t *ht;
- pj_size_t i;
-
- PJ_ASSERT_RETURN(pool && p_heap, PJ_EINVAL);
-
- *p_heap = NULL;
-
- /* Magic? */
- size += 2;
-
- /* Allocate timer heap data structure from the pool */
- ht = pj_pool_alloc(pool, sizeof(pj_timer_heap_t));
- if (!ht)
- return PJ_ENOMEM;
-
- /* Initialize timer heap sizes */
- ht->max_size = size;
+
+ /**
+ * Current contents of the Heap, which is organized as a "heap" of
+ * pj_timer_entry *'s. In this context, a heap is a "partially
+ * ordered, almost complete" binary tree, which is stored in an
+ * array.
+ */
+ pj_timer_entry **heap;
+
+ /**
+ * An array of "pointers" that allows each pj_timer_entry in the
+ * <heap_> to be located in O(1) time. Basically, <timer_id_[i]>
+ * contains the slot in the <heap_> array where an pj_timer_entry
+ * with timer id <i> resides. Thus, the timer id passed back from
+ * <schedule_entry> is really an slot into the <timer_ids> array. The
+ * <timer_ids_> array serves two purposes: negative values are
+ * treated as "pointers" for the <freelist_>, whereas positive
+ * values are treated as "pointers" into the <heap_> array.
+ */
+ pj_timer_id_t *timer_ids;
+
+ /**
+ * "Pointer" to the first element in the freelist contained within
+ * the <timer_ids_> array, which is organized as a stack.
+ */
+ pj_timer_id_t timer_ids_freelist;
+
+ /** Callback to be called when a timer expires. */
+ pj_timer_heap_callback *callback;
+
+};
+
+
+
+PJ_INLINE(void) lock_timer_heap( pj_timer_heap_t *ht )
+{
+ if (ht->lock) {
+ pj_lock_acquire(ht->lock);
+ }
+}
+
+PJ_INLINE(void) unlock_timer_heap( pj_timer_heap_t *ht )
+{
+ if (ht->lock) {
+ pj_lock_release(ht->lock);
+ }
+}
+
+
+static void copy_node( pj_timer_heap_t *ht, int slot, pj_timer_entry *moved_node )
+{
+ PJ_CHECK_STACK();
+
+ // Insert <moved_node> into its new location in the heap.
+ ht->heap[slot] = moved_node;
+
+ // Update the corresponding slot in the parallel <timer_ids_> array.
+ ht->timer_ids[moved_node->_timer_id] = slot;
+}
+
+static pj_timer_id_t pop_freelist( pj_timer_heap_t *ht )
+{
+ // We need to truncate this to <int> for backwards compatibility.
+ pj_timer_id_t new_id = ht->timer_ids_freelist;
+
+ PJ_CHECK_STACK();
+
+ // The freelist values in the <timer_ids_> are negative, so we need
+ // to negate them to get the next freelist "pointer."
+ ht->timer_ids_freelist =
+ -ht->timer_ids[ht->timer_ids_freelist];
+
+ return new_id;
+
+}
+
+static void push_freelist (pj_timer_heap_t *ht, pj_timer_id_t old_id)
+{
+ PJ_CHECK_STACK();
+
+ // The freelist values in the <timer_ids_> are negative, so we need
+ // to negate them to get the next freelist "pointer."
+ ht->timer_ids[old_id] = -ht->timer_ids_freelist;
+ ht->timer_ids_freelist = old_id;
+}
+
+
+static void reheap_down(pj_timer_heap_t *ht, pj_timer_entry *moved_node,
+ size_t slot, size_t child)
+{
+ PJ_CHECK_STACK();
+
+ // Restore the heap property after a deletion.
+
+ while (child < ht->cur_size)
+ {
+ // Choose the smaller of the two children.
+ if (child + 1 < ht->cur_size
+ && PJ_TIME_VAL_LT(ht->heap[child + 1]->_timer_value, ht->heap[child]->_timer_value))
+ child++;
+
+ // Perform a <copy> if the child has a larger timeout value than
+ // the <moved_node>.
+ if (PJ_TIME_VAL_LT(ht->heap[child]->_timer_value, moved_node->_timer_value))
+ {
+ copy_node( ht, slot, ht->heap[child]);
+ slot = child;
+ child = HEAP_LEFT(child);
+ }
+ else
+ // We've found our location in the heap.
+ break;
+ }
+
+ copy_node( ht, slot, moved_node);
+}
+
+static void reheap_up( pj_timer_heap_t *ht, pj_timer_entry *moved_node,
+ size_t slot, size_t parent)
+{
+ // Restore the heap property after an insertion.
+
+ while (slot > 0)
+ {
+ // If the parent node is greater than the <moved_node> we need
+ // to copy it down.
+ if (PJ_TIME_VAL_LT(moved_node->_timer_value, ht->heap[parent]->_timer_value))
+ {
+ copy_node(ht, slot, ht->heap[parent]);
+ slot = parent;
+ parent = HEAP_PARENT(slot);
+ }
+ else
+ break;
+ }
+
+ // Insert the new node into its proper resting place in the heap and
+ // update the corresponding slot in the parallel <timer_ids> array.
+ copy_node(ht, slot, moved_node);
+}
+
+
+static pj_timer_entry * remove_node( pj_timer_heap_t *ht, size_t slot)
+{
+ pj_timer_entry *removed_node = ht->heap[slot];
+
+ // Return this timer id to the freelist.
+ push_freelist( ht, removed_node->_timer_id );
+
+ // Decrement the size of the heap by one since we're removing the
+ // "slot"th node.
+ ht->cur_size--;
+
+ // Set the ID
+ removed_node->_timer_id = -1;
+
+ // Only try to reheapify if we're not deleting the last entry.
+
+ if (slot < ht->cur_size)
+ {
+ int parent;
+ pj_timer_entry *moved_node = ht->heap[ht->cur_size];
+
+ // Move the end node to the location being removed and update
+ // the corresponding slot in the parallel <timer_ids> array.
+ copy_node( ht, slot, moved_node);
+
+ // If the <moved_node->time_value_> is great than or equal its
+ // parent it needs be moved down the heap.
+ parent = HEAP_PARENT (slot);
+
+ if (PJ_TIME_VAL_GTE(moved_node->_timer_value, ht->heap[parent]->_timer_value))
+ reheap_down( ht, moved_node, slot, HEAP_LEFT(slot));
+ else
+ reheap_up( ht, moved_node, slot, parent);
+ }
+
+ return removed_node;
+}
+
+static void grow_heap(pj_timer_heap_t *ht)
+{
+ // All the containers will double in size from max_size_
+ size_t new_size = ht->max_size * 2;
+ pj_timer_id_t *new_timer_ids;
+ pj_size_t i;
+
+ // First grow the heap itself.
+
+ pj_timer_entry **new_heap = 0;
+
+ new_heap = pj_pool_alloc(ht->pool, sizeof(pj_timer_entry*) * new_size);
+ memcpy(new_heap, ht->heap, ht->max_size * sizeof(pj_timer_entry*));
+ //delete [] this->heap_;
+ ht->heap = new_heap;
+
+ // Grow the array of timer ids.
+
+ new_timer_ids = 0;
+ new_timer_ids = pj_pool_alloc(ht->pool, new_size * sizeof(pj_timer_id_t));
+
+ memcpy( new_timer_ids, ht->timer_ids, ht->max_size * sizeof(pj_timer_id_t));
+
+ //delete [] timer_ids_;
+ ht->timer_ids = new_timer_ids;
+
+ // And add the new elements to the end of the "freelist".
+ for (i = ht->max_size; i < new_size; i++)
+ ht->timer_ids[i] = -((pj_timer_id_t) (i + 1));
+
+ ht->max_size = new_size;
+}
+
+static void insert_node(pj_timer_heap_t *ht, pj_timer_entry *new_node)
+{
+ if (ht->cur_size + 2 >= ht->max_size)
+ grow_heap(ht);
+
+ reheap_up( ht, new_node, ht->cur_size, HEAP_PARENT(ht->cur_size));
+ ht->cur_size++;
+}
+
+
+static pj_status_t schedule_entry( pj_timer_heap_t *ht,
+ pj_timer_entry *entry,
+ const pj_time_val *future_time )
+{
+ if (ht->cur_size < ht->max_size)
+ {
+ // Obtain the next unique sequence number.
+ // Set the entry
+ entry->_timer_id = pop_freelist(ht);
+ entry->_timer_value = *future_time;
+ insert_node( ht, entry);
+ return 0;
+ }
+ else
+ return -1;
+}
+
+
+static int cancel( pj_timer_heap_t *ht,
+ pj_timer_entry *entry,
+ int dont_call)
+{
+ long timer_node_slot;
+
+ PJ_CHECK_STACK();
+
+ // Check to see if the timer_id is out of range
+ if (entry->_timer_id < 0 || (pj_size_t)entry->_timer_id > ht->max_size)
+ return 0;
+
+ timer_node_slot = ht->timer_ids[entry->_timer_id];
+
+ if (timer_node_slot < 0) // Check to see if timer_id is still valid.
+ return 0;
+
+ if (entry != ht->heap[timer_node_slot])
+ {
+ pj_assert(entry == ht->heap[timer_node_slot]);
+ return 0;
+ }
+ else
+ {
+ remove_node( ht, timer_node_slot);
+
+ if (dont_call == 0)
+ // Call the close hook.
+ (*ht->callback)(ht, entry);
+ return 1;
+ }
+}
+
+
+/*
+ * Calculate memory size required to create a timer heap.
+ */
+PJ_DEF(pj_size_t) pj_timer_heap_mem_size(pj_size_t count)
+{
+ return /* size of the timer heap itself: */
+ sizeof(pj_timer_heap_t) +
+ /* size of each entry: */
+ (count+2) * (sizeof(pj_timer_entry*)+sizeof(pj_timer_id_t)) +
+ /* lock, pool etc: */
+ 132;
+}
+
+/*
+ * Create a new timer heap.
+ */
+PJ_DEF(pj_status_t) pj_timer_heap_create( pj_pool_t *pool,
+ pj_size_t size,
+ pj_timer_heap_t **p_heap)
+{
+ pj_timer_heap_t *ht;
+ pj_size_t i;
+
+ PJ_ASSERT_RETURN(pool && p_heap, PJ_EINVAL);
+
+ *p_heap = NULL;
+
+ /* Magic? */
+ size += 2;
+
+ /* Allocate timer heap data structure from the pool */
+ ht = pj_pool_alloc(pool, sizeof(pj_timer_heap_t));
+ if (!ht)
+ return PJ_ENOMEM;
+
+ /* Initialize timer heap sizes */
+ ht->max_size = size;
ht->cur_size = 0;
- ht->max_entries_per_poll = DEFAULT_MAX_TIMED_OUT_PER_POLL;
- ht->timer_ids_freelist = 1;
+ ht->max_entries_per_poll = DEFAULT_MAX_TIMED_OUT_PER_POLL;
+ ht->timer_ids_freelist = 1;
ht->pool = pool;
-
- /* Lock. */
+
+ /* Lock. */
ht->lock = NULL;
ht->auto_delete_lock = 0;
-
- // Create the heap array.
- ht->heap = pj_pool_alloc(pool, sizeof(pj_timer_entry*) * size);
- if (!ht->heap)
- return PJ_ENOMEM;
-
- // Create the parallel
- ht->timer_ids = pj_pool_alloc( pool, sizeof(pj_timer_id_t) * size);
- if (!ht->timer_ids)
- return PJ_ENOMEM;
-
- // Initialize the "freelist," which uses negative values to
- // distinguish freelist elements from "pointers" into the <heap_>
- // array.
- for (i=0; i<size; ++i)
- ht->timer_ids[i] = -((pj_timer_id_t) (i + 1));
-
- *p_heap = ht;
- return PJ_SUCCESS;
-}
+
+ // Create the heap array.
+ ht->heap = pj_pool_alloc(pool, sizeof(pj_timer_entry*) * size);
+ if (!ht->heap)
+ return PJ_ENOMEM;
+
+ // Create the parallel
+ ht->timer_ids = pj_pool_alloc( pool, sizeof(pj_timer_id_t) * size);
+ if (!ht->timer_ids)
+ return PJ_ENOMEM;
+
+ // Initialize the "freelist," which uses negative values to
+ // distinguish freelist elements from "pointers" into the <heap_>
+ // array.
+ for (i=0; i<size; ++i)
+ ht->timer_ids[i] = -((pj_timer_id_t) (i + 1));
+
+ *p_heap = ht;
+ return PJ_SUCCESS;
+}
PJ_DEF(void) pj_timer_heap_destroy( pj_timer_heap_t *ht )
{
@@ -413,111 +434,111 @@ PJ_DEF(unsigned) pj_timer_heap_set_max_timed_out_per_poll(pj_timer_heap_t *ht,
ht->max_entries_per_poll = count;
return old_count;
}
-
-PJ_DEF(pj_timer_entry*) pj_timer_entry_init( pj_timer_entry *entry,
- int id,
- void *user_data,
- pj_timer_heap_callback *cb )
-{
- pj_assert(entry && cb);
-
- entry->id = id;
- entry->user_data = user_data;
- entry->cb = cb;
-
- return entry;
-}
-
-PJ_DEF(pj_status_t) pj_timer_heap_schedule( pj_timer_heap_t *ht,
- pj_timer_entry *entry,
- const pj_time_val *delay)
-{
- pj_status_t status;
- pj_time_val expires;
-
- PJ_ASSERT_RETURN(ht && entry && delay, PJ_EINVAL);
-
- pj_gettimeofday(&expires);
- PJ_TIME_VAL_ADD(expires, *delay);
-
- lock_timer_heap(ht);
- status = schedule_entry(ht, entry, &expires);
- unlock_timer_heap(ht);
-
- return status;
-}
-
-PJ_DEF(int) pj_timer_heap_cancel( pj_timer_heap_t *ht,
- pj_timer_entry *entry)
-{
- int count;
-
- PJ_ASSERT_RETURN(ht && entry, PJ_EINVAL);
-
- lock_timer_heap(ht);
- count = cancel(ht, entry, 1);
- unlock_timer_heap(ht);
-
- return count;
-}
-
+
+PJ_DEF(pj_timer_entry*) pj_timer_entry_init( pj_timer_entry *entry,
+ int id,
+ void *user_data,
+ pj_timer_heap_callback *cb )
+{
+ pj_assert(entry && cb);
+
+ entry->id = id;
+ entry->user_data = user_data;
+ entry->cb = cb;
+
+ return entry;
+}
+
+PJ_DEF(pj_status_t) pj_timer_heap_schedule( pj_timer_heap_t *ht,
+ pj_timer_entry *entry,
+ const pj_time_val *delay)
+{
+ pj_status_t status;
+ pj_time_val expires;
+
+ PJ_ASSERT_RETURN(ht && entry && delay, PJ_EINVAL);
+
+ pj_gettimeofday(&expires);
+ PJ_TIME_VAL_ADD(expires, *delay);
+
+ lock_timer_heap(ht);
+ status = schedule_entry(ht, entry, &expires);
+ unlock_timer_heap(ht);
+
+ return status;
+}
+
+PJ_DEF(int) pj_timer_heap_cancel( pj_timer_heap_t *ht,
+ pj_timer_entry *entry)
+{
+ int count;
+
+ PJ_ASSERT_RETURN(ht && entry, PJ_EINVAL);
+
+ lock_timer_heap(ht);
+ count = cancel(ht, entry, 1);
+ unlock_timer_heap(ht);
+
+ return count;
+}
+
PJ_DEF(unsigned) pj_timer_heap_poll( pj_timer_heap_t *ht,
- pj_time_val *next_delay )
-{
- pj_time_val now;
- unsigned count;
-
- PJ_ASSERT_RETURN(ht, 0);
-
- if (!ht->cur_size && next_delay) {
- next_delay->sec = next_delay->msec = PJ_MAXINT32;
- return 0;
- }
-
- count = 0;
- pj_gettimeofday(&now);
-
- lock_timer_heap(ht);
- while ( ht->cur_size &&
+ pj_time_val *next_delay )
+{
+ pj_time_val now;
+ unsigned count;
+
+ PJ_ASSERT_RETURN(ht, 0);
+
+ if (!ht->cur_size && next_delay) {
+ next_delay->sec = next_delay->msec = PJ_MAXINT32;
+ return 0;
+ }
+
+ count = 0;
+ pj_gettimeofday(&now);
+
+ lock_timer_heap(ht);
+ while ( ht->cur_size &&
PJ_TIME_VAL_LTE(ht->heap[0]->_timer_value, now) &&
- count < ht->max_entries_per_poll )
- {
- pj_timer_entry *node = remove_node(ht, 0);
- ++count;
-
- unlock_timer_heap(ht);
- (*node->cb)(ht, node);
- lock_timer_heap(ht);
- }
- if (ht->cur_size && next_delay) {
- *next_delay = ht->heap[0]->_timer_value;
- PJ_TIME_VAL_SUB(*next_delay, now);
- } else if (next_delay) {
- next_delay->sec = next_delay->msec = PJ_MAXINT32;
- }
- unlock_timer_heap(ht);
-
- return count;
-}
-
-PJ_DEF(pj_size_t) pj_timer_heap_count( pj_timer_heap_t *ht )
+ count < ht->max_entries_per_poll )
+ {
+ pj_timer_entry *node = remove_node(ht, 0);
+ ++count;
+
+ unlock_timer_heap(ht);
+ (*node->cb)(ht, node);
+ lock_timer_heap(ht);
+ }
+ if (ht->cur_size && next_delay) {
+ *next_delay = ht->heap[0]->_timer_value;
+ PJ_TIME_VAL_SUB(*next_delay, now);
+ } else if (next_delay) {
+ next_delay->sec = next_delay->msec = PJ_MAXINT32;
+ }
+ unlock_timer_heap(ht);
+
+ return count;
+}
+
+PJ_DEF(pj_size_t) pj_timer_heap_count( pj_timer_heap_t *ht )
{
PJ_ASSERT_RETURN(ht, 0);
-
- return ht->cur_size;
-}
-
-PJ_DEF(pj_status_t) pj_timer_heap_earliest_time( pj_timer_heap_t * ht,
- pj_time_val *timeval)
-{
- pj_assert(ht->cur_size != 0);
- if (ht->cur_size == 0)
- return PJ_ENOTFOUND;
-
- lock_timer_heap(ht);
- *timeval = ht->heap[0]->_timer_value;
- unlock_timer_heap(ht);
-
- return PJ_SUCCESS;
-}
-
+
+ return ht->cur_size;
+}
+
+PJ_DEF(pj_status_t) pj_timer_heap_earliest_time( pj_timer_heap_t * ht,
+ pj_time_val *timeval)
+{
+ pj_assert(ht->cur_size != 0);
+ if (ht->cur_size == 0)
+ return PJ_ENOTFOUND;
+
+ lock_timer_heap(ht);
+ *timeval = ht->heap[0]->_timer_value;
+ unlock_timer_heap(ht);
+
+ return PJ_SUCCESS;
+}
+
diff --git a/pjlib/src/pj/types.c b/pjlib/src/pj/types.c
index c45e7406..7ca146ee 100644
--- a/pjlib/src/pj/types.c
+++ b/pjlib/src/pj/types.c
@@ -1,31 +1,52 @@
-/* $Id$
- */
-#include <pj/types.h>
-#include <pj/os.h>
-
-void pj_time_val_normalize(pj_time_val *t)
-{
- PJ_CHECK_STACK();
-
- if (t->msec >= 1000) {
- do {
- t->sec++;
- t->msec -= 1000;
- } while (t->msec >= 1000);
- }
- else if (t->msec <= -1000) {
- do {
- t->sec--;
- t->msec += 1000;
- } while (t->msec <= -1000);
- }
-
- if (t->sec >= 1 && t->msec < 0) {
- t->sec--;
- t->msec += 1000;
-
- } else if (t->sec < 0 && t->msec > 0) {
- t->sec++;
- t->msec -= 1000;
- }
-}
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/types.h>
+#include <pj/os.h>
+
+void pj_time_val_normalize(pj_time_val *t)
+{
+ PJ_CHECK_STACK();
+
+ if (t->msec >= 1000) {
+ do {
+ t->sec++;
+ t->msec -= 1000;
+ } while (t->msec >= 1000);
+ }
+ else if (t->msec <= -1000) {
+ do {
+ t->sec--;
+ t->msec += 1000;
+ } while (t->msec <= -1000);
+ }
+
+ if (t->sec >= 1 && t->msec < 0) {
+ t->sec--;
+ t->msec += 1000;
+
+ } else if (t->sec < 0 && t->msec > 0) {
+ t->sec++;
+ t->msec -= 1000;
+ }
+}
diff --git a/pjlib/src/pjlib++-test/main.cpp b/pjlib/src/pjlib++-test/main.cpp
index 99b7f8d5..1b41dbe7 100644
--- a/pjlib/src/pjlib++-test/main.cpp
+++ b/pjlib/src/pjlib++-test/main.cpp
@@ -1,3 +1,24 @@
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
#include <pj++/file.hpp>
#include <pj++/list.hpp>
#include <pj++/lock.hpp>
diff --git a/pjlib/src/pjlib-samples/except.c b/pjlib/src/pjlib-samples/except.c
index ab936c3e..36509e43 100644
--- a/pjlib/src/pjlib-samples/except.c
+++ b/pjlib/src/pjlib-samples/except.c
@@ -1,69 +1,89 @@
-/* $Id$
- */
-#include <pj/except.h>
-#include <pj/rand.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-/**
- * \page page_pjlib_samples_except_c Example: Exception Handling
- *
- * Below is sample program to demonstrate how to use exception handling.
- *
- * \includelineno pjlib-samples/except.c
- */
-
-static pj_exception_id_t NO_MEMORY, OTHER_EXCEPTION;
-
-static void randomly_throw_exception()
-{
- if (pj_rand() % 2)
- PJ_THROW(OTHER_EXCEPTION);
-}
-
-static void *my_malloc(size_t size)
-{
- void *ptr = malloc(size);
- if (!ptr)
- PJ_THROW(NO_MEMORY);
- return ptr;
-}
-
-static int test_exception()
-{
- PJ_USE_EXCEPTION;
-
- PJ_TRY {
- void *data = my_malloc(200);
- free(data);
- randomly_throw_exception();
- }
- PJ_CATCH( NO_MEMORY ) {
- puts("Can't allocate memory");
- return 0;
- }
- PJ_DEFAULT {
- pj_exception_id_t x_id;
-
- x_id = PJ_GET_EXCEPTION();
- printf("Caught exception %d (%s)\n",
- x_id, pj_exception_id_name(x_id));
- }
- PJ_END
- return 1;
-}
-
-int main()
-{
- pj_status_t rc;
-
- // Error handling is omited for clarity.
-
- rc = pj_init();
-
- rc = pj_exception_id_alloc("No Memory", &NO_MEMORY);
- rc = pj_exception_id_alloc("Other Exception", &OTHER_EXCEPTION);
-
- return test_exception();
-}
-
+/* $Id$ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/except.h>
+#include <pj/rand.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/**
+ * \page page_pjlib_samples_except_c Example: Exception Handling
+ *
+ * Below is sample program to demonstrate how to use exception handling.
+ *
+ * \includelineno pjlib-samples/except.c
+ */
+
+static pj_exception_id_t NO_MEMORY, OTHER_EXCEPTION;
+
+static void randomly_throw_exception()
+{
+ if (pj_rand() % 2)
+ PJ_THROW(OTHER_EXCEPTION);
+}
+
+static void *my_malloc(size_t size)
+{
+ void *ptr = malloc(size);
+ if (!ptr)
+ PJ_THROW(NO_MEMORY);
+ return ptr;
+}
+
+static int test_exception()
+{
+ PJ_USE_EXCEPTION;
+
+ PJ_TRY {
+ void *data = my_malloc(200);
+ free(data);
+ randomly_throw_exception();
+ }
+ PJ_CATCH( NO_MEMORY ) {
+ puts("Can't allocate memory");
+ return 0;
+ }
+ PJ_DEFAULT {
+ pj_exception_id_t x_id;
+
+ x_id = PJ_GET_EXCEPTION();
+ printf("Caught exception %d (%s)\n",
+ x_id, pj_exception_id_name(x_id));
+ }
+ PJ_END
+ return 1;
+}
+
+int main()
+{
+ pj_status_t rc;
+
+ // Error handling is omited for clarity.
+
+ rc = pj_init();
+
+ rc = pj_exception_id_alloc("No Memory", &NO_MEMORY);
+ rc = pj_exception_id_alloc("Other Exception", &OTHER_EXCEPTION);
+
+ return test_exception();
+}
+
diff --git a/pjlib/src/pjlib-samples/list.c b/pjlib/src/pjlib-samples/list.c
index 127d8ddf..e478d220 100644
--- a/pjlib/src/pjlib-samples/list.c
+++ b/pjlib/src/pjlib-samples/list.c
@@ -1,55 +1,75 @@
-/* $Id$
- */
-#include <pj/list.h>
-#include <pj/assert.h>
-#include <pj/log.h>
-
-/**
- * \page page_pjlib_samples_list_c Example: List Manipulation
- *
- * Below is sample program to demonstrate how to manipulate linked list.
- *
- * \includelineno pjlib-samples/list.c
- */
-
-struct my_node
-{
- // This must be the first member declared in the struct!
- PJ_DECL_LIST_MEMBER(struct my_node);
- int value;
-};
-
-
-int main()
-{
- struct my_node nodes[10];
- struct my_node list;
- struct my_node *it;
- int i;
-
- // Initialize the list as empty.
- pj_list_init(&list);
-
- // Insert nodes.
- for (i=0; i<10; ++i) {
- nodes[i].value = i;
- pj_list_insert_before(&list, &nodes[i]);
- }
-
- // Iterate list nodes.
- it = list.next;
- while (it != &list) {
- PJ_LOG(3,("list", "value = %d", it->value));
- it = it->next;
- }
-
- // Erase all nodes.
- for (i=0; i<10; ++i) {
- pj_list_erase(&nodes[i]);
- }
-
- // List must be empty by now.
- pj_assert( pj_list_empty(&list) );
-
- return 0;
-};
+/* $Id$ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/list.h>
+#include <pj/assert.h>
+#include <pj/log.h>
+
+/**
+ * \page page_pjlib_samples_list_c Example: List Manipulation
+ *
+ * Below is sample program to demonstrate how to manipulate linked list.
+ *
+ * \includelineno pjlib-samples/list.c
+ */
+
+struct my_node
+{
+ // This must be the first member declared in the struct!
+ PJ_DECL_LIST_MEMBER(struct my_node);
+ int value;
+};
+
+
+int main()
+{
+ struct my_node nodes[10];
+ struct my_node list;
+ struct my_node *it;
+ int i;
+
+ // Initialize the list as empty.
+ pj_list_init(&list);
+
+ // Insert nodes.
+ for (i=0; i<10; ++i) {
+ nodes[i].value = i;
+ pj_list_insert_before(&list, &nodes[i]);
+ }
+
+ // Iterate list nodes.
+ it = list.next;
+ while (it != &list) {
+ PJ_LOG(3,("list", "value = %d", it->value));
+ it = it->next;
+ }
+
+ // Erase all nodes.
+ for (i=0; i<10; ++i) {
+ pj_list_erase(&nodes[i]);
+ }
+
+ // List must be empty by now.
+ pj_assert( pj_list_empty(&list) );
+
+ return 0;
+};
diff --git a/pjlib/src/pjlib-samples/log.c b/pjlib/src/pjlib-samples/log.c
index 2e289764..cf1b7c85 100644
--- a/pjlib/src/pjlib-samples/log.c
+++ b/pjlib/src/pjlib-samples/log.c
@@ -1,26 +1,46 @@
-/* $Id$
- */
-#include <pj/log.h>
-
-/**
- * \page page_pjlib_samples_log_c Example: Log, Hello World
- *
- * Very simple program to write log.
- *
- * \includelineno pjlib-samples/log.c
- */
-
-int main()
-{
- pj_status_t rc;
-
- // Error handling omited for clarity
-
- // Must initialize PJLIB first!
- rc = pj_init();
-
- PJ_LOG(3, ("main.c", "Hello world!"));
-
- return 0;
-}
-
+/* $Id$ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/log.h>
+
+/**
+ * \page page_pjlib_samples_log_c Example: Log, Hello World
+ *
+ * Very simple program to write log.
+ *
+ * \includelineno pjlib-samples/log.c
+ */
+
+int main()
+{
+ pj_status_t rc;
+
+ // Error handling omited for clarity
+
+ // Must initialize PJLIB first!
+ rc = pj_init();
+
+ PJ_LOG(3, ("main.c", "Hello world!"));
+
+ return 0;
+}
+
diff --git a/pjlib/src/pjlib-test/atomic.c b/pjlib/src/pjlib-test/atomic.c
index 09bdfdba..a6d55d25 100644
--- a/pjlib/src/pjlib-test/atomic.c
+++ b/pjlib/src/pjlib-test/atomic.c
@@ -1,92 +1,113 @@
-/* $Id$
- */
-#include "test.h"
-#include <pjlib.h>
-
-/**
- * \page page_pjlib_atomic_test Test: Atomic Variable
- *
- * This file provides implementation of \b atomic_test(). It tests the
- * functionality of the atomic variable API.
- *
- * \section atomic_test_sec Scope of the Test
- *
- * API tested:
- * - pj_atomic_create()
- * - pj_atomic_get()
- * - pj_atomic_inc()
- * - pj_atomic_dec()
- * - pj_atomic_set()
- * - pj_atomic_destroy()
- *
- *
- * This file is <b>pjlib-test/atomic.c</b>
- *
- * \include pjlib-test/atomic.c
- */
-
-
-#if INCLUDE_ATOMIC_TEST
-
-int atomic_test(void)
-{
- pj_pool_t *pool;
- pj_atomic_t *atomic_var;
- pj_status_t rc;
-
- pool = pj_pool_create(mem, NULL, 4096, 0, NULL);
- if (!pool)
- return -10;
-
- /* create() */
- rc = pj_atomic_create(pool, 111, &atomic_var);
- if (rc != 0) {
- return -20;
- }
-
- /* get: check the value. */
- if (pj_atomic_get(atomic_var) != 111)
- return -30;
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "test.h"
+#include <pjlib.h>
+
+/**
+ * \page page_pjlib_atomic_test Test: Atomic Variable
+ *
+ * This file provides implementation of \b atomic_test(). It tests the
+ * functionality of the atomic variable API.
+ *
+ * \section atomic_test_sec Scope of the Test
+ *
+ * API tested:
+ * - pj_atomic_create()
+ * - pj_atomic_get()
+ * - pj_atomic_inc()
+ * - pj_atomic_dec()
+ * - pj_atomic_set()
+ * - pj_atomic_destroy()
+ *
+ *
+ * This file is <b>pjlib-test/atomic.c</b>
+ *
+ * \include pjlib-test/atomic.c
+ */
+
+
+#if INCLUDE_ATOMIC_TEST
+
+int atomic_test(void)
+{
+ pj_pool_t *pool;
+ pj_atomic_t *atomic_var;
+ pj_status_t rc;
+
+ pool = pj_pool_create(mem, NULL, 4096, 0, NULL);
+ if (!pool)
+ return -10;
+
+ /* create() */
+ rc = pj_atomic_create(pool, 111, &atomic_var);
+ if (rc != 0) {
+ return -20;
+ }
+
+ /* get: check the value. */
+ if (pj_atomic_get(atomic_var) != 111)
+ return -30;
/* increment. */
- pj_atomic_inc(atomic_var);
- if (pj_atomic_get(atomic_var) != 112)
- return -40;
-
+ pj_atomic_inc(atomic_var);
+ if (pj_atomic_get(atomic_var) != 112)
+ return -40;
+
/* decrement. */
- pj_atomic_dec(atomic_var);
- if (pj_atomic_get(atomic_var) != 111)
- return -50;
-
+ pj_atomic_dec(atomic_var);
+ if (pj_atomic_get(atomic_var) != 111)
+ return -50;
+
/* set */
- pj_atomic_set(atomic_var, 211);
- if (pj_atomic_get(atomic_var) != 211)
- return -60;
+ pj_atomic_set(atomic_var, 211);
+ if (pj_atomic_get(atomic_var) != 211)
+ return -60;
/* add */
pj_atomic_add(atomic_var, 10);
if (pj_atomic_get(atomic_var) != 221)
return -60;
-
- /* check the value again. */
- if (pj_atomic_get(atomic_var) != 221)
- return -70;
-
- /* destroy */
- rc = pj_atomic_destroy(atomic_var);
- if (rc != 0)
- return -80;
-
- pj_pool_release(pool);
-
- return 0;
-}
-
-
-#else
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled.
- */
-int dummy_atomic_test;
-#endif /* INCLUDE_ATOMIC_TEST */
-
+
+ /* check the value again. */
+ if (pj_atomic_get(atomic_var) != 221)
+ return -70;
+
+ /* destroy */
+ rc = pj_atomic_destroy(atomic_var);
+ if (rc != 0)
+ return -80;
+
+ pj_pool_release(pool);
+
+ return 0;
+}
+
+
+#else
+/* To prevent warning about "translation unit is empty"
+ * when this test is disabled.
+ */
+int dummy_atomic_test;
+#endif /* INCLUDE_ATOMIC_TEST */
+
diff --git a/pjlib/src/pjlib-test/echo_clt.c b/pjlib/src/pjlib-test/echo_clt.c
index afded4f4..ae84b1fb 100644
--- a/pjlib/src/pjlib-test/echo_clt.c
+++ b/pjlib/src/pjlib-test/echo_clt.c
@@ -1,252 +1,273 @@
-/* $Id$
- */
-#include "test.h"
-#include <pjlib.h>
-
-#if INCLUDE_ECHO_CLIENT
-
-enum { BUF_SIZE = 512 };
-
-struct client
-{
- int sock_type;
- const char *server;
- int port;
-};
-
-static pj_atomic_t *totalBytes;
-static pj_atomic_t *timeout_counter;
-static pj_atomic_t *invalid_counter;
-
-#define MSEC_PRINT_DURATION 1000
-
-static int wait_socket(pj_sock_t sock, unsigned msec_timeout)
-{
- pj_fd_set_t fdset;
- pj_time_val timeout;
-
- timeout.sec = 0;
- timeout.msec = msec_timeout;
- pj_time_val_normalize(&timeout);
-
- PJ_FD_ZERO(&fdset);
- PJ_FD_SET(sock, &fdset);
-
- return pj_sock_select(FD_SETSIZE, &fdset, NULL, NULL, &timeout);
-}
-
-static int echo_client_thread(void *arg)
-{
- pj_sock_t sock;
- char send_buf[BUF_SIZE];
- char recv_buf[BUF_SIZE];
- pj_sockaddr_in addr;
- pj_str_t s;
- pj_status_t rc;
- pj_uint32_t buffer_id;
- pj_uint32_t buffer_counter;
- struct client *client = arg;
- pj_status_t last_recv_err = PJ_SUCCESS, last_send_err = PJ_SUCCESS;
- unsigned counter = 0;
-
- rc = app_socket(PJ_AF_INET, client->sock_type, 0, -1, &sock);
- if (rc != PJ_SUCCESS) {
- app_perror("...unable to create socket", rc);
- return -10;
- }
-
- rc = pj_sockaddr_in_init( &addr, pj_cstr(&s, client->server),
- (pj_uint16_t)client->port);
- if (rc != PJ_SUCCESS) {
- app_perror("...unable to resolve server", rc);
- return -15;
- }
-
- rc = pj_sock_connect(sock, &addr, sizeof(addr));
- if (rc != PJ_SUCCESS) {
- app_perror("...connect() error", rc);
- pj_sock_close(sock);
- return -20;
- }
-
- PJ_LOG(3,("", "...socket connected to %s:%d",
- pj_inet_ntoa(addr.sin_addr),
- pj_ntohs(addr.sin_port)));
-
- pj_memset(send_buf, 'A', BUF_SIZE);
- send_buf[BUF_SIZE-1]='\0';
-
- /* Give other thread chance to initialize themselves! */
- pj_thread_sleep(200);
-
- //PJ_LOG(3,("", "...thread %p running", pj_thread_this()));
-
- buffer_id = (pj_uint32_t) pj_thread_this();
- buffer_counter = 0;
-
- *(pj_uint32_t*)send_buf = buffer_id;
-
- for (;;) {
- int rc;
- pj_ssize_t bytes;
-
- ++counter;
-
- //while (wait_socket(sock,0) > 0)
- // ;
-
- /* Send a packet. */
- bytes = BUF_SIZE;
- *(pj_uint32_t*)(send_buf+4) = ++buffer_counter;
- rc = pj_sock_send(sock, send_buf, &bytes, 0);
- if (rc != PJ_SUCCESS || bytes != BUF_SIZE) {
- if (rc != last_send_err) {
- app_perror("...send() error", rc);
- PJ_LOG(3,("", "...ignoring subsequent error.."));
- last_send_err = rc;
- pj_thread_sleep(100);
- }
- continue;
- }
-
- rc = wait_socket(sock, 500);
- if (rc == 0) {
- PJ_LOG(3,("", "...timeout"));
- bytes = 0;
- pj_atomic_inc(timeout_counter);
- } else if (rc < 0) {
- rc = pj_get_netos_error();
- app_perror("...select() error", rc);
- break;
- } else {
- /* Receive back the original packet. */
- bytes = 0;
- do {
- pj_ssize_t received = BUF_SIZE - bytes;
- rc = pj_sock_recv(sock, recv_buf+bytes, &received, 0);
- if (rc != PJ_SUCCESS || received == 0) {
- if (rc != last_recv_err) {
- app_perror("...recv() error", rc);
- PJ_LOG(3,("", "...ignoring subsequent error.."));
- last_recv_err = rc;
- pj_thread_sleep(100);
- }
- bytes = 0;
- received = 0;
- break;
- }
- bytes += received;
- } while (bytes != BUF_SIZE && bytes != 0);
- }
-
- if (bytes == 0)
- continue;
-
- if (pj_memcmp(send_buf, recv_buf, BUF_SIZE) != 0) {
- recv_buf[BUF_SIZE-1] = '\0';
- PJ_LOG(3,("", "...error: buffer %u has changed!\n"
- "send_buf=%s\n"
- "recv_buf=%s\n",
- counter, send_buf, recv_buf));
- pj_atomic_inc(invalid_counter);
- }
-
- /* Accumulate total received. */
- pj_atomic_add(totalBytes, bytes);
- }
-
- pj_sock_close(sock);
- return 0;
-}
-
-int echo_client(int sock_type, const char *server, int port)
-{
- pj_pool_t *pool;
- pj_thread_t *thread[ECHO_CLIENT_MAX_THREADS];
- pj_status_t rc;
- struct client client;
- int i;
- pj_atomic_value_t last_received;
- pj_timestamp last_report;
-
- client.sock_type = sock_type;
- client.server = server;
- client.port = port;
-
- pool = pj_pool_create( mem, NULL, 4000, 4000, NULL );
-
- rc = pj_atomic_create(pool, 0, &totalBytes);
- if (rc != PJ_SUCCESS) {
- PJ_LOG(3,("", "...error: unable to create atomic variable", rc));
- return -30;
- }
- rc = pj_atomic_create(pool, 0, &invalid_counter);
- rc = pj_atomic_create(pool, 0, &timeout_counter);
-
- PJ_LOG(3,("", "Echo client started"));
- PJ_LOG(3,("", " Destination: %s:%d",
- ECHO_SERVER_ADDRESS, ECHO_SERVER_START_PORT));
- PJ_LOG(3,("", " Press Ctrl-C to exit"));
-
- for (i=0; i<ECHO_CLIENT_MAX_THREADS; ++i) {
- rc = pj_thread_create( pool, NULL, &echo_client_thread, &client,
- PJ_THREAD_DEFAULT_STACK_SIZE, 0,
- &thread[i]);
- if (rc != PJ_SUCCESS) {
- app_perror("...error: unable to create thread", rc);
- return -10;
- }
- }
-
- last_received = 0;
- pj_get_timestamp(&last_report);
-
- for (;;) {
- pj_timestamp now;
- unsigned long received, cur_received;
- unsigned msec;
- pj_highprec_t bw;
- pj_time_val elapsed;
- unsigned bw32;
- pj_uint32_t timeout, invalid;
-
- pj_thread_sleep(1000);
-
- pj_get_timestamp(&now);
- elapsed = pj_elapsed_time(&last_report, &now);
- msec = PJ_TIME_VAL_MSEC(elapsed);
-
- received = pj_atomic_get(totalBytes);
- cur_received = received - last_received;
-
- bw = cur_received;
- pj_highprec_mul(bw, 1000);
- pj_highprec_div(bw, msec);
-
- bw32 = (unsigned)bw;
-
- last_report = now;
- last_received = received;
-
- timeout = pj_atomic_get(timeout_counter);
- invalid = pj_atomic_get(invalid_counter);
-
- PJ_LOG(3,("",
- "...%d threads, total bandwidth: %d KB/s, "
- "timeout=%d, invalid=%d",
- ECHO_CLIENT_MAX_THREADS, bw32/1000,
- timeout, invalid));
- }
-
- for (i=0; i<ECHO_CLIENT_MAX_THREADS; ++i) {
- pj_thread_join( thread[i] );
- }
-
- pj_pool_release(pool);
- return 0;
-}
-
-
-#else
-int dummy_echo_client;
-#endif /* INCLUDE_ECHO_CLIENT */
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "test.h"
+#include <pjlib.h>
+
+#if INCLUDE_ECHO_CLIENT
+
+enum { BUF_SIZE = 512 };
+
+struct client
+{
+ int sock_type;
+ const char *server;
+ int port;
+};
+
+static pj_atomic_t *totalBytes;
+static pj_atomic_t *timeout_counter;
+static pj_atomic_t *invalid_counter;
+
+#define MSEC_PRINT_DURATION 1000
+
+static int wait_socket(pj_sock_t sock, unsigned msec_timeout)
+{
+ pj_fd_set_t fdset;
+ pj_time_val timeout;
+
+ timeout.sec = 0;
+ timeout.msec = msec_timeout;
+ pj_time_val_normalize(&timeout);
+
+ PJ_FD_ZERO(&fdset);
+ PJ_FD_SET(sock, &fdset);
+
+ return pj_sock_select(FD_SETSIZE, &fdset, NULL, NULL, &timeout);
+}
+
+static int echo_client_thread(void *arg)
+{
+ pj_sock_t sock;
+ char send_buf[BUF_SIZE];
+ char recv_buf[BUF_SIZE];
+ pj_sockaddr_in addr;
+ pj_str_t s;
+ pj_status_t rc;
+ pj_uint32_t buffer_id;
+ pj_uint32_t buffer_counter;
+ struct client *client = arg;
+ pj_status_t last_recv_err = PJ_SUCCESS, last_send_err = PJ_SUCCESS;
+ unsigned counter = 0;
+
+ rc = app_socket(PJ_AF_INET, client->sock_type, 0, -1, &sock);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...unable to create socket", rc);
+ return -10;
+ }
+
+ rc = pj_sockaddr_in_init( &addr, pj_cstr(&s, client->server),
+ (pj_uint16_t)client->port);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...unable to resolve server", rc);
+ return -15;
+ }
+
+ rc = pj_sock_connect(sock, &addr, sizeof(addr));
+ if (rc != PJ_SUCCESS) {
+ app_perror("...connect() error", rc);
+ pj_sock_close(sock);
+ return -20;
+ }
+
+ PJ_LOG(3,("", "...socket connected to %s:%d",
+ pj_inet_ntoa(addr.sin_addr),
+ pj_ntohs(addr.sin_port)));
+
+ pj_memset(send_buf, 'A', BUF_SIZE);
+ send_buf[BUF_SIZE-1]='\0';
+
+ /* Give other thread chance to initialize themselves! */
+ pj_thread_sleep(200);
+
+ //PJ_LOG(3,("", "...thread %p running", pj_thread_this()));
+
+ buffer_id = (pj_uint32_t) pj_thread_this();
+ buffer_counter = 0;
+
+ *(pj_uint32_t*)send_buf = buffer_id;
+
+ for (;;) {
+ int rc;
+ pj_ssize_t bytes;
+
+ ++counter;
+
+ //while (wait_socket(sock,0) > 0)
+ // ;
+
+ /* Send a packet. */
+ bytes = BUF_SIZE;
+ *(pj_uint32_t*)(send_buf+4) = ++buffer_counter;
+ rc = pj_sock_send(sock, send_buf, &bytes, 0);
+ if (rc != PJ_SUCCESS || bytes != BUF_SIZE) {
+ if (rc != last_send_err) {
+ app_perror("...send() error", rc);
+ PJ_LOG(3,("", "...ignoring subsequent error.."));
+ last_send_err = rc;
+ pj_thread_sleep(100);
+ }
+ continue;
+ }
+
+ rc = wait_socket(sock, 500);
+ if (rc == 0) {
+ PJ_LOG(3,("", "...timeout"));
+ bytes = 0;
+ pj_atomic_inc(timeout_counter);
+ } else if (rc < 0) {
+ rc = pj_get_netos_error();
+ app_perror("...select() error", rc);
+ break;
+ } else {
+ /* Receive back the original packet. */
+ bytes = 0;
+ do {
+ pj_ssize_t received = BUF_SIZE - bytes;
+ rc = pj_sock_recv(sock, recv_buf+bytes, &received, 0);
+ if (rc != PJ_SUCCESS || received == 0) {
+ if (rc != last_recv_err) {
+ app_perror("...recv() error", rc);
+ PJ_LOG(3,("", "...ignoring subsequent error.."));
+ last_recv_err = rc;
+ pj_thread_sleep(100);
+ }
+ bytes = 0;
+ received = 0;
+ break;
+ }
+ bytes += received;
+ } while (bytes != BUF_SIZE && bytes != 0);
+ }
+
+ if (bytes == 0)
+ continue;
+
+ if (pj_memcmp(send_buf, recv_buf, BUF_SIZE) != 0) {
+ recv_buf[BUF_SIZE-1] = '\0';
+ PJ_LOG(3,("", "...error: buffer %u has changed!\n"
+ "send_buf=%s\n"
+ "recv_buf=%s\n",
+ counter, send_buf, recv_buf));
+ pj_atomic_inc(invalid_counter);
+ }
+
+ /* Accumulate total received. */
+ pj_atomic_add(totalBytes, bytes);
+ }
+
+ pj_sock_close(sock);
+ return 0;
+}
+
+int echo_client(int sock_type, const char *server, int port)
+{
+ pj_pool_t *pool;
+ pj_thread_t *thread[ECHO_CLIENT_MAX_THREADS];
+ pj_status_t rc;
+ struct client client;
+ int i;
+ pj_atomic_value_t last_received;
+ pj_timestamp last_report;
+
+ client.sock_type = sock_type;
+ client.server = server;
+ client.port = port;
+
+ pool = pj_pool_create( mem, NULL, 4000, 4000, NULL );
+
+ rc = pj_atomic_create(pool, 0, &totalBytes);
+ if (rc != PJ_SUCCESS) {
+ PJ_LOG(3,("", "...error: unable to create atomic variable", rc));
+ return -30;
+ }
+ rc = pj_atomic_create(pool, 0, &invalid_counter);
+ rc = pj_atomic_create(pool, 0, &timeout_counter);
+
+ PJ_LOG(3,("", "Echo client started"));
+ PJ_LOG(3,("", " Destination: %s:%d",
+ ECHO_SERVER_ADDRESS, ECHO_SERVER_START_PORT));
+ PJ_LOG(3,("", " Press Ctrl-C to exit"));
+
+ for (i=0; i<ECHO_CLIENT_MAX_THREADS; ++i) {
+ rc = pj_thread_create( pool, NULL, &echo_client_thread, &client,
+ PJ_THREAD_DEFAULT_STACK_SIZE, 0,
+ &thread[i]);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error: unable to create thread", rc);
+ return -10;
+ }
+ }
+
+ last_received = 0;
+ pj_get_timestamp(&last_report);
+
+ for (;;) {
+ pj_timestamp now;
+ unsigned long received, cur_received;
+ unsigned msec;
+ pj_highprec_t bw;
+ pj_time_val elapsed;
+ unsigned bw32;
+ pj_uint32_t timeout, invalid;
+
+ pj_thread_sleep(1000);
+
+ pj_get_timestamp(&now);
+ elapsed = pj_elapsed_time(&last_report, &now);
+ msec = PJ_TIME_VAL_MSEC(elapsed);
+
+ received = pj_atomic_get(totalBytes);
+ cur_received = received - last_received;
+
+ bw = cur_received;
+ pj_highprec_mul(bw, 1000);
+ pj_highprec_div(bw, msec);
+
+ bw32 = (unsigned)bw;
+
+ last_report = now;
+ last_received = received;
+
+ timeout = pj_atomic_get(timeout_counter);
+ invalid = pj_atomic_get(invalid_counter);
+
+ PJ_LOG(3,("",
+ "...%d threads, total bandwidth: %d KB/s, "
+ "timeout=%d, invalid=%d",
+ ECHO_CLIENT_MAX_THREADS, bw32/1000,
+ timeout, invalid));
+ }
+
+ for (i=0; i<ECHO_CLIENT_MAX_THREADS; ++i) {
+ pj_thread_join( thread[i] );
+ }
+
+ pj_pool_release(pool);
+ return 0;
+}
+
+
+#else
+int dummy_echo_client;
+#endif /* INCLUDE_ECHO_CLIENT */
diff --git a/pjlib/src/pjlib-test/errno.c b/pjlib/src/pjlib-test/errno.c
index 7bf2887f..6fa3e93b 100644
--- a/pjlib/src/pjlib-test/errno.c
+++ b/pjlib/src/pjlib-test/errno.c
@@ -1,146 +1,166 @@
-/* $Id$
- */
-#include "test.h"
-#include <pj/errno.h>
-#include <pj/log.h>
-#include <pj/ctype.h>
-#include <pj/compat/socket.h>
-#include <pj/string.h>
-
-#if INCLUDE_ERRNO_TEST
-
-#define THIS_FILE "errno"
-
-#if defined(PJ_WIN32) && PJ_WIN32 != 0
-# include <windows.h>
-#endif
-
-#if defined(PJ_HAS_ERRNO_H) && PJ_HAS_ERRNO_H != 0
-# include <errno.h>
-#endif
-
-static void trim_newlines(char *s)
-{
- while (*s) {
- if (*s == '\r' || *s == '\n')
- *s = ' ';
- ++s;
- }
-}
-
-int my_strncasecmp(const char *s1, const char *s2, int max_len)
-{
- while (*s1 && *s2 && max_len > 0) {
- if (pj_tolower(*s1) != pj_tolower(*s2))
- return -1;
- ++s1;
- ++s2;
- --max_len;
- }
- return 0;
-}
-
-const char *my_stristr(const char *whole, const char *part)
-{
- int part_len = strlen(part);
- while (*whole) {
- if (my_strncasecmp(whole, part, part_len) == 0)
- return whole;
- ++whole;
- }
- return NULL;
-}
-
-int errno_test(void)
-{
- enum { CUT = 6 };
- pj_status_t rc;
- char errbuf[256];
-
- PJ_LOG(3,(THIS_FILE, "...errno test: check the msg carefully"));
-
- /*
- * Windows platform error.
- */
-# ifdef ERROR_INVALID_DATA
- rc = PJ_STATUS_FROM_OS(ERROR_INVALID_DATA);
- pj_set_os_error(rc);
-
- /* Whole */
- pj_strerror(rc, errbuf, sizeof(errbuf));
- trim_newlines(errbuf);
- PJ_LOG(3,(THIS_FILE, "...msg for rc=ERROR_INVALID_DATA: '%s'", errbuf));
- if (my_stristr(errbuf, "invalid") == NULL) {
- PJ_LOG(3, (THIS_FILE,
- "...error: expecting \"invalid\" string in the msg"));
- return -20;
- }
-
- /* Cut version. */
- pj_strerror(rc, errbuf, CUT);
- PJ_LOG(3,(THIS_FILE, "...msg for rc=ERROR_INVALID_DATA (cut): '%s'", errbuf));
-# endif
-
- /*
- * Unix errors
- */
-# ifdef EINVAL
- rc = PJ_STATUS_FROM_OS(EINVAL);
- pj_set_os_error(rc);
-
- /* Whole */
- pj_strerror(rc, errbuf, sizeof(errbuf));
- trim_newlines(errbuf);
- PJ_LOG(3,(THIS_FILE, "...msg for rc=EINVAL: '%s'", errbuf));
- if (my_stristr(errbuf, "invalid") == NULL) {
- PJ_LOG(3, (THIS_FILE,
- "...error: expecting \"invalid\" string in the msg"));
- return -30;
- }
-
- /* Cut */
- pj_strerror(rc, errbuf, CUT);
- PJ_LOG(3,(THIS_FILE, "...msg for rc=EINVAL (cut): '%s'", errbuf));
-# endif
-
- /*
- * Windows WSA errors
- */
-# ifdef WSAEINVAL
- rc = PJ_STATUS_FROM_OS(WSAEINVAL);
- pj_set_os_error(rc);
-
- /* Whole */
- pj_strerror(rc, errbuf, sizeof(errbuf));
- trim_newlines(errbuf);
- PJ_LOG(3,(THIS_FILE, "...msg for rc=WSAEINVAL: '%s'", errbuf));
- if (my_stristr(errbuf, "invalid") == NULL) {
- PJ_LOG(3, (THIS_FILE,
- "...error: expecting \"invalid\" string in the msg"));
- return -40;
- }
-
- /* Cut */
- pj_strerror(rc, errbuf, CUT);
- PJ_LOG(3,(THIS_FILE, "...msg for rc=WSAEINVAL (cut): '%s'", errbuf));
-# endif
-
- pj_strerror(PJ_EBUG, errbuf, sizeof(errbuf));
- PJ_LOG(3,(THIS_FILE, "...msg for rc=PJ_EBUG: '%s'", errbuf));
- if (my_stristr(errbuf, "BUG") == NULL) {
- PJ_LOG(3, (THIS_FILE,
- "...error: expecting \"BUG\" string in the msg"));
- return -20;
- }
-
- pj_strerror(PJ_EBUG, errbuf, CUT);
- PJ_LOG(3,(THIS_FILE, "...msg for rc=PJ_EBUG, cut at %d chars: '%s'",
- CUT, errbuf));
-
- return 0;
-}
-
-
-#endif /* INCLUDE_ERRNO_TEST */
-
-
+/* $Id$ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "test.h"
+#include <pj/errno.h>
+#include <pj/log.h>
+#include <pj/ctype.h>
+#include <pj/compat/socket.h>
+#include <pj/string.h>
+
+#if INCLUDE_ERRNO_TEST
+
+#define THIS_FILE "errno"
+
+#if defined(PJ_WIN32) && PJ_WIN32 != 0
+# include <windows.h>
+#endif
+
+#if defined(PJ_HAS_ERRNO_H) && PJ_HAS_ERRNO_H != 0
+# include <errno.h>
+#endif
+
+static void trim_newlines(char *s)
+{
+ while (*s) {
+ if (*s == '\r' || *s == '\n')
+ *s = ' ';
+ ++s;
+ }
+}
+
+int my_strncasecmp(const char *s1, const char *s2, int max_len)
+{
+ while (*s1 && *s2 && max_len > 0) {
+ if (pj_tolower(*s1) != pj_tolower(*s2))
+ return -1;
+ ++s1;
+ ++s2;
+ --max_len;
+ }
+ return 0;
+}
+
+const char *my_stristr(const char *whole, const char *part)
+{
+ int part_len = strlen(part);
+ while (*whole) {
+ if (my_strncasecmp(whole, part, part_len) == 0)
+ return whole;
+ ++whole;
+ }
+ return NULL;
+}
+
+int errno_test(void)
+{
+ enum { CUT = 6 };
+ pj_status_t rc;
+ char errbuf[256];
+
+ PJ_LOG(3,(THIS_FILE, "...errno test: check the msg carefully"));
+
+ /*
+ * Windows platform error.
+ */
+# ifdef ERROR_INVALID_DATA
+ rc = PJ_STATUS_FROM_OS(ERROR_INVALID_DATA);
+ pj_set_os_error(rc);
+
+ /* Whole */
+ pj_strerror(rc, errbuf, sizeof(errbuf));
+ trim_newlines(errbuf);
+ PJ_LOG(3,(THIS_FILE, "...msg for rc=ERROR_INVALID_DATA: '%s'", errbuf));
+ if (my_stristr(errbuf, "invalid") == NULL) {
+ PJ_LOG(3, (THIS_FILE,
+ "...error: expecting \"invalid\" string in the msg"));
+ return -20;
+ }
+
+ /* Cut version. */
+ pj_strerror(rc, errbuf, CUT);
+ PJ_LOG(3,(THIS_FILE, "...msg for rc=ERROR_INVALID_DATA (cut): '%s'", errbuf));
+# endif
+
+ /*
+ * Unix errors
+ */
+# ifdef EINVAL
+ rc = PJ_STATUS_FROM_OS(EINVAL);
+ pj_set_os_error(rc);
+
+ /* Whole */
+ pj_strerror(rc, errbuf, sizeof(errbuf));
+ trim_newlines(errbuf);
+ PJ_LOG(3,(THIS_FILE, "...msg for rc=EINVAL: '%s'", errbuf));
+ if (my_stristr(errbuf, "invalid") == NULL) {
+ PJ_LOG(3, (THIS_FILE,
+ "...error: expecting \"invalid\" string in the msg"));
+ return -30;
+ }
+
+ /* Cut */
+ pj_strerror(rc, errbuf, CUT);
+ PJ_LOG(3,(THIS_FILE, "...msg for rc=EINVAL (cut): '%s'", errbuf));
+# endif
+
+ /*
+ * Windows WSA errors
+ */
+# ifdef WSAEINVAL
+ rc = PJ_STATUS_FROM_OS(WSAEINVAL);
+ pj_set_os_error(rc);
+
+ /* Whole */
+ pj_strerror(rc, errbuf, sizeof(errbuf));
+ trim_newlines(errbuf);
+ PJ_LOG(3,(THIS_FILE, "...msg for rc=WSAEINVAL: '%s'", errbuf));
+ if (my_stristr(errbuf, "invalid") == NULL) {
+ PJ_LOG(3, (THIS_FILE,
+ "...error: expecting \"invalid\" string in the msg"));
+ return -40;
+ }
+
+ /* Cut */
+ pj_strerror(rc, errbuf, CUT);
+ PJ_LOG(3,(THIS_FILE, "...msg for rc=WSAEINVAL (cut): '%s'", errbuf));
+# endif
+
+ pj_strerror(PJ_EBUG, errbuf, sizeof(errbuf));
+ PJ_LOG(3,(THIS_FILE, "...msg for rc=PJ_EBUG: '%s'", errbuf));
+ if (my_stristr(errbuf, "BUG") == NULL) {
+ PJ_LOG(3, (THIS_FILE,
+ "...error: expecting \"BUG\" string in the msg"));
+ return -20;
+ }
+
+ pj_strerror(PJ_EBUG, errbuf, CUT);
+ PJ_LOG(3,(THIS_FILE, "...msg for rc=PJ_EBUG, cut at %d chars: '%s'",
+ CUT, errbuf));
+
+ return 0;
+}
+
+
+#endif /* INCLUDE_ERRNO_TEST */
+
+
diff --git a/pjlib/src/pjlib-test/exception.c b/pjlib/src/pjlib-test/exception.c
index 31a4a545..be0886e1 100644
--- a/pjlib/src/pjlib-test/exception.c
+++ b/pjlib/src/pjlib-test/exception.c
@@ -1,161 +1,182 @@
-/* $Id$
- */
-#include "test.h"
-
-
-/**
- * \page page_pjlib_exception_test Test: Exception Handling
- *
- * This file provides implementation of \b exception_test(). It tests the
- * functionality of the exception handling API.
- *
- * @note This test use static ID not acquired through proper registration.
- * This is not recommended, since it may create ID collissions.
- *
- * \section exception_test_sec Scope of the Test
- *
- * Some scenarios tested:
- * - no exception situation
- * - basic TRY/CATCH
- * - multiple exception handlers
- * - default handlers
- *
- *
- * This file is <b>pjlib-test/exception.c</b>
- *
- * \include pjlib-test/exception.c
- */
-
-
-#if INCLUDE_EXCEPTION_TEST
-
-#include <pjlib.h>
-
-#define ID_1 1
-#define ID_2 2
-
-static int throw_id_1(void)
-{
- PJ_THROW( ID_1 );
- return -1;
-}
-
-static int throw_id_2(void)
-{
- PJ_THROW( ID_2 );
- return -1;
-}
-
-
-static int test(void)
-{
- PJ_USE_EXCEPTION;
- int rc = 0;
-
- /*
- * No exception situation.
- */
- PJ_TRY {
- rc = rc;
- }
- PJ_CATCH( ID_1 ) {
- rc = -2;
- }
- PJ_DEFAULT {
- rc = -3;
- }
- PJ_END;
-
- if (rc != 0)
- return rc;
-
-
- /*
- * Basic TRY/CATCH
- */
- PJ_TRY {
- rc = throw_id_1();
-
- // should not reach here.
- rc = -10;
- }
- PJ_CATCH( ID_1 ) {
- if (!rc) rc = 0;
- }
- PJ_DEFAULT {
- int id = PJ_GET_EXCEPTION();
- PJ_LOG(3,("", "...error: got unexpected exception %d (%s)",
- id, pj_exception_id_name(id)));
- if (!rc) rc = -20;
- }
- PJ_END;
-
- if (rc != 0)
- return rc;
-
- /*
- * Multiple exceptions handlers
- */
- PJ_TRY {
- rc = throw_id_2();
- // should not reach here.
- rc = -25;
- }
- PJ_CATCH( ID_1 ) {
- if (!rc) rc = -30;
- }
- PJ_CATCH( ID_2 ) {
- if (!rc) rc = 0;
- }
- PJ_DEFAULT {
- if (!rc) rc = -40;
- }
- PJ_END;
-
- if (rc != 0)
- return rc;
-
- /*
- * Test default handler.
- */
- PJ_TRY {
- rc = throw_id_1();
- // should not reach here
- rc = -50;
- }
- PJ_CATCH( ID_2 ) {
- if (!rc) rc = -60;
- }
- PJ_DEFAULT {
- if (!rc) rc = 0;
- }
- PJ_END;
-
- if (rc != 0)
- return rc;
-
- return 0;
-}
-
-int exception_test(void)
-{
- int i, rc;
- enum { LOOP = 10 };
-
- for (i=0; i<LOOP; ++i) {
- if ((rc=test()) != 0) {
- PJ_LOG(3,("", "...failed at i=%d (rc=%d)", i, rc));
- return rc;
- }
- }
- return 0;
-}
-
-#else
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled.
- */
-int dummy_exception_test;
-#endif /* INCLUDE_EXCEPTION_TEST */
-
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "test.h"
+
+
+/**
+ * \page page_pjlib_exception_test Test: Exception Handling
+ *
+ * This file provides implementation of \b exception_test(). It tests the
+ * functionality of the exception handling API.
+ *
+ * @note This test use static ID not acquired through proper registration.
+ * This is not recommended, since it may create ID collissions.
+ *
+ * \section exception_test_sec Scope of the Test
+ *
+ * Some scenarios tested:
+ * - no exception situation
+ * - basic TRY/CATCH
+ * - multiple exception handlers
+ * - default handlers
+ *
+ *
+ * This file is <b>pjlib-test/exception.c</b>
+ *
+ * \include pjlib-test/exception.c
+ */
+
+
+#if INCLUDE_EXCEPTION_TEST
+
+#include <pjlib.h>
+
+#define ID_1 1
+#define ID_2 2
+
+static int throw_id_1(void)
+{
+ PJ_THROW( ID_1 );
+ return -1;
+}
+
+static int throw_id_2(void)
+{
+ PJ_THROW( ID_2 );
+ return -1;
+}
+
+
+static int test(void)
+{
+ PJ_USE_EXCEPTION;
+ int rc = 0;
+
+ /*
+ * No exception situation.
+ */
+ PJ_TRY {
+ rc = rc;
+ }
+ PJ_CATCH( ID_1 ) {
+ rc = -2;
+ }
+ PJ_DEFAULT {
+ rc = -3;
+ }
+ PJ_END;
+
+ if (rc != 0)
+ return rc;
+
+
+ /*
+ * Basic TRY/CATCH
+ */
+ PJ_TRY {
+ rc = throw_id_1();
+
+ // should not reach here.
+ rc = -10;
+ }
+ PJ_CATCH( ID_1 ) {
+ if (!rc) rc = 0;
+ }
+ PJ_DEFAULT {
+ int id = PJ_GET_EXCEPTION();
+ PJ_LOG(3,("", "...error: got unexpected exception %d (%s)",
+ id, pj_exception_id_name(id)));
+ if (!rc) rc = -20;
+ }
+ PJ_END;
+
+ if (rc != 0)
+ return rc;
+
+ /*
+ * Multiple exceptions handlers
+ */
+ PJ_TRY {
+ rc = throw_id_2();
+ // should not reach here.
+ rc = -25;
+ }
+ PJ_CATCH( ID_1 ) {
+ if (!rc) rc = -30;
+ }
+ PJ_CATCH( ID_2 ) {
+ if (!rc) rc = 0;
+ }
+ PJ_DEFAULT {
+ if (!rc) rc = -40;
+ }
+ PJ_END;
+
+ if (rc != 0)
+ return rc;
+
+ /*
+ * Test default handler.
+ */
+ PJ_TRY {
+ rc = throw_id_1();
+ // should not reach here
+ rc = -50;
+ }
+ PJ_CATCH( ID_2 ) {
+ if (!rc) rc = -60;
+ }
+ PJ_DEFAULT {
+ if (!rc) rc = 0;
+ }
+ PJ_END;
+
+ if (rc != 0)
+ return rc;
+
+ return 0;
+}
+
+int exception_test(void)
+{
+ int i, rc;
+ enum { LOOP = 10 };
+
+ for (i=0; i<LOOP; ++i) {
+ if ((rc=test()) != 0) {
+ PJ_LOG(3,("", "...failed at i=%d (rc=%d)", i, rc));
+ return rc;
+ }
+ }
+ return 0;
+}
+
+#else
+/* To prevent warning about "translation unit is empty"
+ * when this test is disabled.
+ */
+int dummy_exception_test;
+#endif /* INCLUDE_EXCEPTION_TEST */
+
+
diff --git a/pjlib/src/pjlib-test/fifobuf.c b/pjlib/src/pjlib-test/fifobuf.c
index 2f59473d..55d4c5aa 100644
--- a/pjlib/src/pjlib-test/fifobuf.c
+++ b/pjlib/src/pjlib-test/fifobuf.c
@@ -1,100 +1,121 @@
-/* $Id$
- */
-#include "test.h"
-
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled.
- */
-int dummy_fifobuf_test;
-
-#if INCLUDE_FIFOBUF_TEST
-
-#include <pjlib.h>
-
-int fifobuf_test()
-{
- enum { SIZE = 1024, MAX_ENTRIES = 128,
- MIN_SIZE = 4, MAX_SIZE = 64,
- LOOP=10000 };
- pj_pool_t *pool;
- pj_fifobuf_t fifo;
- unsigned available = SIZE;
- void *entries[MAX_ENTRIES];
- void *buffer;
- int i;
-
- pool = pj_pool_create(mem, NULL, SIZE+256, 0, NULL);
- if (!pool)
- return -10;
-
- buffer = pj_pool_alloc(pool, SIZE);
- if (!buffer)
- return -20;
-
- pj_fifobuf_init (&fifo, buffer, SIZE);
-
- // Test 1
- for (i=0; i<LOOP*MAX_ENTRIES; ++i) {
- int size;
- int c, f;
- c = i%2;
- f = (i+1)%2;
- do {
- size = MIN_SIZE+(pj_rand() % MAX_SIZE);
- entries[c] = pj_fifobuf_alloc (&fifo, size);
- } while (entries[c] == 0);
- if ( i!=0) {
- pj_fifobuf_free(&fifo, entries[f]);
- }
- }
- if (entries[(i+1)%2])
- pj_fifobuf_free(&fifo, entries[(i+1)%2]);
-
- if (pj_fifobuf_max_size(&fifo) < SIZE-4) {
- pj_assert(0);
- return -1;
- }
-
- // Test 2
- entries[0] = pj_fifobuf_alloc (&fifo, MIN_SIZE);
- if (!entries[0]) return -1;
- for (i=0; i<LOOP*MAX_ENTRIES; ++i) {
- int size = MIN_SIZE+(pj_rand() % MAX_SIZE);
- entries[1] = pj_fifobuf_alloc (&fifo, size);
- if (entries[1])
- pj_fifobuf_unalloc(&fifo, entries[1]);
- }
- pj_fifobuf_unalloc(&fifo, entries[0]);
- if (pj_fifobuf_max_size(&fifo) < SIZE-4) {
- pj_assert(0);
- return -2;
- }
-
- // Test 3
- for (i=0; i<LOOP; ++i) {
- int count, j;
- for (count=0; available>=MIN_SIZE+4 && count < MAX_ENTRIES;) {
- int size = MIN_SIZE+(pj_rand() % MAX_SIZE);
- entries[count] = pj_fifobuf_alloc (&fifo, size);
- if (entries[count]) {
- available -= (size+4);
- ++count;
- }
- }
- for (j=0; j<count; ++j) {
- pj_fifobuf_free (&fifo, entries[j]);
- }
- available = SIZE;
- }
-
- if (pj_fifobuf_max_size(&fifo) < SIZE-4) {
- pj_assert(0);
- return -3;
- }
- pj_pool_release(pool);
- return 0;
-}
-
-#endif /* INCLUDE_FIFOBUF_TEST */
-
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "test.h"
+
+/* To prevent warning about "translation unit is empty"
+ * when this test is disabled.
+ */
+int dummy_fifobuf_test;
+
+#if INCLUDE_FIFOBUF_TEST
+
+#include <pjlib.h>
+
+int fifobuf_test()
+{
+ enum { SIZE = 1024, MAX_ENTRIES = 128,
+ MIN_SIZE = 4, MAX_SIZE = 64,
+ LOOP=10000 };
+ pj_pool_t *pool;
+ pj_fifobuf_t fifo;
+ unsigned available = SIZE;
+ void *entries[MAX_ENTRIES];
+ void *buffer;
+ int i;
+
+ pool = pj_pool_create(mem, NULL, SIZE+256, 0, NULL);
+ if (!pool)
+ return -10;
+
+ buffer = pj_pool_alloc(pool, SIZE);
+ if (!buffer)
+ return -20;
+
+ pj_fifobuf_init (&fifo, buffer, SIZE);
+
+ // Test 1
+ for (i=0; i<LOOP*MAX_ENTRIES; ++i) {
+ int size;
+ int c, f;
+ c = i%2;
+ f = (i+1)%2;
+ do {
+ size = MIN_SIZE+(pj_rand() % MAX_SIZE);
+ entries[c] = pj_fifobuf_alloc (&fifo, size);
+ } while (entries[c] == 0);
+ if ( i!=0) {
+ pj_fifobuf_free(&fifo, entries[f]);
+ }
+ }
+ if (entries[(i+1)%2])
+ pj_fifobuf_free(&fifo, entries[(i+1)%2]);
+
+ if (pj_fifobuf_max_size(&fifo) < SIZE-4) {
+ pj_assert(0);
+ return -1;
+ }
+
+ // Test 2
+ entries[0] = pj_fifobuf_alloc (&fifo, MIN_SIZE);
+ if (!entries[0]) return -1;
+ for (i=0; i<LOOP*MAX_ENTRIES; ++i) {
+ int size = MIN_SIZE+(pj_rand() % MAX_SIZE);
+ entries[1] = pj_fifobuf_alloc (&fifo, size);
+ if (entries[1])
+ pj_fifobuf_unalloc(&fifo, entries[1]);
+ }
+ pj_fifobuf_unalloc(&fifo, entries[0]);
+ if (pj_fifobuf_max_size(&fifo) < SIZE-4) {
+ pj_assert(0);
+ return -2;
+ }
+
+ // Test 3
+ for (i=0; i<LOOP; ++i) {
+ int count, j;
+ for (count=0; available>=MIN_SIZE+4 && count < MAX_ENTRIES;) {
+ int size = MIN_SIZE+(pj_rand() % MAX_SIZE);
+ entries[count] = pj_fifobuf_alloc (&fifo, size);
+ if (entries[count]) {
+ available -= (size+4);
+ ++count;
+ }
+ }
+ for (j=0; j<count; ++j) {
+ pj_fifobuf_free (&fifo, entries[j]);
+ }
+ available = SIZE;
+ }
+
+ if (pj_fifobuf_max_size(&fifo) < SIZE-4) {
+ pj_assert(0);
+ return -3;
+ }
+ pj_pool_release(pool);
+ return 0;
+}
+
+#endif /* INCLUDE_FIFOBUF_TEST */
+
+
diff --git a/pjlib/src/pjlib-test/file.c b/pjlib/src/pjlib-test/file.c
index b3ab6e32..6e5611ad 100644
--- a/pjlib/src/pjlib-test/file.c
+++ b/pjlib/src/pjlib-test/file.c
@@ -1,4 +1,25 @@
/* $Id$ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
#include "test.h"
#include <pjlib.h>
diff --git a/pjlib/src/pjlib-test/ioq_perf.c b/pjlib/src/pjlib-test/ioq_perf.c
index cfeaab76..2d76a011 100644
--- a/pjlib/src/pjlib-test/ioq_perf.c
+++ b/pjlib/src/pjlib-test/ioq_perf.c
@@ -1,486 +1,507 @@
-/* $Id$
- */
-#include "test.h"
-#include <pjlib.h>
-#include <pj/compat/high_precision.h>
-
-/**
- * \page page_pjlib_ioqueue_perf_test Test: I/O Queue Performance
- *
- * Test the performance of the I/O queue, using typical producer
- * consumer test. The test should examine the effect of using multiple
- * threads on the performance.
- *
- * This file is <b>pjlib-test/ioq_perf.c</b>
- *
- * \include pjlib-test/ioq_perf.c
- */
-
-#if INCLUDE_IOQUEUE_PERF_TEST
-
-#ifdef _MSC_VER
-# pragma warning ( disable: 4204) // non-constant aggregate initializer
-#endif
-
-#define THIS_FILE "ioq_perf"
-//#define TRACE_(expr) PJ_LOG(3,expr)
-#define TRACE_(expr)
-
-
-static pj_bool_t thread_quit_flag;
-static pj_status_t last_error;
-static unsigned last_error_counter;
-
-/* Descriptor for each producer/consumer pair. */
-typedef struct test_item
-{
- pj_sock_t server_fd,
- client_fd;
- pj_ioqueue_t *ioqueue;
- pj_ioqueue_key_t *server_key,
- *client_key;
- pj_ioqueue_op_key_t recv_op,
- send_op;
- int has_pending_send;
- pj_size_t buffer_size;
- char *outgoing_buffer;
- char *incoming_buffer;
- pj_size_t bytes_sent,
- bytes_recv;
-} test_item;
-
-/* Callback when data has been read.
- * Increment item->bytes_recv and ready to read the next data.
- */
-static void on_read_complete(pj_ioqueue_key_t *key,
- pj_ioqueue_op_key_t *op_key,
- pj_ssize_t bytes_read)
-{
- test_item *item = pj_ioqueue_get_user_data(key);
- pj_status_t rc;
- int data_is_available = 1;
-
- //TRACE_((THIS_FILE, " read complete, bytes_read=%d", bytes_read));
-
- do {
- if (thread_quit_flag)
- return;
-
- if (bytes_read < 0) {
- pj_status_t rc = -bytes_read;
- char errmsg[128];
-
- if (rc != last_error) {
- //last_error = rc;
- pj_strerror(rc, errmsg, sizeof(errmsg));
- PJ_LOG(3,(THIS_FILE, "...error: read error, bytes_read=%d (%s)",
- bytes_read, errmsg));
- PJ_LOG(3,(THIS_FILE,
- ".....additional info: total read=%u, total sent=%u",
- item->bytes_recv, item->bytes_sent));
- } else {
- last_error_counter++;
- }
- bytes_read = 0;
-
- } else if (bytes_read == 0) {
- PJ_LOG(3,(THIS_FILE, "...socket has closed!"));
- }
-
- item->bytes_recv += bytes_read;
-
- /* To assure that the test quits, even if main thread
- * doesn't have time to run.
- */
- if (item->bytes_recv > item->buffer_size * 10000)
- thread_quit_flag = 1;
-
- bytes_read = item->buffer_size;
- rc = pj_ioqueue_recv( key, op_key,
- item->incoming_buffer, &bytes_read, 0 );
-
- if (rc == PJ_SUCCESS) {
- data_is_available = 1;
- } else if (rc == PJ_EPENDING) {
- data_is_available = 0;
- } else {
- data_is_available = 0;
- if (rc != last_error) {
- last_error = rc;
- app_perror("...error: read error(1)", rc);
- } else {
- last_error_counter++;
- }
- }
-
- if (!item->has_pending_send) {
- pj_ssize_t sent = item->buffer_size;
- rc = pj_ioqueue_send(item->client_key, &item->send_op,
- item->outgoing_buffer, &sent, 0);
- if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
- app_perror("...error: write error", rc);
- }
-
- item->has_pending_send = (rc==PJ_EPENDING);
- }
-
- } while (data_is_available);
-}
-
-/* Callback when data has been written.
- * Increment item->bytes_sent and write the next data.
- */
-static void on_write_complete(pj_ioqueue_key_t *key,
- pj_ioqueue_op_key_t *op_key,
- pj_ssize_t bytes_sent)
-{
- test_item *item = pj_ioqueue_get_user_data(key);
-
- //TRACE_((THIS_FILE, " write complete: sent = %d", bytes_sent));
-
- if (thread_quit_flag)
- return;
-
- item->has_pending_send = 0;
- item->bytes_sent += bytes_sent;
-
- if (bytes_sent <= 0) {
- PJ_LOG(3,(THIS_FILE, "...error: sending stopped. bytes_sent=%d",
- bytes_sent));
- }
- else {
- pj_status_t rc;
-
- bytes_sent = item->buffer_size;
- rc = pj_ioqueue_send( item->client_key, op_key,
- item->outgoing_buffer, &bytes_sent, 0);
- if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
- app_perror("...error: write error", rc);
- }
-
- item->has_pending_send = (rc==PJ_EPENDING);
- }
-}
-
-/* The worker thread. */
-static int worker_thread(void *arg)
-{
- pj_ioqueue_t *ioqueue = arg;
- const pj_time_val timeout = {0, 100};
- int rc;
-
- while (!thread_quit_flag) {
- rc = pj_ioqueue_poll(ioqueue, &timeout);
- //TRACE_((THIS_FILE, " thread: poll returned rc=%d", rc));
- if (rc < 0) {
- app_perror("...error in pj_ioqueue_poll()", pj_get_netos_error());
- return -1;
- }
- }
- return 0;
-}
-
-/* Calculate the bandwidth for the specific test configuration.
- * The test is simple:
- * - create sockpair_cnt number of producer-consumer socket pair.
- * - create thread_cnt number of worker threads.
- * - each producer will send buffer_size bytes data as fast and
- * as soon as it can.
- * - each consumer will read buffer_size bytes of data as fast
- * as it could.
- * - measure the total bytes received by all consumers during a
- * period of time.
- */
-static int perform_test(int sock_type, const char *type_name,
- unsigned thread_cnt, unsigned sockpair_cnt,
- pj_size_t buffer_size,
- pj_size_t *p_bandwidth)
-{
- enum { MSEC_DURATION = 5000 };
- pj_pool_t *pool;
- test_item *items;
- pj_thread_t **thread;
- pj_ioqueue_t *ioqueue;
- pj_status_t rc;
- pj_ioqueue_callback ioqueue_callback;
- pj_uint32_t total_elapsed_usec, total_received;
- pj_highprec_t bandwidth;
- pj_timestamp start, stop;
- unsigned i;
-
- TRACE_((THIS_FILE, " starting test.."));
-
- ioqueue_callback.on_read_complete = &on_read_complete;
- ioqueue_callback.on_write_complete = &on_write_complete;
-
- thread_quit_flag = 0;
-
- pool = pj_pool_create(mem, NULL, 4096, 4096, NULL);
- if (!pool)
- return -10;
-
- items = pj_pool_alloc(pool, sockpair_cnt*sizeof(test_item));
- thread = pj_pool_alloc(pool, thread_cnt*sizeof(pj_thread_t*));
-
- TRACE_((THIS_FILE, " creating ioqueue.."));
- rc = pj_ioqueue_create(pool, sockpair_cnt*2, &ioqueue);
- if (rc != PJ_SUCCESS) {
- app_perror("...error: unable to create ioqueue", rc);
- return -15;
- }
-
- /* Initialize each producer-consumer pair. */
- for (i=0; i<sockpair_cnt; ++i) {
- pj_ssize_t bytes;
-
- items[i].ioqueue = ioqueue;
- items[i].buffer_size = buffer_size;
- items[i].outgoing_buffer = pj_pool_alloc(pool, buffer_size);
- items[i].incoming_buffer = pj_pool_alloc(pool, buffer_size);
- items[i].bytes_recv = items[i].bytes_sent = 0;
-
- /* randomize outgoing buffer. */
- pj_create_random_string(items[i].outgoing_buffer, buffer_size);
-
- /* Create socket pair. */
- TRACE_((THIS_FILE, " calling socketpair.."));
- rc = app_socketpair(PJ_AF_INET, sock_type, 0,
- &items[i].server_fd, &items[i].client_fd);
- if (rc != PJ_SUCCESS) {
- app_perror("...error: unable to create socket pair", rc);
- return -20;
- }
-
- /* Register server socket to ioqueue. */
- TRACE_((THIS_FILE, " register(1).."));
- rc = pj_ioqueue_register_sock(pool, ioqueue,
- items[i].server_fd,
- &items[i], &ioqueue_callback,
- &items[i].server_key);
- if (rc != PJ_SUCCESS) {
- app_perror("...error: registering server socket to ioqueue", rc);
- return -60;
- }
-
- /* Register client socket to ioqueue. */
- TRACE_((THIS_FILE, " register(2).."));
- rc = pj_ioqueue_register_sock(pool, ioqueue,
- items[i].client_fd,
- &items[i], &ioqueue_callback,
- &items[i].client_key);
- if (rc != PJ_SUCCESS) {
- app_perror("...error: registering server socket to ioqueue", rc);
- return -70;
- }
-
- /* Start reading. */
- TRACE_((THIS_FILE, " pj_ioqueue_recv.."));
- bytes = items[i].buffer_size;
- rc = pj_ioqueue_recv(items[i].server_key, &items[i].recv_op,
- items[i].incoming_buffer, &bytes,
- 0);
- if (rc != PJ_EPENDING) {
- app_perror("...error: pj_ioqueue_recv", rc);
- return -73;
- }
-
- /* Start writing. */
- TRACE_((THIS_FILE, " pj_ioqueue_write.."));
- bytes = items[i].buffer_size;
- rc = pj_ioqueue_send(items[i].client_key, &items[i].recv_op,
- items[i].outgoing_buffer, &bytes, 0);
- if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
- app_perror("...error: pj_ioqueue_write", rc);
- return -76;
- }
-
- items[i].has_pending_send = (rc==PJ_EPENDING);
- }
-
- /* Create the threads. */
- for (i=0; i<thread_cnt; ++i) {
- rc = pj_thread_create( pool, NULL,
- &worker_thread,
- ioqueue,
- PJ_THREAD_DEFAULT_STACK_SIZE,
- PJ_THREAD_SUSPENDED, &thread[i] );
- if (rc != PJ_SUCCESS) {
- app_perror("...error: unable to create thread", rc);
- return -80;
- }
- }
-
- /* Mark start time. */
- rc = pj_get_timestamp(&start);
- if (rc != PJ_SUCCESS)
- return -90;
-
- /* Start the thread. */
- TRACE_((THIS_FILE, " resuming all threads.."));
- for (i=0; i<thread_cnt; ++i) {
- rc = pj_thread_resume(thread[i]);
- if (rc != 0)
- return -100;
- }
-
- /* Wait for MSEC_DURATION seconds.
- * This should be as simple as pj_thread_sleep(MSEC_DURATION) actually,
- * but unfortunately it doesn't work when system doesn't employ
- * timeslicing for threads.
- */
- TRACE_((THIS_FILE, " wait for few seconds.."));
- do {
- pj_thread_sleep(1);
-
- /* Mark end time. */
- rc = pj_get_timestamp(&stop);
-
- if (thread_quit_flag) {
- TRACE_((THIS_FILE, " transfer limit reached.."));
- break;
- }
-
- if (pj_elapsed_usec(&start,&stop)<MSEC_DURATION * 1000) {
- TRACE_((THIS_FILE, " time limit reached.."));
- break;
- }
-
- } while (1);
-
- /* Terminate all threads. */
- TRACE_((THIS_FILE, " terminating all threads.."));
- thread_quit_flag = 1;
-
- for (i=0; i<thread_cnt; ++i) {
- TRACE_((THIS_FILE, " join thread %d..", i));
- pj_thread_join(thread[i]);
- pj_thread_destroy(thread[i]);
- }
-
- /* Close all sockets. */
- TRACE_((THIS_FILE, " closing all sockets.."));
- for (i=0; i<sockpair_cnt; ++i) {
- pj_ioqueue_unregister(items[i].server_key);
- pj_ioqueue_unregister(items[i].client_key);
- pj_sock_close(items[i].server_fd);
- pj_sock_close(items[i].client_fd);
- }
-
- /* Destroy ioqueue. */
- TRACE_((THIS_FILE, " destroying ioqueue.."));
- pj_ioqueue_destroy(ioqueue);
-
- /* Calculate actual time in usec. */
- total_elapsed_usec = pj_elapsed_usec(&start, &stop);
-
- /* Calculate total bytes received. */
- total_received = 0;
- for (i=0; i<sockpair_cnt; ++i) {
- total_received = items[i].bytes_recv;
- }
-
- /* bandwidth = total_received*1000/total_elapsed_usec */
- bandwidth = total_received;
- pj_highprec_mul(bandwidth, 1000);
- pj_highprec_div(bandwidth, total_elapsed_usec);
-
- *p_bandwidth = (pj_uint32_t)bandwidth;
-
- PJ_LOG(3,(THIS_FILE, " %.4s %d %d %3d us %8d KB/s",
- type_name, thread_cnt, sockpair_cnt,
- -1 /*total_elapsed_usec/sockpair_cnt*/,
- *p_bandwidth));
-
- /* Done. */
- pj_pool_release(pool);
-
- TRACE_((THIS_FILE, " done.."));
- return 0;
-}
-
-/*
- * main test entry.
- */
-int ioqueue_perf_test(void)
-{
- enum { BUF_SIZE = 512 };
- int i, rc;
- struct {
- int type;
- const char *type_name;
- int thread_cnt;
- int sockpair_cnt;
- } test_param[] =
- {
- { PJ_SOCK_DGRAM, "udp", 1, 1},
- { PJ_SOCK_DGRAM, "udp", 1, 2},
- { PJ_SOCK_DGRAM, "udp", 1, 4},
- { PJ_SOCK_DGRAM, "udp", 1, 8},
- { PJ_SOCK_DGRAM, "udp", 2, 1},
- { PJ_SOCK_DGRAM, "udp", 2, 2},
- { PJ_SOCK_DGRAM, "udp", 2, 4},
- { PJ_SOCK_DGRAM, "udp", 2, 8},
- { PJ_SOCK_DGRAM, "udp", 4, 1},
- { PJ_SOCK_DGRAM, "udp", 4, 2},
- { PJ_SOCK_DGRAM, "udp", 4, 4},
- { PJ_SOCK_DGRAM, "udp", 4, 8},
- { PJ_SOCK_STREAM, "tcp", 1, 1},
- { PJ_SOCK_STREAM, "tcp", 1, 2},
- { PJ_SOCK_STREAM, "tcp", 1, 4},
- { PJ_SOCK_STREAM, "tcp", 1, 8},
- { PJ_SOCK_STREAM, "tcp", 2, 1},
- { PJ_SOCK_STREAM, "tcp", 2, 2},
- { PJ_SOCK_STREAM, "tcp", 2, 4},
- { PJ_SOCK_STREAM, "tcp", 2, 8},
- { PJ_SOCK_STREAM, "tcp", 4, 1},
- { PJ_SOCK_STREAM, "tcp", 4, 2},
- { PJ_SOCK_STREAM, "tcp", 4, 4},
- { PJ_SOCK_STREAM, "tcp", 4, 8},
- };
- pj_size_t best_bandwidth;
- int best_index = 0;
-
- PJ_LOG(3,(THIS_FILE, " Benchmarking %s ioqueue:", pj_ioqueue_name()));
- PJ_LOG(3,(THIS_FILE, " ==============================================="));
- PJ_LOG(3,(THIS_FILE, " Type Threads Skt.Pairs Avg.Time Bandwidth"));
- PJ_LOG(3,(THIS_FILE, " ==============================================="));
-
- best_bandwidth = 0;
- for (i=0; i<sizeof(test_param)/sizeof(test_param[0]); ++i) {
- pj_size_t bandwidth;
-
- rc = perform_test(test_param[i].type,
- test_param[i].type_name,
- test_param[i].thread_cnt,
- test_param[i].sockpair_cnt,
- BUF_SIZE,
- &bandwidth);
- if (rc != 0)
- return rc;
-
- if (bandwidth > best_bandwidth)
- best_bandwidth = bandwidth, best_index = i;
-
- /* Give it a rest before next test. */
- pj_thread_sleep(500);
- }
-
- PJ_LOG(3,(THIS_FILE,
- " Best: Type=%s Threads=%d, Skt.Pairs=%d, Bandwidth=%u KB/s",
- test_param[best_index].type_name,
- test_param[best_index].thread_cnt,
- test_param[best_index].sockpair_cnt,
- best_bandwidth));
- PJ_LOG(3,(THIS_FILE, " (Note: packet size=%d, total errors=%u)",
- BUF_SIZE, last_error_counter));
- return 0;
-}
-
-#else
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled.
- */
-int dummy_uiq_perf_test;
-#endif /* INCLUDE_IOQUEUE_PERF_TEST */
-
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "test.h"
+#include <pjlib.h>
+#include <pj/compat/high_precision.h>
+
+/**
+ * \page page_pjlib_ioqueue_perf_test Test: I/O Queue Performance
+ *
+ * Test the performance of the I/O queue, using typical producer
+ * consumer test. The test should examine the effect of using multiple
+ * threads on the performance.
+ *
+ * This file is <b>pjlib-test/ioq_perf.c</b>
+ *
+ * \include pjlib-test/ioq_perf.c
+ */
+
+#if INCLUDE_IOQUEUE_PERF_TEST
+
+#ifdef _MSC_VER
+# pragma warning ( disable: 4204) // non-constant aggregate initializer
+#endif
+
+#define THIS_FILE "ioq_perf"
+//#define TRACE_(expr) PJ_LOG(3,expr)
+#define TRACE_(expr)
+
+
+static pj_bool_t thread_quit_flag;
+static pj_status_t last_error;
+static unsigned last_error_counter;
+
+/* Descriptor for each producer/consumer pair. */
+typedef struct test_item
+{
+ pj_sock_t server_fd,
+ client_fd;
+ pj_ioqueue_t *ioqueue;
+ pj_ioqueue_key_t *server_key,
+ *client_key;
+ pj_ioqueue_op_key_t recv_op,
+ send_op;
+ int has_pending_send;
+ pj_size_t buffer_size;
+ char *outgoing_buffer;
+ char *incoming_buffer;
+ pj_size_t bytes_sent,
+ bytes_recv;
+} test_item;
+
+/* Callback when data has been read.
+ * Increment item->bytes_recv and ready to read the next data.
+ */
+static void on_read_complete(pj_ioqueue_key_t *key,
+ pj_ioqueue_op_key_t *op_key,
+ pj_ssize_t bytes_read)
+{
+ test_item *item = pj_ioqueue_get_user_data(key);
+ pj_status_t rc;
+ int data_is_available = 1;
+
+ //TRACE_((THIS_FILE, " read complete, bytes_read=%d", bytes_read));
+
+ do {
+ if (thread_quit_flag)
+ return;
+
+ if (bytes_read < 0) {
+ pj_status_t rc = -bytes_read;
+ char errmsg[128];
+
+ if (rc != last_error) {
+ //last_error = rc;
+ pj_strerror(rc, errmsg, sizeof(errmsg));
+ PJ_LOG(3,(THIS_FILE, "...error: read error, bytes_read=%d (%s)",
+ bytes_read, errmsg));
+ PJ_LOG(3,(THIS_FILE,
+ ".....additional info: total read=%u, total sent=%u",
+ item->bytes_recv, item->bytes_sent));
+ } else {
+ last_error_counter++;
+ }
+ bytes_read = 0;
+
+ } else if (bytes_read == 0) {
+ PJ_LOG(3,(THIS_FILE, "...socket has closed!"));
+ }
+
+ item->bytes_recv += bytes_read;
+
+ /* To assure that the test quits, even if main thread
+ * doesn't have time to run.
+ */
+ if (item->bytes_recv > item->buffer_size * 10000)
+ thread_quit_flag = 1;
+
+ bytes_read = item->buffer_size;
+ rc = pj_ioqueue_recv( key, op_key,
+ item->incoming_buffer, &bytes_read, 0 );
+
+ if (rc == PJ_SUCCESS) {
+ data_is_available = 1;
+ } else if (rc == PJ_EPENDING) {
+ data_is_available = 0;
+ } else {
+ data_is_available = 0;
+ if (rc != last_error) {
+ last_error = rc;
+ app_perror("...error: read error(1)", rc);
+ } else {
+ last_error_counter++;
+ }
+ }
+
+ if (!item->has_pending_send) {
+ pj_ssize_t sent = item->buffer_size;
+ rc = pj_ioqueue_send(item->client_key, &item->send_op,
+ item->outgoing_buffer, &sent, 0);
+ if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
+ app_perror("...error: write error", rc);
+ }
+
+ item->has_pending_send = (rc==PJ_EPENDING);
+ }
+
+ } while (data_is_available);
+}
+
+/* Callback when data has been written.
+ * Increment item->bytes_sent and write the next data.
+ */
+static void on_write_complete(pj_ioqueue_key_t *key,
+ pj_ioqueue_op_key_t *op_key,
+ pj_ssize_t bytes_sent)
+{
+ test_item *item = pj_ioqueue_get_user_data(key);
+
+ //TRACE_((THIS_FILE, " write complete: sent = %d", bytes_sent));
+
+ if (thread_quit_flag)
+ return;
+
+ item->has_pending_send = 0;
+ item->bytes_sent += bytes_sent;
+
+ if (bytes_sent <= 0) {
+ PJ_LOG(3,(THIS_FILE, "...error: sending stopped. bytes_sent=%d",
+ bytes_sent));
+ }
+ else {
+ pj_status_t rc;
+
+ bytes_sent = item->buffer_size;
+ rc = pj_ioqueue_send( item->client_key, op_key,
+ item->outgoing_buffer, &bytes_sent, 0);
+ if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
+ app_perror("...error: write error", rc);
+ }
+
+ item->has_pending_send = (rc==PJ_EPENDING);
+ }
+}
+
+/* The worker thread. */
+static int worker_thread(void *arg)
+{
+ pj_ioqueue_t *ioqueue = arg;
+ const pj_time_val timeout = {0, 100};
+ int rc;
+
+ while (!thread_quit_flag) {
+ rc = pj_ioqueue_poll(ioqueue, &timeout);
+ //TRACE_((THIS_FILE, " thread: poll returned rc=%d", rc));
+ if (rc < 0) {
+ app_perror("...error in pj_ioqueue_poll()", pj_get_netos_error());
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/* Calculate the bandwidth for the specific test configuration.
+ * The test is simple:
+ * - create sockpair_cnt number of producer-consumer socket pair.
+ * - create thread_cnt number of worker threads.
+ * - each producer will send buffer_size bytes data as fast and
+ * as soon as it can.
+ * - each consumer will read buffer_size bytes of data as fast
+ * as it could.
+ * - measure the total bytes received by all consumers during a
+ * period of time.
+ */
+static int perform_test(int sock_type, const char *type_name,
+ unsigned thread_cnt, unsigned sockpair_cnt,
+ pj_size_t buffer_size,
+ pj_size_t *p_bandwidth)
+{
+ enum { MSEC_DURATION = 5000 };
+ pj_pool_t *pool;
+ test_item *items;
+ pj_thread_t **thread;
+ pj_ioqueue_t *ioqueue;
+ pj_status_t rc;
+ pj_ioqueue_callback ioqueue_callback;
+ pj_uint32_t total_elapsed_usec, total_received;
+ pj_highprec_t bandwidth;
+ pj_timestamp start, stop;
+ unsigned i;
+
+ TRACE_((THIS_FILE, " starting test.."));
+
+ ioqueue_callback.on_read_complete = &on_read_complete;
+ ioqueue_callback.on_write_complete = &on_write_complete;
+
+ thread_quit_flag = 0;
+
+ pool = pj_pool_create(mem, NULL, 4096, 4096, NULL);
+ if (!pool)
+ return -10;
+
+ items = pj_pool_alloc(pool, sockpair_cnt*sizeof(test_item));
+ thread = pj_pool_alloc(pool, thread_cnt*sizeof(pj_thread_t*));
+
+ TRACE_((THIS_FILE, " creating ioqueue.."));
+ rc = pj_ioqueue_create(pool, sockpair_cnt*2, &ioqueue);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error: unable to create ioqueue", rc);
+ return -15;
+ }
+
+ /* Initialize each producer-consumer pair. */
+ for (i=0; i<sockpair_cnt; ++i) {
+ pj_ssize_t bytes;
+
+ items[i].ioqueue = ioqueue;
+ items[i].buffer_size = buffer_size;
+ items[i].outgoing_buffer = pj_pool_alloc(pool, buffer_size);
+ items[i].incoming_buffer = pj_pool_alloc(pool, buffer_size);
+ items[i].bytes_recv = items[i].bytes_sent = 0;
+
+ /* randomize outgoing buffer. */
+ pj_create_random_string(items[i].outgoing_buffer, buffer_size);
+
+ /* Create socket pair. */
+ TRACE_((THIS_FILE, " calling socketpair.."));
+ rc = app_socketpair(PJ_AF_INET, sock_type, 0,
+ &items[i].server_fd, &items[i].client_fd);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error: unable to create socket pair", rc);
+ return -20;
+ }
+
+ /* Register server socket to ioqueue. */
+ TRACE_((THIS_FILE, " register(1).."));
+ rc = pj_ioqueue_register_sock(pool, ioqueue,
+ items[i].server_fd,
+ &items[i], &ioqueue_callback,
+ &items[i].server_key);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error: registering server socket to ioqueue", rc);
+ return -60;
+ }
+
+ /* Register client socket to ioqueue. */
+ TRACE_((THIS_FILE, " register(2).."));
+ rc = pj_ioqueue_register_sock(pool, ioqueue,
+ items[i].client_fd,
+ &items[i], &ioqueue_callback,
+ &items[i].client_key);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error: registering server socket to ioqueue", rc);
+ return -70;
+ }
+
+ /* Start reading. */
+ TRACE_((THIS_FILE, " pj_ioqueue_recv.."));
+ bytes = items[i].buffer_size;
+ rc = pj_ioqueue_recv(items[i].server_key, &items[i].recv_op,
+ items[i].incoming_buffer, &bytes,
+ 0);
+ if (rc != PJ_EPENDING) {
+ app_perror("...error: pj_ioqueue_recv", rc);
+ return -73;
+ }
+
+ /* Start writing. */
+ TRACE_((THIS_FILE, " pj_ioqueue_write.."));
+ bytes = items[i].buffer_size;
+ rc = pj_ioqueue_send(items[i].client_key, &items[i].recv_op,
+ items[i].outgoing_buffer, &bytes, 0);
+ if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
+ app_perror("...error: pj_ioqueue_write", rc);
+ return -76;
+ }
+
+ items[i].has_pending_send = (rc==PJ_EPENDING);
+ }
+
+ /* Create the threads. */
+ for (i=0; i<thread_cnt; ++i) {
+ rc = pj_thread_create( pool, NULL,
+ &worker_thread,
+ ioqueue,
+ PJ_THREAD_DEFAULT_STACK_SIZE,
+ PJ_THREAD_SUSPENDED, &thread[i] );
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error: unable to create thread", rc);
+ return -80;
+ }
+ }
+
+ /* Mark start time. */
+ rc = pj_get_timestamp(&start);
+ if (rc != PJ_SUCCESS)
+ return -90;
+
+ /* Start the thread. */
+ TRACE_((THIS_FILE, " resuming all threads.."));
+ for (i=0; i<thread_cnt; ++i) {
+ rc = pj_thread_resume(thread[i]);
+ if (rc != 0)
+ return -100;
+ }
+
+ /* Wait for MSEC_DURATION seconds.
+ * This should be as simple as pj_thread_sleep(MSEC_DURATION) actually,
+ * but unfortunately it doesn't work when system doesn't employ
+ * timeslicing for threads.
+ */
+ TRACE_((THIS_FILE, " wait for few seconds.."));
+ do {
+ pj_thread_sleep(1);
+
+ /* Mark end time. */
+ rc = pj_get_timestamp(&stop);
+
+ if (thread_quit_flag) {
+ TRACE_((THIS_FILE, " transfer limit reached.."));
+ break;
+ }
+
+ if (pj_elapsed_usec(&start,&stop)<MSEC_DURATION * 1000) {
+ TRACE_((THIS_FILE, " time limit reached.."));
+ break;
+ }
+
+ } while (1);
+
+ /* Terminate all threads. */
+ TRACE_((THIS_FILE, " terminating all threads.."));
+ thread_quit_flag = 1;
+
+ for (i=0; i<thread_cnt; ++i) {
+ TRACE_((THIS_FILE, " join thread %d..", i));
+ pj_thread_join(thread[i]);
+ pj_thread_destroy(thread[i]);
+ }
+
+ /* Close all sockets. */
+ TRACE_((THIS_FILE, " closing all sockets.."));
+ for (i=0; i<sockpair_cnt; ++i) {
+ pj_ioqueue_unregister(items[i].server_key);
+ pj_ioqueue_unregister(items[i].client_key);
+ pj_sock_close(items[i].server_fd);
+ pj_sock_close(items[i].client_fd);
+ }
+
+ /* Destroy ioqueue. */
+ TRACE_((THIS_FILE, " destroying ioqueue.."));
+ pj_ioqueue_destroy(ioqueue);
+
+ /* Calculate actual time in usec. */
+ total_elapsed_usec = pj_elapsed_usec(&start, &stop);
+
+ /* Calculate total bytes received. */
+ total_received = 0;
+ for (i=0; i<sockpair_cnt; ++i) {
+ total_received = items[i].bytes_recv;
+ }
+
+ /* bandwidth = total_received*1000/total_elapsed_usec */
+ bandwidth = total_received;
+ pj_highprec_mul(bandwidth, 1000);
+ pj_highprec_div(bandwidth, total_elapsed_usec);
+
+ *p_bandwidth = (pj_uint32_t)bandwidth;
+
+ PJ_LOG(3,(THIS_FILE, " %.4s %d %d %3d us %8d KB/s",
+ type_name, thread_cnt, sockpair_cnt,
+ -1 /*total_elapsed_usec/sockpair_cnt*/,
+ *p_bandwidth));
+
+ /* Done. */
+ pj_pool_release(pool);
+
+ TRACE_((THIS_FILE, " done.."));
+ return 0;
+}
+
+/*
+ * main test entry.
+ */
+int ioqueue_perf_test(void)
+{
+ enum { BUF_SIZE = 512 };
+ int i, rc;
+ struct {
+ int type;
+ const char *type_name;
+ int thread_cnt;
+ int sockpair_cnt;
+ } test_param[] =
+ {
+ { PJ_SOCK_DGRAM, "udp", 1, 1},
+ { PJ_SOCK_DGRAM, "udp", 1, 2},
+ { PJ_SOCK_DGRAM, "udp", 1, 4},
+ { PJ_SOCK_DGRAM, "udp", 1, 8},
+ { PJ_SOCK_DGRAM, "udp", 2, 1},
+ { PJ_SOCK_DGRAM, "udp", 2, 2},
+ { PJ_SOCK_DGRAM, "udp", 2, 4},
+ { PJ_SOCK_DGRAM, "udp", 2, 8},
+ { PJ_SOCK_DGRAM, "udp", 4, 1},
+ { PJ_SOCK_DGRAM, "udp", 4, 2},
+ { PJ_SOCK_DGRAM, "udp", 4, 4},
+ { PJ_SOCK_DGRAM, "udp", 4, 8},
+ { PJ_SOCK_STREAM, "tcp", 1, 1},
+ { PJ_SOCK_STREAM, "tcp", 1, 2},
+ { PJ_SOCK_STREAM, "tcp", 1, 4},
+ { PJ_SOCK_STREAM, "tcp", 1, 8},
+ { PJ_SOCK_STREAM, "tcp", 2, 1},
+ { PJ_SOCK_STREAM, "tcp", 2, 2},
+ { PJ_SOCK_STREAM, "tcp", 2, 4},
+ { PJ_SOCK_STREAM, "tcp", 2, 8},
+ { PJ_SOCK_STREAM, "tcp", 4, 1},
+ { PJ_SOCK_STREAM, "tcp", 4, 2},
+ { PJ_SOCK_STREAM, "tcp", 4, 4},
+ { PJ_SOCK_STREAM, "tcp", 4, 8},
+ };
+ pj_size_t best_bandwidth;
+ int best_index = 0;
+
+ PJ_LOG(3,(THIS_FILE, " Benchmarking %s ioqueue:", pj_ioqueue_name()));
+ PJ_LOG(3,(THIS_FILE, " ==============================================="));
+ PJ_LOG(3,(THIS_FILE, " Type Threads Skt.Pairs Avg.Time Bandwidth"));
+ PJ_LOG(3,(THIS_FILE, " ==============================================="));
+
+ best_bandwidth = 0;
+ for (i=0; i<sizeof(test_param)/sizeof(test_param[0]); ++i) {
+ pj_size_t bandwidth;
+
+ rc = perform_test(test_param[i].type,
+ test_param[i].type_name,
+ test_param[i].thread_cnt,
+ test_param[i].sockpair_cnt,
+ BUF_SIZE,
+ &bandwidth);
+ if (rc != 0)
+ return rc;
+
+ if (bandwidth > best_bandwidth)
+ best_bandwidth = bandwidth, best_index = i;
+
+ /* Give it a rest before next test. */
+ pj_thread_sleep(500);
+ }
+
+ PJ_LOG(3,(THIS_FILE,
+ " Best: Type=%s Threads=%d, Skt.Pairs=%d, Bandwidth=%u KB/s",
+ test_param[best_index].type_name,
+ test_param[best_index].thread_cnt,
+ test_param[best_index].sockpair_cnt,
+ best_bandwidth));
+ PJ_LOG(3,(THIS_FILE, " (Note: packet size=%d, total errors=%u)",
+ BUF_SIZE, last_error_counter));
+ return 0;
+}
+
+#else
+/* To prevent warning about "translation unit is empty"
+ * when this test is disabled.
+ */
+int dummy_uiq_perf_test;
+#endif /* INCLUDE_IOQUEUE_PERF_TEST */
+
+
diff --git a/pjlib/src/pjlib-test/ioq_tcp.c b/pjlib/src/pjlib-test/ioq_tcp.c
index 22827942..30d594b0 100644
--- a/pjlib/src/pjlib-test/ioq_tcp.c
+++ b/pjlib/src/pjlib-test/ioq_tcp.c
@@ -1,524 +1,545 @@
-/* $Id$
- */
-#include "test.h"
-
-/**
- * \page page_pjlib_ioqueue_tcp_test Test: I/O Queue (TCP)
- *
- * This file provides implementation to test the
- * functionality of the I/O queue when TCP socket is used.
- *
- *
- * This file is <b>pjlib-test/ioq_tcp.c</b>
- *
- * \include pjlib-test/ioq_tcp.c
- */
-
-
-#if INCLUDE_TCP_IOQUEUE_TEST
-
-#include <pjlib.h>
-
-#if PJ_HAS_TCP
-
-#define THIS_FILE "test_tcp"
-#define PORT 50000
-#define NON_EXISTANT_PORT 50123
-#define LOOP 100
-#define BUF_MIN_SIZE 32
-#define BUF_MAX_SIZE 2048
-#define SOCK_INACTIVE_MIN (4-2)
-#define SOCK_INACTIVE_MAX (PJ_IOQUEUE_MAX_HANDLES - 2)
-#define POOL_SIZE (2*BUF_MAX_SIZE + SOCK_INACTIVE_MAX*128 + 2048)
-
-static pj_ssize_t callback_read_size,
- callback_write_size,
- callback_accept_status,
- callback_connect_status;
-static pj_ioqueue_key_t *callback_read_key,
- *callback_write_key,
- *callback_accept_key,
- *callback_connect_key;
-static pj_ioqueue_op_key_t *callback_read_op,
- *callback_write_op,
- *callback_accept_op;
-
-static void on_ioqueue_read(pj_ioqueue_key_t *key,
- pj_ioqueue_op_key_t *op_key,
- pj_ssize_t bytes_read)
-{
- callback_read_key = key;
- callback_read_op = op_key;
- callback_read_size = bytes_read;
-}
-
-static void on_ioqueue_write(pj_ioqueue_key_t *key,
- pj_ioqueue_op_key_t *op_key,
- pj_ssize_t bytes_written)
-{
- callback_write_key = key;
- callback_write_op = op_key;
- callback_write_size = bytes_written;
-}
-
-static void on_ioqueue_accept(pj_ioqueue_key_t *key,
- pj_ioqueue_op_key_t *op_key,
- pj_sock_t sock,
- int status)
-{
- PJ_UNUSED_ARG(sock);
-
- callback_accept_key = key;
- callback_accept_op = op_key;
- callback_accept_status = status;
-}
-
-static void on_ioqueue_connect(pj_ioqueue_key_t *key, int status)
-{
- callback_connect_key = key;
- callback_connect_status = status;
-}
-
-static pj_ioqueue_callback test_cb =
-{
- &on_ioqueue_read,
- &on_ioqueue_write,
- &on_ioqueue_accept,
- &on_ioqueue_connect,
-};
-
-static int send_recv_test(pj_ioqueue_t *ioque,
- pj_ioqueue_key_t *skey,
- pj_ioqueue_key_t *ckey,
- void *send_buf,
- void *recv_buf,
- pj_ssize_t bufsize,
- pj_timestamp *t_elapsed)
-{
- pj_status_t status;
- pj_ssize_t bytes;
- pj_time_val timeout;
- pj_timestamp t1, t2;
- int pending_op = 0;
- pj_ioqueue_op_key_t read_op, write_op;
-
- // Start reading on the server side.
- bytes = bufsize;
- status = pj_ioqueue_recv(skey, &read_op, recv_buf, &bytes, 0);
- if (status != PJ_SUCCESS && status != PJ_EPENDING) {
- app_perror("...pj_ioqueue_recv error", status);
- return -100;
- }
-
- if (status == PJ_EPENDING)
- ++pending_op;
- else {
- /* Does not expect to return error or immediate data. */
- return -115;
- }
-
- // Randomize send buffer.
- pj_create_random_string((char*)send_buf, bufsize);
-
- // Starts send on the client side.
- bytes = bufsize;
- status = pj_ioqueue_send(ckey, &write_op, send_buf, &bytes, 0);
- if (status != PJ_SUCCESS && bytes != PJ_EPENDING) {
- return -120;
- }
- if (status == PJ_EPENDING) {
- ++pending_op;
- }
-
- // Begin time.
- pj_get_timestamp(&t1);
-
- // Reset indicators
- callback_read_size = callback_write_size = 0;
- callback_read_key = callback_write_key = NULL;
- callback_read_op = callback_write_op = NULL;
-
- // Poll the queue until we've got completion event in the server side.
- status = 0;
- while (pending_op > 0) {
- timeout.sec = 1; timeout.msec = 0;
- status = pj_ioqueue_poll(ioque, &timeout);
- if (status > 0) {
- if (callback_read_size) {
- if (callback_read_size != bufsize)
- return -160;
- if (callback_read_key != skey)
- return -161;
- if (callback_read_op != &read_op)
- return -162;
- }
- if (callback_write_size) {
- if (callback_write_key != ckey)
- return -163;
- if (callback_write_op != &write_op)
- return -164;
- }
- pending_op -= status;
- }
- if (status == 0) {
- PJ_LOG(3,("", "...error: timed out"));
- }
- if (status < 0) {
- return -170;
- }
- }
-
- // Pending op is zero.
- // Subsequent poll should yield zero too.
- timeout.sec = timeout.msec = 0;
- status = pj_ioqueue_poll(ioque, &timeout);
- if (status != 0)
- return -173;
-
- // End time.
- pj_get_timestamp(&t2);
- t_elapsed->u32.lo += (t2.u32.lo - t1.u32.lo);
-
- // Compare recv buffer with send buffer.
- if (pj_memcmp(send_buf, recv_buf, bufsize) != 0) {
- return -180;
- }
-
- // Success
- return 0;
-}
-
-
-/*
- * Compliance test for success scenario.
- */
-static int compliance_test_0(void)
-{
- pj_sock_t ssock=-1, csock0=-1, csock1=-1;
- pj_sockaddr_in addr, client_addr, rmt_addr;
- int client_addr_len;
- pj_pool_t *pool = NULL;
- char *send_buf, *recv_buf;
- pj_ioqueue_t *ioque = NULL;
- pj_ioqueue_key_t *skey, *ckey0, *ckey1;
- pj_ioqueue_op_key_t accept_op;
- int bufsize = BUF_MIN_SIZE;
- pj_ssize_t status = -1;
- int pending_op = 0;
- pj_timestamp t_elapsed;
- pj_str_t s;
- pj_status_t rc;
-
- // Create pool.
- pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);
-
- // Allocate buffers for send and receive.
- send_buf = (char*)pj_pool_alloc(pool, bufsize);
- recv_buf = (char*)pj_pool_alloc(pool, bufsize);
-
- // Create server socket and client socket for connecting
- rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, 0, &ssock);
- if (rc != PJ_SUCCESS) {
- app_perror("...error creating socket", rc);
- status=-1; goto on_error;
- }
-
- rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, 0, &csock1);
- if (rc != PJ_SUCCESS) {
- app_perror("...error creating socket", rc);
- status=-1; goto on_error;
- }
-
- // Bind server socket.
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = PJ_AF_INET;
- addr.sin_port = pj_htons(PORT);
- if (pj_sock_bind(ssock, &addr, sizeof(addr))) {
- app_perror("...bind error", rc);
- status=-10; goto on_error;
- }
-
- // Create I/O Queue.
- rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
- if (rc != PJ_SUCCESS) {
- app_perror("...ERROR in pj_ioqueue_create()", rc);
- status=-20; goto on_error;
- }
-
- // Register server socket and client socket.
- rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL, &test_cb, &skey);
- if (rc == PJ_SUCCESS)
- rc = pj_ioqueue_register_sock(pool, ioque, csock1, NULL, &test_cb,
- &ckey1);
- else
- ckey1 = NULL;
- if (rc != PJ_SUCCESS) {
- app_perror("...ERROR in pj_ioqueue_register_sock()", rc);
- status=-23; goto on_error;
- }
-
- // Server socket listen().
- if (pj_sock_listen(ssock, 5)) {
- app_perror("...ERROR in pj_sock_listen()", rc);
- status=-25; goto on_error;
- }
-
- // Server socket accept()
- client_addr_len = sizeof(pj_sockaddr_in);
- status = pj_ioqueue_accept(skey, &accept_op, &csock0,
- &client_addr, &rmt_addr, &client_addr_len);
- if (status != PJ_EPENDING) {
- app_perror("...ERROR in pj_ioqueue_accept()", rc);
- status=-30; goto on_error;
- }
- if (status==PJ_EPENDING) {
- ++pending_op;
- }
-
- // Initialize remote address.
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = PJ_AF_INET;
- addr.sin_port = pj_htons(PORT);
- addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));
-
- // Client socket connect()
- status = pj_ioqueue_connect(ckey1, &addr, sizeof(addr));
- if (status!=PJ_SUCCESS && status != PJ_EPENDING) {
- app_perror("...ERROR in pj_ioqueue_connect()", rc);
- status=-40; goto on_error;
- }
- if (status==PJ_EPENDING) {
- ++pending_op;
- }
-
- // Poll until connected
- callback_read_size = callback_write_size = 0;
- callback_accept_status = callback_connect_status = -2;
-
- callback_read_key = callback_write_key =
- callback_accept_key = callback_connect_key = NULL;
- callback_accept_op = callback_read_op = callback_write_op = NULL;
-
- while (pending_op) {
- pj_time_val timeout = {1, 0};
-
- status=pj_ioqueue_poll(ioque, &timeout);
- if (status > 0) {
- if (callback_accept_status != -2) {
- if (callback_accept_status != 0) {
- status=-41; goto on_error;
- }
- if (callback_accept_key != skey) {
- status=-42; goto on_error;
- }
- if (callback_accept_op != &accept_op) {
- status=-43; goto on_error;
- }
- callback_accept_status = -2;
- }
-
- if (callback_connect_status != -2) {
- if (callback_connect_status != 0) {
- status=-50; goto on_error;
- }
- if (callback_connect_key != ckey1) {
- status=-51; goto on_error;
- }
- callback_connect_status = -2;
- }
-
- pending_op -= status;
-
- if (pending_op == 0) {
- status = 0;
- }
- }
- }
-
- // There's no pending operation.
- // When we poll the ioqueue, there must not be events.
- if (pending_op == 0) {
- pj_time_val timeout = {1, 0};
- status = pj_ioqueue_poll(ioque, &timeout);
- if (status != 0) {
- status=-60; goto on_error;
- }
- }
-
- // Check accepted socket.
- if (csock0 == PJ_INVALID_SOCKET) {
- status = -69;
- app_perror("...accept() error", pj_get_os_error());
- goto on_error;
- }
-
- // Register newly accepted socket.
- rc = pj_ioqueue_register_sock(pool, ioque, csock0, NULL,
- &test_cb, &ckey0);
- if (rc != PJ_SUCCESS) {
- app_perror("...ERROR in pj_ioqueue_register_sock", rc);
- status = -70;
- goto on_error;
- }
-
- // Test send and receive.
- t_elapsed.u32.lo = 0;
- status = send_recv_test(ioque, ckey0, ckey1, send_buf,
- recv_buf, bufsize, &t_elapsed);
- if (status != 0) {
- goto on_error;
- }
-
- // Success
- status = 0;
-
-on_error:
- if (ssock != PJ_INVALID_SOCKET)
- pj_sock_close(ssock);
- if (csock1 != PJ_INVALID_SOCKET)
- pj_sock_close(csock1);
- if (csock0 != PJ_INVALID_SOCKET)
- pj_sock_close(csock0);
- if (ioque != NULL)
- pj_ioqueue_destroy(ioque);
- pj_pool_release(pool);
- return status;
-
-}
-
-/*
- * Compliance test for failed scenario.
- * In this case, the client connects to a non-existant service.
- */
-static int compliance_test_1(void)
-{
- pj_sock_t csock1=-1;
- pj_sockaddr_in addr;
- pj_pool_t *pool = NULL;
- pj_ioqueue_t *ioque = NULL;
- pj_ioqueue_key_t *ckey1;
- pj_ssize_t status = -1;
- int pending_op = 0;
- pj_str_t s;
- pj_status_t rc;
-
- // Create pool.
- pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);
-
- // Create I/O Queue.
- rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
- if (!ioque) {
- status=-20; goto on_error;
- }
-
- // Create client socket
- rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, 0, &csock1);
- if (rc != PJ_SUCCESS) {
- app_perror("...ERROR in pj_sock_socket()", rc);
- status=-1; goto on_error;
- }
-
- // Register client socket.
- rc = pj_ioqueue_register_sock(pool, ioque, csock1, NULL,
- &test_cb, &ckey1);
- if (rc != PJ_SUCCESS) {
- app_perror("...ERROR in pj_ioqueue_register_sock()", rc);
- status=-23; goto on_error;
- }
-
- // Initialize remote address.
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = PJ_AF_INET;
- addr.sin_port = pj_htons(NON_EXISTANT_PORT);
- addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));
-
- // Client socket connect()
- status = pj_ioqueue_connect(ckey1, &addr, sizeof(addr));
- if (status==PJ_SUCCESS) {
- // unexpectedly success!
- status = -30;
- goto on_error;
- }
- if (status != PJ_EPENDING) {
- // success
- } else {
- ++pending_op;
- }
-
- callback_connect_status = -2;
- callback_connect_key = NULL;
-
- // Poll until we've got result
- while (pending_op) {
- pj_time_val timeout = {1, 0};
-
- status=pj_ioqueue_poll(ioque, &timeout);
- if (status > 0) {
- if (callback_connect_key==ckey1) {
- if (callback_connect_status == 0) {
- // unexpectedly connected!
- status = -50;
- goto on_error;
- }
- }
-
- pending_op -= status;
- if (pending_op == 0) {
- status = 0;
- }
- }
- }
-
- // There's no pending operation.
- // When we poll the ioqueue, there must not be events.
- if (pending_op == 0) {
- pj_time_val timeout = {1, 0};
- status = pj_ioqueue_poll(ioque, &timeout);
- if (status != 0) {
- status=-60; goto on_error;
- }
- }
-
- // Success
- status = 0;
-
-on_error:
- if (csock1 != PJ_INVALID_SOCKET)
- pj_sock_close(csock1);
- if (ioque != NULL)
- pj_ioqueue_destroy(ioque);
- pj_pool_release(pool);
- return status;
-}
-
-int tcp_ioqueue_test()
-{
- int status;
-
- PJ_LOG(3, (THIS_FILE, "..%s compliance test 0 (success scenario)",
- pj_ioqueue_name()));
- if ((status=compliance_test_0()) != 0) {
- PJ_LOG(1, (THIS_FILE, "....FAILED (status=%d)\n", status));
- return status;
- }
- PJ_LOG(3, (THIS_FILE, "..%s compliance test 1 (failed scenario)",
- pj_ioqueue_name()));
- if ((status=compliance_test_1()) != 0) {
- PJ_LOG(1, (THIS_FILE, "....FAILED (status=%d)\n", status));
- return status;
- }
-
- return 0;
-}
-
-#endif /* PJ_HAS_TCP */
-
-
-#else
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled.
- */
-int dummy_uiq_tcp;
-#endif /* INCLUDE_TCP_IOQUEUE_TEST */
-
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "test.h"
+
+/**
+ * \page page_pjlib_ioqueue_tcp_test Test: I/O Queue (TCP)
+ *
+ * This file provides implementation to test the
+ * functionality of the I/O queue when TCP socket is used.
+ *
+ *
+ * This file is <b>pjlib-test/ioq_tcp.c</b>
+ *
+ * \include pjlib-test/ioq_tcp.c
+ */
+
+
+#if INCLUDE_TCP_IOQUEUE_TEST
+
+#include <pjlib.h>
+
+#if PJ_HAS_TCP
+
+#define THIS_FILE "test_tcp"
+#define PORT 50000
+#define NON_EXISTANT_PORT 50123
+#define LOOP 100
+#define BUF_MIN_SIZE 32
+#define BUF_MAX_SIZE 2048
+#define SOCK_INACTIVE_MIN (4-2)
+#define SOCK_INACTIVE_MAX (PJ_IOQUEUE_MAX_HANDLES - 2)
+#define POOL_SIZE (2*BUF_MAX_SIZE + SOCK_INACTIVE_MAX*128 + 2048)
+
+static pj_ssize_t callback_read_size,
+ callback_write_size,
+ callback_accept_status,
+ callback_connect_status;
+static pj_ioqueue_key_t *callback_read_key,
+ *callback_write_key,
+ *callback_accept_key,
+ *callback_connect_key;
+static pj_ioqueue_op_key_t *callback_read_op,
+ *callback_write_op,
+ *callback_accept_op;
+
+static void on_ioqueue_read(pj_ioqueue_key_t *key,
+ pj_ioqueue_op_key_t *op_key,
+ pj_ssize_t bytes_read)
+{
+ callback_read_key = key;
+ callback_read_op = op_key;
+ callback_read_size = bytes_read;
+}
+
+static void on_ioqueue_write(pj_ioqueue_key_t *key,
+ pj_ioqueue_op_key_t *op_key,
+ pj_ssize_t bytes_written)
+{
+ callback_write_key = key;
+ callback_write_op = op_key;
+ callback_write_size = bytes_written;
+}
+
+static void on_ioqueue_accept(pj_ioqueue_key_t *key,
+ pj_ioqueue_op_key_t *op_key,
+ pj_sock_t sock,
+ int status)
+{
+ PJ_UNUSED_ARG(sock);
+
+ callback_accept_key = key;
+ callback_accept_op = op_key;
+ callback_accept_status = status;
+}
+
+static void on_ioqueue_connect(pj_ioqueue_key_t *key, int status)
+{
+ callback_connect_key = key;
+ callback_connect_status = status;
+}
+
+static pj_ioqueue_callback test_cb =
+{
+ &on_ioqueue_read,
+ &on_ioqueue_write,
+ &on_ioqueue_accept,
+ &on_ioqueue_connect,
+};
+
+static int send_recv_test(pj_ioqueue_t *ioque,
+ pj_ioqueue_key_t *skey,
+ pj_ioqueue_key_t *ckey,
+ void *send_buf,
+ void *recv_buf,
+ pj_ssize_t bufsize,
+ pj_timestamp *t_elapsed)
+{
+ pj_status_t status;
+ pj_ssize_t bytes;
+ pj_time_val timeout;
+ pj_timestamp t1, t2;
+ int pending_op = 0;
+ pj_ioqueue_op_key_t read_op, write_op;
+
+ // Start reading on the server side.
+ bytes = bufsize;
+ status = pj_ioqueue_recv(skey, &read_op, recv_buf, &bytes, 0);
+ if (status != PJ_SUCCESS && status != PJ_EPENDING) {
+ app_perror("...pj_ioqueue_recv error", status);
+ return -100;
+ }
+
+ if (status == PJ_EPENDING)
+ ++pending_op;
+ else {
+ /* Does not expect to return error or immediate data. */
+ return -115;
+ }
+
+ // Randomize send buffer.
+ pj_create_random_string((char*)send_buf, bufsize);
+
+ // Starts send on the client side.
+ bytes = bufsize;
+ status = pj_ioqueue_send(ckey, &write_op, send_buf, &bytes, 0);
+ if (status != PJ_SUCCESS && bytes != PJ_EPENDING) {
+ return -120;
+ }
+ if (status == PJ_EPENDING) {
+ ++pending_op;
+ }
+
+ // Begin time.
+ pj_get_timestamp(&t1);
+
+ // Reset indicators
+ callback_read_size = callback_write_size = 0;
+ callback_read_key = callback_write_key = NULL;
+ callback_read_op = callback_write_op = NULL;
+
+ // Poll the queue until we've got completion event in the server side.
+ status = 0;
+ while (pending_op > 0) {
+ timeout.sec = 1; timeout.msec = 0;
+ status = pj_ioqueue_poll(ioque, &timeout);
+ if (status > 0) {
+ if (callback_read_size) {
+ if (callback_read_size != bufsize)
+ return -160;
+ if (callback_read_key != skey)
+ return -161;
+ if (callback_read_op != &read_op)
+ return -162;
+ }
+ if (callback_write_size) {
+ if (callback_write_key != ckey)
+ return -163;
+ if (callback_write_op != &write_op)
+ return -164;
+ }
+ pending_op -= status;
+ }
+ if (status == 0) {
+ PJ_LOG(3,("", "...error: timed out"));
+ }
+ if (status < 0) {
+ return -170;
+ }
+ }
+
+ // Pending op is zero.
+ // Subsequent poll should yield zero too.
+ timeout.sec = timeout.msec = 0;
+ status = pj_ioqueue_poll(ioque, &timeout);
+ if (status != 0)
+ return -173;
+
+ // End time.
+ pj_get_timestamp(&t2);
+ t_elapsed->u32.lo += (t2.u32.lo - t1.u32.lo);
+
+ // Compare recv buffer with send buffer.
+ if (pj_memcmp(send_buf, recv_buf, bufsize) != 0) {
+ return -180;
+ }
+
+ // Success
+ return 0;
+}
+
+
+/*
+ * Compliance test for success scenario.
+ */
+static int compliance_test_0(void)
+{
+ pj_sock_t ssock=-1, csock0=-1, csock1=-1;
+ pj_sockaddr_in addr, client_addr, rmt_addr;
+ int client_addr_len;
+ pj_pool_t *pool = NULL;
+ char *send_buf, *recv_buf;
+ pj_ioqueue_t *ioque = NULL;
+ pj_ioqueue_key_t *skey, *ckey0, *ckey1;
+ pj_ioqueue_op_key_t accept_op;
+ int bufsize = BUF_MIN_SIZE;
+ pj_ssize_t status = -1;
+ int pending_op = 0;
+ pj_timestamp t_elapsed;
+ pj_str_t s;
+ pj_status_t rc;
+
+ // Create pool.
+ pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);
+
+ // Allocate buffers for send and receive.
+ send_buf = (char*)pj_pool_alloc(pool, bufsize);
+ recv_buf = (char*)pj_pool_alloc(pool, bufsize);
+
+ // Create server socket and client socket for connecting
+ rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, 0, &ssock);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error creating socket", rc);
+ status=-1; goto on_error;
+ }
+
+ rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, 0, &csock1);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error creating socket", rc);
+ status=-1; goto on_error;
+ }
+
+ // Bind server socket.
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = PJ_AF_INET;
+ addr.sin_port = pj_htons(PORT);
+ if (pj_sock_bind(ssock, &addr, sizeof(addr))) {
+ app_perror("...bind error", rc);
+ status=-10; goto on_error;
+ }
+
+ // Create I/O Queue.
+ rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...ERROR in pj_ioqueue_create()", rc);
+ status=-20; goto on_error;
+ }
+
+ // Register server socket and client socket.
+ rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL, &test_cb, &skey);
+ if (rc == PJ_SUCCESS)
+ rc = pj_ioqueue_register_sock(pool, ioque, csock1, NULL, &test_cb,
+ &ckey1);
+ else
+ ckey1 = NULL;
+ if (rc != PJ_SUCCESS) {
+ app_perror("...ERROR in pj_ioqueue_register_sock()", rc);
+ status=-23; goto on_error;
+ }
+
+ // Server socket listen().
+ if (pj_sock_listen(ssock, 5)) {
+ app_perror("...ERROR in pj_sock_listen()", rc);
+ status=-25; goto on_error;
+ }
+
+ // Server socket accept()
+ client_addr_len = sizeof(pj_sockaddr_in);
+ status = pj_ioqueue_accept(skey, &accept_op, &csock0,
+ &client_addr, &rmt_addr, &client_addr_len);
+ if (status != PJ_EPENDING) {
+ app_perror("...ERROR in pj_ioqueue_accept()", rc);
+ status=-30; goto on_error;
+ }
+ if (status==PJ_EPENDING) {
+ ++pending_op;
+ }
+
+ // Initialize remote address.
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = PJ_AF_INET;
+ addr.sin_port = pj_htons(PORT);
+ addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));
+
+ // Client socket connect()
+ status = pj_ioqueue_connect(ckey1, &addr, sizeof(addr));
+ if (status!=PJ_SUCCESS && status != PJ_EPENDING) {
+ app_perror("...ERROR in pj_ioqueue_connect()", rc);
+ status=-40; goto on_error;
+ }
+ if (status==PJ_EPENDING) {
+ ++pending_op;
+ }
+
+ // Poll until connected
+ callback_read_size = callback_write_size = 0;
+ callback_accept_status = callback_connect_status = -2;
+
+ callback_read_key = callback_write_key =
+ callback_accept_key = callback_connect_key = NULL;
+ callback_accept_op = callback_read_op = callback_write_op = NULL;
+
+ while (pending_op) {
+ pj_time_val timeout = {1, 0};
+
+ status=pj_ioqueue_poll(ioque, &timeout);
+ if (status > 0) {
+ if (callback_accept_status != -2) {
+ if (callback_accept_status != 0) {
+ status=-41; goto on_error;
+ }
+ if (callback_accept_key != skey) {
+ status=-42; goto on_error;
+ }
+ if (callback_accept_op != &accept_op) {
+ status=-43; goto on_error;
+ }
+ callback_accept_status = -2;
+ }
+
+ if (callback_connect_status != -2) {
+ if (callback_connect_status != 0) {
+ status=-50; goto on_error;
+ }
+ if (callback_connect_key != ckey1) {
+ status=-51; goto on_error;
+ }
+ callback_connect_status = -2;
+ }
+
+ pending_op -= status;
+
+ if (pending_op == 0) {
+ status = 0;
+ }
+ }
+ }
+
+ // There's no pending operation.
+ // When we poll the ioqueue, there must not be events.
+ if (pending_op == 0) {
+ pj_time_val timeout = {1, 0};
+ status = pj_ioqueue_poll(ioque, &timeout);
+ if (status != 0) {
+ status=-60; goto on_error;
+ }
+ }
+
+ // Check accepted socket.
+ if (csock0 == PJ_INVALID_SOCKET) {
+ status = -69;
+ app_perror("...accept() error", pj_get_os_error());
+ goto on_error;
+ }
+
+ // Register newly accepted socket.
+ rc = pj_ioqueue_register_sock(pool, ioque, csock0, NULL,
+ &test_cb, &ckey0);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...ERROR in pj_ioqueue_register_sock", rc);
+ status = -70;
+ goto on_error;
+ }
+
+ // Test send and receive.
+ t_elapsed.u32.lo = 0;
+ status = send_recv_test(ioque, ckey0, ckey1, send_buf,
+ recv_buf, bufsize, &t_elapsed);
+ if (status != 0) {
+ goto on_error;
+ }
+
+ // Success
+ status = 0;
+
+on_error:
+ if (ssock != PJ_INVALID_SOCKET)
+ pj_sock_close(ssock);
+ if (csock1 != PJ_INVALID_SOCKET)
+ pj_sock_close(csock1);
+ if (csock0 != PJ_INVALID_SOCKET)
+ pj_sock_close(csock0);
+ if (ioque != NULL)
+ pj_ioqueue_destroy(ioque);
+ pj_pool_release(pool);
+ return status;
+
+}
+
+/*
+ * Compliance test for failed scenario.
+ * In this case, the client connects to a non-existant service.
+ */
+static int compliance_test_1(void)
+{
+ pj_sock_t csock1=-1;
+ pj_sockaddr_in addr;
+ pj_pool_t *pool = NULL;
+ pj_ioqueue_t *ioque = NULL;
+ pj_ioqueue_key_t *ckey1;
+ pj_ssize_t status = -1;
+ int pending_op = 0;
+ pj_str_t s;
+ pj_status_t rc;
+
+ // Create pool.
+ pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);
+
+ // Create I/O Queue.
+ rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
+ if (!ioque) {
+ status=-20; goto on_error;
+ }
+
+ // Create client socket
+ rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, 0, &csock1);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...ERROR in pj_sock_socket()", rc);
+ status=-1; goto on_error;
+ }
+
+ // Register client socket.
+ rc = pj_ioqueue_register_sock(pool, ioque, csock1, NULL,
+ &test_cb, &ckey1);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...ERROR in pj_ioqueue_register_sock()", rc);
+ status=-23; goto on_error;
+ }
+
+ // Initialize remote address.
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = PJ_AF_INET;
+ addr.sin_port = pj_htons(NON_EXISTANT_PORT);
+ addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));
+
+ // Client socket connect()
+ status = pj_ioqueue_connect(ckey1, &addr, sizeof(addr));
+ if (status==PJ_SUCCESS) {
+ // unexpectedly success!
+ status = -30;
+ goto on_error;
+ }
+ if (status != PJ_EPENDING) {
+ // success
+ } else {
+ ++pending_op;
+ }
+
+ callback_connect_status = -2;
+ callback_connect_key = NULL;
+
+ // Poll until we've got result
+ while (pending_op) {
+ pj_time_val timeout = {1, 0};
+
+ status=pj_ioqueue_poll(ioque, &timeout);
+ if (status > 0) {
+ if (callback_connect_key==ckey1) {
+ if (callback_connect_status == 0) {
+ // unexpectedly connected!
+ status = -50;
+ goto on_error;
+ }
+ }
+
+ pending_op -= status;
+ if (pending_op == 0) {
+ status = 0;
+ }
+ }
+ }
+
+ // There's no pending operation.
+ // When we poll the ioqueue, there must not be events.
+ if (pending_op == 0) {
+ pj_time_val timeout = {1, 0};
+ status = pj_ioqueue_poll(ioque, &timeout);
+ if (status != 0) {
+ status=-60; goto on_error;
+ }
+ }
+
+ // Success
+ status = 0;
+
+on_error:
+ if (csock1 != PJ_INVALID_SOCKET)
+ pj_sock_close(csock1);
+ if (ioque != NULL)
+ pj_ioqueue_destroy(ioque);
+ pj_pool_release(pool);
+ return status;
+}
+
+int tcp_ioqueue_test()
+{
+ int status;
+
+ PJ_LOG(3, (THIS_FILE, "..%s compliance test 0 (success scenario)",
+ pj_ioqueue_name()));
+ if ((status=compliance_test_0()) != 0) {
+ PJ_LOG(1, (THIS_FILE, "....FAILED (status=%d)\n", status));
+ return status;
+ }
+ PJ_LOG(3, (THIS_FILE, "..%s compliance test 1 (failed scenario)",
+ pj_ioqueue_name()));
+ if ((status=compliance_test_1()) != 0) {
+ PJ_LOG(1, (THIS_FILE, "....FAILED (status=%d)\n", status));
+ return status;
+ }
+
+ return 0;
+}
+
+#endif /* PJ_HAS_TCP */
+
+
+#else
+/* To prevent warning about "translation unit is empty"
+ * when this test is disabled.
+ */
+int dummy_uiq_tcp;
+#endif /* INCLUDE_TCP_IOQUEUE_TEST */
+
+
diff --git a/pjlib/src/pjlib-test/ioq_udp.c b/pjlib/src/pjlib-test/ioq_udp.c
index c6a5c5f0..8e8b6d1f 100644
--- a/pjlib/src/pjlib-test/ioq_udp.c
+++ b/pjlib/src/pjlib-test/ioq_udp.c
@@ -1,647 +1,668 @@
-/* $Id$
- */
-#include "test.h"
-
-
-/**
- * \page page_pjlib_ioqueue_udp_test Test: I/O Queue (UDP)
- *
- * This file provides implementation to test the
- * functionality of the I/O queue when UDP socket is used.
- *
- *
- * This file is <b>pjlib-test/ioq_udp.c</b>
- *
- * \include pjlib-test/ioq_udp.c
- */
-
-
-#if INCLUDE_UDP_IOQUEUE_TEST
-
-#include <pjlib.h>
-
-#include <pj/compat/socket.h>
-
-#define THIS_FILE "test_udp"
-#define PORT 51233
-#define LOOP 100
-#define BUF_MIN_SIZE 32
-#define BUF_MAX_SIZE 2048
-#define SOCK_INACTIVE_MIN (1)
-#define SOCK_INACTIVE_MAX (PJ_IOQUEUE_MAX_HANDLES - 2)
-#define POOL_SIZE (2*BUF_MAX_SIZE + SOCK_INACTIVE_MAX*128 + 2048)
-
-#undef TRACE_
-#define TRACE_(msg) PJ_LOG(3,(THIS_FILE,"....." msg))
-
-static pj_ssize_t callback_read_size,
- callback_write_size,
- callback_accept_status,
- callback_connect_status;
-static pj_ioqueue_key_t *callback_read_key,
- *callback_write_key,
- *callback_accept_key,
- *callback_connect_key;
-static pj_ioqueue_op_key_t *callback_read_op,
- *callback_write_op,
- *callback_accept_op;
-
-static void on_ioqueue_read(pj_ioqueue_key_t *key,
- pj_ioqueue_op_key_t *op_key,
- pj_ssize_t bytes_read)
-{
- callback_read_key = key;
- callback_read_op = op_key;
- callback_read_size = bytes_read;
-}
-
-static void on_ioqueue_write(pj_ioqueue_key_t *key,
- pj_ioqueue_op_key_t *op_key,
- pj_ssize_t bytes_written)
-{
- callback_write_key = key;
- callback_write_op = op_key;
- callback_write_size = bytes_written;
-}
-
-static void on_ioqueue_accept(pj_ioqueue_key_t *key,
- pj_ioqueue_op_key_t *op_key,
- pj_sock_t sock, int status)
-{
- PJ_UNUSED_ARG(sock);
- callback_accept_key = key;
- callback_accept_op = op_key;
- callback_accept_status = status;
-}
-
-static void on_ioqueue_connect(pj_ioqueue_key_t *key, int status)
-{
- callback_connect_key = key;
- callback_connect_status = status;
-}
-
-static pj_ioqueue_callback test_cb =
-{
- &on_ioqueue_read,
- &on_ioqueue_write,
- &on_ioqueue_accept,
- &on_ioqueue_connect,
-};
-
-#ifdef PJ_WIN32
-# define S_ADDR S_un.S_addr
-#else
-# define S_ADDR s_addr
-#endif
-
-/*
- * compliance_test()
- * To test that the basic IOQueue functionality works. It will just exchange
- * data between two sockets.
- */
-static int compliance_test(void)
-{
- pj_sock_t ssock=-1, csock=-1;
- pj_sockaddr_in addr;
- int addrlen;
- pj_pool_t *pool = NULL;
- char *send_buf, *recv_buf;
- pj_ioqueue_t *ioque = NULL;
- pj_ioqueue_key_t *skey, *ckey;
- pj_ioqueue_op_key_t read_op, write_op;
- int bufsize = BUF_MIN_SIZE;
- pj_ssize_t bytes, status = -1;
- pj_str_t temp;
- pj_bool_t send_pending, recv_pending;
- pj_status_t rc;
-
- pj_set_os_error(PJ_SUCCESS);
-
- // Create pool.
- pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);
-
- // Allocate buffers for send and receive.
- send_buf = (char*)pj_pool_alloc(pool, bufsize);
- recv_buf = (char*)pj_pool_alloc(pool, bufsize);
-
- // Allocate sockets for sending and receiving.
- TRACE_("creating sockets...");
- rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &ssock);
- if (rc==PJ_SUCCESS)
- rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &csock);
- else
- csock = PJ_INVALID_SOCKET;
- if (rc != PJ_SUCCESS) {
- app_perror("...ERROR in pj_sock_socket()", rc);
- status=-1; goto on_error;
- }
-
- // Bind server socket.
- TRACE_("bind socket...");
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = PJ_AF_INET;
- addr.sin_port = pj_htons(PORT);
- if (pj_sock_bind(ssock, &addr, sizeof(addr))) {
- status=-10; goto on_error;
- }
-
- // Create I/O Queue.
- TRACE_("create ioqueue...");
- rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
- if (rc != PJ_SUCCESS) {
- status=-20; goto on_error;
- }
-
- // Register server and client socket.
- // We put this after inactivity socket, hopefully this can represent the
- // worst waiting time.
- TRACE_("registering first sockets...");
- rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL,
- &test_cb, &skey);
- if (rc != PJ_SUCCESS) {
- app_perror("...error(10): ioqueue_register error", rc);
- status=-25; goto on_error;
- }
- TRACE_("registering second sockets...");
- rc = pj_ioqueue_register_sock( pool, ioque, csock, NULL,
- &test_cb, &ckey);
- if (rc != PJ_SUCCESS) {
- app_perror("...error(11): ioqueue_register error", rc);
- status=-26; goto on_error;
- }
-
- // Set destination address to send the packet.
- TRACE_("set destination address...");
- temp = pj_str("127.0.0.1");
- if ((rc=pj_sockaddr_in_init(&addr, &temp, PORT)) != 0) {
- app_perror("...error: unable to resolve 127.0.0.1", rc);
- status=-26; goto on_error;
- }
-
- // Randomize send_buf.
- pj_create_random_string(send_buf, bufsize);
-
- // Register reading from ioqueue.
- TRACE_("start recvfrom...");
- addrlen = sizeof(addr);
- bytes = bufsize;
- rc = pj_ioqueue_recvfrom(skey, &read_op, recv_buf, &bytes, 0,
- &addr, &addrlen);
- if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
- app_perror("...error: pj_ioqueue_recvfrom", rc);
- status=-28; goto on_error;
- } else if (rc == PJ_EPENDING) {
- recv_pending = 1;
- PJ_LOG(3, (THIS_FILE,
- "......ok: recvfrom returned pending"));
- } else {
- PJ_LOG(3, (THIS_FILE,
- "......error: recvfrom returned immediate ok!"));
- status=-29; goto on_error;
- }
-
- // Write must return the number of bytes.
- TRACE_("start sendto...");
- bytes = bufsize;
- rc = pj_ioqueue_sendto(ckey, &write_op, send_buf, &bytes, 0, &addr,
- sizeof(addr));
- if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
- app_perror("...error: pj_ioqueue_sendto", rc);
- status=-30; goto on_error;
- } else if (rc == PJ_EPENDING) {
- send_pending = 1;
- PJ_LOG(3, (THIS_FILE,
- "......ok: sendto returned pending"));
- } else {
- send_pending = 0;
- PJ_LOG(3, (THIS_FILE,
- "......ok: sendto returned immediate success"));
- }
-
- // reset callback variables.
- callback_read_size = callback_write_size = 0;
- callback_accept_status = callback_connect_status = -2;
- callback_read_key = callback_write_key =
- callback_accept_key = callback_connect_key = NULL;
- callback_read_op = callback_write_op = NULL;
-
- // Poll if pending.
- while (send_pending || recv_pending) {
- int rc;
- pj_time_val timeout = { 5, 0 };
-
- TRACE_("poll...");
- rc = pj_ioqueue_poll(ioque, &timeout);
-
- if (rc == 0) {
- PJ_LOG(1,(THIS_FILE, "...ERROR: timed out..."));
- status=-45; goto on_error;
- } else if (rc < 0) {
- app_perror("...ERROR in ioqueue_poll()", rc);
- status=-50; goto on_error;
- }
-
- if (callback_read_key != NULL) {
- if (callback_read_size != bufsize) {
- status=-61; goto on_error;
- }
- if (callback_read_key != skey) {
- status=-65; goto on_error;
- }
- if (callback_read_op != &read_op) {
- status=-66; goto on_error;
- }
-
- if (memcmp(send_buf, recv_buf, bufsize) != 0) {
- status=-70; goto on_error;
- }
-
-
- recv_pending = 0;
- }
-
- if (callback_write_key != NULL) {
- if (callback_write_size != bufsize) {
- status=-73; goto on_error;
- }
- if (callback_write_key != ckey) {
- status=-75; goto on_error;
- }
- if (callback_write_op != &write_op) {
- status=-76; goto on_error;
- }
-
- send_pending = 0;
- }
- }
-
- // Success
- status = 0;
-
-on_error:
- if (status != 0) {
- char errbuf[128];
- PJ_LOG(1, (THIS_FILE,
- "...compliance test error: status=%d, os_err=%d (%s)",
- status, pj_get_netos_error(),
- pj_strerror(pj_get_netos_error(), errbuf, sizeof(errbuf))));
- }
- if (ssock)
- pj_sock_close(ssock);
- if (csock)
- pj_sock_close(csock);
- if (ioque != NULL)
- pj_ioqueue_destroy(ioque);
- pj_pool_release(pool);
- return status;
-
-}
-
-/*
- * Testing with many handles.
- * This will just test registering PJ_IOQUEUE_MAX_HANDLES count
- * of sockets to the ioqueue.
- */
-static int many_handles_test(void)
-{
- enum { MAX = PJ_IOQUEUE_MAX_HANDLES };
- pj_pool_t *pool;
- pj_ioqueue_t *ioqueue;
- pj_sock_t *sock;
- pj_ioqueue_key_t **key;
- pj_status_t rc;
- int count, i;
-
- PJ_LOG(3,(THIS_FILE,"...testing with so many handles"));
-
- pool = pj_pool_create(mem, NULL, 4000, 4000, NULL);
- if (!pool)
- return PJ_ENOMEM;
-
- key = pj_pool_alloc(pool, MAX*sizeof(pj_ioqueue_key_t*));
- sock = pj_pool_alloc(pool, MAX*sizeof(pj_sock_t));
-
- /* Create IOQueue */
- rc = pj_ioqueue_create(pool, MAX, &ioqueue);
- if (rc != PJ_SUCCESS || ioqueue == NULL) {
- app_perror("...error in pj_ioqueue_create", rc);
- return -10;
- }
-
- /* Register as many sockets. */
- for (count=0; count<MAX; ++count) {
- sock[count] = PJ_INVALID_SOCKET;
- rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock[count]);
- if (rc != PJ_SUCCESS || sock[count] == PJ_INVALID_SOCKET) {
- PJ_LOG(3,(THIS_FILE, "....unable to create %d-th socket, rc=%d",
- count, rc));
- break;
- }
- key[count] = NULL;
- rc = pj_ioqueue_register_sock(pool, ioqueue, sock[count],
- NULL, &test_cb, &key[count]);
- if (rc != PJ_SUCCESS || key[count] == NULL) {
- PJ_LOG(3,(THIS_FILE, "....unable to register %d-th socket, rc=%d",
- count, rc));
- return -30;
- }
- }
-
- /* Test complete. */
-
- /* Now deregister and close all handles. */
-
- for (i=0; i<count; ++i) {
- rc = pj_ioqueue_unregister(key[i]);
- if (rc != PJ_SUCCESS) {
- app_perror("...error in pj_ioqueue_unregister", rc);
- }
- rc = pj_sock_close(sock[i]);
- if (rc != PJ_SUCCESS) {
- app_perror("...error in pj_sock_close", rc);
- }
- }
-
- rc = pj_ioqueue_destroy(ioqueue);
- if (rc != PJ_SUCCESS) {
- app_perror("...error in pj_ioqueue_destroy", rc);
- }
-
- pj_pool_release(pool);
-
- PJ_LOG(3,(THIS_FILE,"....many_handles_test() ok"));
-
- return 0;
-}
-
-/*
- * Multi-operation test.
- */
-
-/*
- * Benchmarking IOQueue
- */
-static int bench_test(int bufsize, int inactive_sock_count)
-{
- pj_sock_t ssock=-1, csock=-1;
- pj_sockaddr_in addr;
- pj_pool_t *pool = NULL;
- pj_sock_t *inactive_sock=NULL;
- pj_ioqueue_op_key_t *inactive_read_op;
- char *send_buf, *recv_buf;
- pj_ioqueue_t *ioque = NULL;
- pj_ioqueue_key_t *skey, *ckey, *key;
- pj_timestamp t1, t2, t_elapsed;
- int rc=0, i;
- pj_str_t temp;
- char errbuf[128];
-
- // Create pool.
- pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);
-
- // Allocate buffers for send and receive.
- send_buf = (char*)pj_pool_alloc(pool, bufsize);
- recv_buf = (char*)pj_pool_alloc(pool, bufsize);
-
- // Allocate sockets for sending and receiving.
- rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &ssock);
- if (rc == PJ_SUCCESS) {
- rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &csock);
- } else
- csock = PJ_INVALID_SOCKET;
- if (rc != PJ_SUCCESS) {
- app_perror("...error: pj_sock_socket()", rc);
- goto on_error;
- }
-
- // Bind server socket.
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = PJ_AF_INET;
- addr.sin_port = pj_htons(PORT);
- if (pj_sock_bind(ssock, &addr, sizeof(addr)))
- goto on_error;
-
- pj_assert(inactive_sock_count+2 <= PJ_IOQUEUE_MAX_HANDLES);
-
- // Create I/O Queue.
- rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
- if (rc != PJ_SUCCESS) {
- app_perror("...error: pj_ioqueue_create()", rc);
- goto on_error;
- }
-
- // Allocate inactive sockets, and bind them to some arbitrary address.
- // Then register them to the I/O queue, and start a read operation.
- inactive_sock = (pj_sock_t*)pj_pool_alloc(pool,
- inactive_sock_count*sizeof(pj_sock_t));
- inactive_read_op = (pj_ioqueue_op_key_t*)pj_pool_alloc(pool,
- inactive_sock_count*sizeof(pj_ioqueue_op_key_t));
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = PJ_AF_INET;
- for (i=0; i<inactive_sock_count; ++i) {
- pj_ssize_t bytes;
-
- rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &inactive_sock[i]);
- if (rc != PJ_SUCCESS || inactive_sock[i] < 0) {
- app_perror("...error: pj_sock_socket()", rc);
- goto on_error;
- }
- if ((rc=pj_sock_bind(inactive_sock[i], &addr, sizeof(addr))) != 0) {
- pj_sock_close(inactive_sock[i]);
- inactive_sock[i] = PJ_INVALID_SOCKET;
- app_perror("...error: pj_sock_bind()", rc);
- goto on_error;
- }
- rc = pj_ioqueue_register_sock(pool, ioque, inactive_sock[i],
- NULL, &test_cb, &key);
- if (rc != PJ_SUCCESS) {
- pj_sock_close(inactive_sock[i]);
- inactive_sock[i] = PJ_INVALID_SOCKET;
- app_perror("...error(1): pj_ioqueue_register_sock()", rc);
- PJ_LOG(3,(THIS_FILE, "....i=%d", i));
- goto on_error;
- }
- bytes = bufsize;
- rc = pj_ioqueue_recv(key, &inactive_read_op[i], recv_buf, &bytes, 0);
- if ( rc < 0 && rc != PJ_EPENDING) {
- pj_sock_close(inactive_sock[i]);
- inactive_sock[i] = PJ_INVALID_SOCKET;
- app_perror("...error: pj_ioqueue_read()", rc);
- goto on_error;
- }
- }
-
- // Register server and client socket.
- // We put this after inactivity socket, hopefully this can represent the
- // worst waiting time.
- rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL,
- &test_cb, &skey);
- if (rc != PJ_SUCCESS) {
- app_perror("...error(2): pj_ioqueue_register_sock()", rc);
- goto on_error;
- }
-
- rc = pj_ioqueue_register_sock(pool, ioque, csock, NULL,
- &test_cb, &ckey);
- if (rc != PJ_SUCCESS) {
- app_perror("...error(3): pj_ioqueue_register_sock()", rc);
- goto on_error;
- }
-
- // Set destination address to send the packet.
- pj_sockaddr_in_init(&addr, pj_cstr(&temp, "127.0.0.1"), PORT);
-
- // Test loop.
- t_elapsed.u64 = 0;
- for (i=0; i<LOOP; ++i) {
- pj_ssize_t bytes;
- pj_ioqueue_op_key_t read_op, write_op;
-
- // Randomize send buffer.
- pj_create_random_string(send_buf, bufsize);
-
- // Start reading on the server side.
- bytes = bufsize;
- rc = pj_ioqueue_recv(skey, &read_op, recv_buf, &bytes, 0);
- if (rc < 0 && rc != PJ_EPENDING) {
- app_perror("...error: pj_ioqueue_read()", rc);
- break;
- }
-
- // Starts send on the client side.
- bytes = bufsize;
- rc = pj_ioqueue_sendto(ckey, &write_op, send_buf, &bytes, 0,
- &addr, sizeof(addr));
- if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
- app_perror("...error: pj_ioqueue_write()", bytes);
- rc = -1;
- break;
- }
-
- // Begin time.
- pj_get_timestamp(&t1);
-
- // Poll the queue until we've got completion event in the server side.
- callback_read_key = NULL;
- callback_read_size = 0;
- do {
- rc = pj_ioqueue_poll(ioque, NULL);
- } while (rc >= 0 && callback_read_key != skey);
-
- // End time.
- pj_get_timestamp(&t2);
- t_elapsed.u64 += (t2.u64 - t1.u64);
-
- if (rc < 0)
- break;
-
- // Compare recv buffer with send buffer.
- if (callback_read_size != bufsize ||
- memcmp(send_buf, recv_buf, bufsize))
- {
- rc = -1;
- break;
- }
-
- // Poll until all events are exhausted, before we start the next loop.
- do {
- pj_time_val timeout = { 0, 10 };
- rc = pj_ioqueue_poll(ioque, &timeout);
- } while (rc>0);
-
- rc = 0;
- }
-
- // Print results
- if (rc == 0) {
- pj_timestamp tzero;
- pj_uint32_t usec_delay;
-
- tzero.u32.hi = tzero.u32.lo = 0;
- usec_delay = pj_elapsed_usec( &tzero, &t_elapsed);
-
- PJ_LOG(3, (THIS_FILE, "...%10d %15d % 9d",
- bufsize, inactive_sock_count, usec_delay));
-
- } else {
- PJ_LOG(2, (THIS_FILE, "...ERROR (buf:%d, fds:%d)",
- bufsize, inactive_sock_count+2));
- }
-
- // Cleaning up.
- for (i=0; i<inactive_sock_count; ++i)
- pj_sock_close(inactive_sock[i]);
- pj_sock_close(ssock);
- pj_sock_close(csock);
-
- pj_ioqueue_destroy(ioque);
- pj_pool_release( pool);
- return 0;
-
-on_error:
- PJ_LOG(1,(THIS_FILE, "...ERROR: %s",
- pj_strerror(pj_get_netos_error(), errbuf, sizeof(errbuf))));
- if (ssock)
- pj_sock_close(ssock);
- if (csock)
- pj_sock_close(csock);
- for (i=0; i<inactive_sock_count && inactive_sock &&
- inactive_sock[i]!=PJ_INVALID_SOCKET; ++i)
- {
- pj_sock_close(inactive_sock[i]);
- }
- if (ioque != NULL)
- pj_ioqueue_destroy(ioque);
- pj_pool_release( pool);
- return -1;
-}
-
-int udp_ioqueue_test()
-{
- int status;
- int bufsize, sock_count;
-
- PJ_LOG(3, (THIS_FILE, "...compliance test (%s)", pj_ioqueue_name()));
- if ((status=compliance_test()) != 0) {
- return status;
- }
- PJ_LOG(3, (THIS_FILE, "....compliance test ok"));
-
- if ((status=many_handles_test()) != 0) {
- return status;
- }
-
- PJ_LOG(4, (THIS_FILE, "...benchmarking different buffer size:"));
- PJ_LOG(4, (THIS_FILE, "... note: buf=bytes sent, fds=# of fds, "
- "elapsed=in timer ticks"));
-
- PJ_LOG(3, (THIS_FILE, "...Benchmarking poll times for %s:", pj_ioqueue_name()));
- PJ_LOG(3, (THIS_FILE, "...====================================="));
- PJ_LOG(3, (THIS_FILE, "...Buf.size #inactive-socks Time/poll"));
- PJ_LOG(3, (THIS_FILE, "... (bytes) (nanosec)"));
- PJ_LOG(3, (THIS_FILE, "...====================================="));
-
- for (bufsize=BUF_MIN_SIZE; bufsize <= BUF_MAX_SIZE; bufsize *= 2) {
- if (bench_test(bufsize, SOCK_INACTIVE_MIN))
- return -1;
- }
- bufsize = 512;
- for (sock_count=SOCK_INACTIVE_MIN+2;
- sock_count<=SOCK_INACTIVE_MAX+2;
- sock_count *= 2)
- {
- //PJ_LOG(3,(THIS_FILE, "...testing with %d fds", sock_count));
- if (bench_test(bufsize, sock_count-2))
- return -1;
- }
- return 0;
-}
-
-#else
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled.
- */
-int dummy_uiq_udp;
-#endif /* INCLUDE_UDP_IOQUEUE_TEST */
-
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "test.h"
+
+
+/**
+ * \page page_pjlib_ioqueue_udp_test Test: I/O Queue (UDP)
+ *
+ * This file provides implementation to test the
+ * functionality of the I/O queue when UDP socket is used.
+ *
+ *
+ * This file is <b>pjlib-test/ioq_udp.c</b>
+ *
+ * \include pjlib-test/ioq_udp.c
+ */
+
+
+#if INCLUDE_UDP_IOQUEUE_TEST
+
+#include <pjlib.h>
+
+#include <pj/compat/socket.h>
+
+#define THIS_FILE "test_udp"
+#define PORT 51233
+#define LOOP 100
+#define BUF_MIN_SIZE 32
+#define BUF_MAX_SIZE 2048
+#define SOCK_INACTIVE_MIN (1)
+#define SOCK_INACTIVE_MAX (PJ_IOQUEUE_MAX_HANDLES - 2)
+#define POOL_SIZE (2*BUF_MAX_SIZE + SOCK_INACTIVE_MAX*128 + 2048)
+
+#undef TRACE_
+#define TRACE_(msg) PJ_LOG(3,(THIS_FILE,"....." msg))
+
+static pj_ssize_t callback_read_size,
+ callback_write_size,
+ callback_accept_status,
+ callback_connect_status;
+static pj_ioqueue_key_t *callback_read_key,
+ *callback_write_key,
+ *callback_accept_key,
+ *callback_connect_key;
+static pj_ioqueue_op_key_t *callback_read_op,
+ *callback_write_op,
+ *callback_accept_op;
+
+static void on_ioqueue_read(pj_ioqueue_key_t *key,
+ pj_ioqueue_op_key_t *op_key,
+ pj_ssize_t bytes_read)
+{
+ callback_read_key = key;
+ callback_read_op = op_key;
+ callback_read_size = bytes_read;
+}
+
+static void on_ioqueue_write(pj_ioqueue_key_t *key,
+ pj_ioqueue_op_key_t *op_key,
+ pj_ssize_t bytes_written)
+{
+ callback_write_key = key;
+ callback_write_op = op_key;
+ callback_write_size = bytes_written;
+}
+
+static void on_ioqueue_accept(pj_ioqueue_key_t *key,
+ pj_ioqueue_op_key_t *op_key,
+ pj_sock_t sock, int status)
+{
+ PJ_UNUSED_ARG(sock);
+ callback_accept_key = key;
+ callback_accept_op = op_key;
+ callback_accept_status = status;
+}
+
+static void on_ioqueue_connect(pj_ioqueue_key_t *key, int status)
+{
+ callback_connect_key = key;
+ callback_connect_status = status;
+}
+
+static pj_ioqueue_callback test_cb =
+{
+ &on_ioqueue_read,
+ &on_ioqueue_write,
+ &on_ioqueue_accept,
+ &on_ioqueue_connect,
+};
+
+#ifdef PJ_WIN32
+# define S_ADDR S_un.S_addr
+#else
+# define S_ADDR s_addr
+#endif
+
+/*
+ * compliance_test()
+ * To test that the basic IOQueue functionality works. It will just exchange
+ * data between two sockets.
+ */
+static int compliance_test(void)
+{
+ pj_sock_t ssock=-1, csock=-1;
+ pj_sockaddr_in addr;
+ int addrlen;
+ pj_pool_t *pool = NULL;
+ char *send_buf, *recv_buf;
+ pj_ioqueue_t *ioque = NULL;
+ pj_ioqueue_key_t *skey, *ckey;
+ pj_ioqueue_op_key_t read_op, write_op;
+ int bufsize = BUF_MIN_SIZE;
+ pj_ssize_t bytes, status = -1;
+ pj_str_t temp;
+ pj_bool_t send_pending, recv_pending;
+ pj_status_t rc;
+
+ pj_set_os_error(PJ_SUCCESS);
+
+ // Create pool.
+ pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);
+
+ // Allocate buffers for send and receive.
+ send_buf = (char*)pj_pool_alloc(pool, bufsize);
+ recv_buf = (char*)pj_pool_alloc(pool, bufsize);
+
+ // Allocate sockets for sending and receiving.
+ TRACE_("creating sockets...");
+ rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &ssock);
+ if (rc==PJ_SUCCESS)
+ rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &csock);
+ else
+ csock = PJ_INVALID_SOCKET;
+ if (rc != PJ_SUCCESS) {
+ app_perror("...ERROR in pj_sock_socket()", rc);
+ status=-1; goto on_error;
+ }
+
+ // Bind server socket.
+ TRACE_("bind socket...");
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = PJ_AF_INET;
+ addr.sin_port = pj_htons(PORT);
+ if (pj_sock_bind(ssock, &addr, sizeof(addr))) {
+ status=-10; goto on_error;
+ }
+
+ // Create I/O Queue.
+ TRACE_("create ioqueue...");
+ rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
+ if (rc != PJ_SUCCESS) {
+ status=-20; goto on_error;
+ }
+
+ // Register server and client socket.
+ // We put this after inactivity socket, hopefully this can represent the
+ // worst waiting time.
+ TRACE_("registering first sockets...");
+ rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL,
+ &test_cb, &skey);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error(10): ioqueue_register error", rc);
+ status=-25; goto on_error;
+ }
+ TRACE_("registering second sockets...");
+ rc = pj_ioqueue_register_sock( pool, ioque, csock, NULL,
+ &test_cb, &ckey);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error(11): ioqueue_register error", rc);
+ status=-26; goto on_error;
+ }
+
+ // Set destination address to send the packet.
+ TRACE_("set destination address...");
+ temp = pj_str("127.0.0.1");
+ if ((rc=pj_sockaddr_in_init(&addr, &temp, PORT)) != 0) {
+ app_perror("...error: unable to resolve 127.0.0.1", rc);
+ status=-26; goto on_error;
+ }
+
+ // Randomize send_buf.
+ pj_create_random_string(send_buf, bufsize);
+
+ // Register reading from ioqueue.
+ TRACE_("start recvfrom...");
+ addrlen = sizeof(addr);
+ bytes = bufsize;
+ rc = pj_ioqueue_recvfrom(skey, &read_op, recv_buf, &bytes, 0,
+ &addr, &addrlen);
+ if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
+ app_perror("...error: pj_ioqueue_recvfrom", rc);
+ status=-28; goto on_error;
+ } else if (rc == PJ_EPENDING) {
+ recv_pending = 1;
+ PJ_LOG(3, (THIS_FILE,
+ "......ok: recvfrom returned pending"));
+ } else {
+ PJ_LOG(3, (THIS_FILE,
+ "......error: recvfrom returned immediate ok!"));
+ status=-29; goto on_error;
+ }
+
+ // Write must return the number of bytes.
+ TRACE_("start sendto...");
+ bytes = bufsize;
+ rc = pj_ioqueue_sendto(ckey, &write_op, send_buf, &bytes, 0, &addr,
+ sizeof(addr));
+ if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
+ app_perror("...error: pj_ioqueue_sendto", rc);
+ status=-30; goto on_error;
+ } else if (rc == PJ_EPENDING) {
+ send_pending = 1;
+ PJ_LOG(3, (THIS_FILE,
+ "......ok: sendto returned pending"));
+ } else {
+ send_pending = 0;
+ PJ_LOG(3, (THIS_FILE,
+ "......ok: sendto returned immediate success"));
+ }
+
+ // reset callback variables.
+ callback_read_size = callback_write_size = 0;
+ callback_accept_status = callback_connect_status = -2;
+ callback_read_key = callback_write_key =
+ callback_accept_key = callback_connect_key = NULL;
+ callback_read_op = callback_write_op = NULL;
+
+ // Poll if pending.
+ while (send_pending || recv_pending) {
+ int rc;
+ pj_time_val timeout = { 5, 0 };
+
+ TRACE_("poll...");
+ rc = pj_ioqueue_poll(ioque, &timeout);
+
+ if (rc == 0) {
+ PJ_LOG(1,(THIS_FILE, "...ERROR: timed out..."));
+ status=-45; goto on_error;
+ } else if (rc < 0) {
+ app_perror("...ERROR in ioqueue_poll()", rc);
+ status=-50; goto on_error;
+ }
+
+ if (callback_read_key != NULL) {
+ if (callback_read_size != bufsize) {
+ status=-61; goto on_error;
+ }
+ if (callback_read_key != skey) {
+ status=-65; goto on_error;
+ }
+ if (callback_read_op != &read_op) {
+ status=-66; goto on_error;
+ }
+
+ if (memcmp(send_buf, recv_buf, bufsize) != 0) {
+ status=-70; goto on_error;
+ }
+
+
+ recv_pending = 0;
+ }
+
+ if (callback_write_key != NULL) {
+ if (callback_write_size != bufsize) {
+ status=-73; goto on_error;
+ }
+ if (callback_write_key != ckey) {
+ status=-75; goto on_error;
+ }
+ if (callback_write_op != &write_op) {
+ status=-76; goto on_error;
+ }
+
+ send_pending = 0;
+ }
+ }
+
+ // Success
+ status = 0;
+
+on_error:
+ if (status != 0) {
+ char errbuf[128];
+ PJ_LOG(1, (THIS_FILE,
+ "...compliance test error: status=%d, os_err=%d (%s)",
+ status, pj_get_netos_error(),
+ pj_strerror(pj_get_netos_error(), errbuf, sizeof(errbuf))));
+ }
+ if (ssock)
+ pj_sock_close(ssock);
+ if (csock)
+ pj_sock_close(csock);
+ if (ioque != NULL)
+ pj_ioqueue_destroy(ioque);
+ pj_pool_release(pool);
+ return status;
+
+}
+
+/*
+ * Testing with many handles.
+ * This will just test registering PJ_IOQUEUE_MAX_HANDLES count
+ * of sockets to the ioqueue.
+ */
+static int many_handles_test(void)
+{
+ enum { MAX = PJ_IOQUEUE_MAX_HANDLES };
+ pj_pool_t *pool;
+ pj_ioqueue_t *ioqueue;
+ pj_sock_t *sock;
+ pj_ioqueue_key_t **key;
+ pj_status_t rc;
+ int count, i;
+
+ PJ_LOG(3,(THIS_FILE,"...testing with so many handles"));
+
+ pool = pj_pool_create(mem, NULL, 4000, 4000, NULL);
+ if (!pool)
+ return PJ_ENOMEM;
+
+ key = pj_pool_alloc(pool, MAX*sizeof(pj_ioqueue_key_t*));
+ sock = pj_pool_alloc(pool, MAX*sizeof(pj_sock_t));
+
+ /* Create IOQueue */
+ rc = pj_ioqueue_create(pool, MAX, &ioqueue);
+ if (rc != PJ_SUCCESS || ioqueue == NULL) {
+ app_perror("...error in pj_ioqueue_create", rc);
+ return -10;
+ }
+
+ /* Register as many sockets. */
+ for (count=0; count<MAX; ++count) {
+ sock[count] = PJ_INVALID_SOCKET;
+ rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock[count]);
+ if (rc != PJ_SUCCESS || sock[count] == PJ_INVALID_SOCKET) {
+ PJ_LOG(3,(THIS_FILE, "....unable to create %d-th socket, rc=%d",
+ count, rc));
+ break;
+ }
+ key[count] = NULL;
+ rc = pj_ioqueue_register_sock(pool, ioqueue, sock[count],
+ NULL, &test_cb, &key[count]);
+ if (rc != PJ_SUCCESS || key[count] == NULL) {
+ PJ_LOG(3,(THIS_FILE, "....unable to register %d-th socket, rc=%d",
+ count, rc));
+ return -30;
+ }
+ }
+
+ /* Test complete. */
+
+ /* Now deregister and close all handles. */
+
+ for (i=0; i<count; ++i) {
+ rc = pj_ioqueue_unregister(key[i]);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error in pj_ioqueue_unregister", rc);
+ }
+ rc = pj_sock_close(sock[i]);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error in pj_sock_close", rc);
+ }
+ }
+
+ rc = pj_ioqueue_destroy(ioqueue);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error in pj_ioqueue_destroy", rc);
+ }
+
+ pj_pool_release(pool);
+
+ PJ_LOG(3,(THIS_FILE,"....many_handles_test() ok"));
+
+ return 0;
+}
+
+/*
+ * Multi-operation test.
+ */
+
+/*
+ * Benchmarking IOQueue
+ */
+static int bench_test(int bufsize, int inactive_sock_count)
+{
+ pj_sock_t ssock=-1, csock=-1;
+ pj_sockaddr_in addr;
+ pj_pool_t *pool = NULL;
+ pj_sock_t *inactive_sock=NULL;
+ pj_ioqueue_op_key_t *inactive_read_op;
+ char *send_buf, *recv_buf;
+ pj_ioqueue_t *ioque = NULL;
+ pj_ioqueue_key_t *skey, *ckey, *key;
+ pj_timestamp t1, t2, t_elapsed;
+ int rc=0, i;
+ pj_str_t temp;
+ char errbuf[128];
+
+ // Create pool.
+ pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);
+
+ // Allocate buffers for send and receive.
+ send_buf = (char*)pj_pool_alloc(pool, bufsize);
+ recv_buf = (char*)pj_pool_alloc(pool, bufsize);
+
+ // Allocate sockets for sending and receiving.
+ rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &ssock);
+ if (rc == PJ_SUCCESS) {
+ rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &csock);
+ } else
+ csock = PJ_INVALID_SOCKET;
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error: pj_sock_socket()", rc);
+ goto on_error;
+ }
+
+ // Bind server socket.
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = PJ_AF_INET;
+ addr.sin_port = pj_htons(PORT);
+ if (pj_sock_bind(ssock, &addr, sizeof(addr)))
+ goto on_error;
+
+ pj_assert(inactive_sock_count+2 <= PJ_IOQUEUE_MAX_HANDLES);
+
+ // Create I/O Queue.
+ rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error: pj_ioqueue_create()", rc);
+ goto on_error;
+ }
+
+ // Allocate inactive sockets, and bind them to some arbitrary address.
+ // Then register them to the I/O queue, and start a read operation.
+ inactive_sock = (pj_sock_t*)pj_pool_alloc(pool,
+ inactive_sock_count*sizeof(pj_sock_t));
+ inactive_read_op = (pj_ioqueue_op_key_t*)pj_pool_alloc(pool,
+ inactive_sock_count*sizeof(pj_ioqueue_op_key_t));
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = PJ_AF_INET;
+ for (i=0; i<inactive_sock_count; ++i) {
+ pj_ssize_t bytes;
+
+ rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &inactive_sock[i]);
+ if (rc != PJ_SUCCESS || inactive_sock[i] < 0) {
+ app_perror("...error: pj_sock_socket()", rc);
+ goto on_error;
+ }
+ if ((rc=pj_sock_bind(inactive_sock[i], &addr, sizeof(addr))) != 0) {
+ pj_sock_close(inactive_sock[i]);
+ inactive_sock[i] = PJ_INVALID_SOCKET;
+ app_perror("...error: pj_sock_bind()", rc);
+ goto on_error;
+ }
+ rc = pj_ioqueue_register_sock(pool, ioque, inactive_sock[i],
+ NULL, &test_cb, &key);
+ if (rc != PJ_SUCCESS) {
+ pj_sock_close(inactive_sock[i]);
+ inactive_sock[i] = PJ_INVALID_SOCKET;
+ app_perror("...error(1): pj_ioqueue_register_sock()", rc);
+ PJ_LOG(3,(THIS_FILE, "....i=%d", i));
+ goto on_error;
+ }
+ bytes = bufsize;
+ rc = pj_ioqueue_recv(key, &inactive_read_op[i], recv_buf, &bytes, 0);
+ if ( rc < 0 && rc != PJ_EPENDING) {
+ pj_sock_close(inactive_sock[i]);
+ inactive_sock[i] = PJ_INVALID_SOCKET;
+ app_perror("...error: pj_ioqueue_read()", rc);
+ goto on_error;
+ }
+ }
+
+ // Register server and client socket.
+ // We put this after inactivity socket, hopefully this can represent the
+ // worst waiting time.
+ rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL,
+ &test_cb, &skey);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error(2): pj_ioqueue_register_sock()", rc);
+ goto on_error;
+ }
+
+ rc = pj_ioqueue_register_sock(pool, ioque, csock, NULL,
+ &test_cb, &ckey);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error(3): pj_ioqueue_register_sock()", rc);
+ goto on_error;
+ }
+
+ // Set destination address to send the packet.
+ pj_sockaddr_in_init(&addr, pj_cstr(&temp, "127.0.0.1"), PORT);
+
+ // Test loop.
+ t_elapsed.u64 = 0;
+ for (i=0; i<LOOP; ++i) {
+ pj_ssize_t bytes;
+ pj_ioqueue_op_key_t read_op, write_op;
+
+ // Randomize send buffer.
+ pj_create_random_string(send_buf, bufsize);
+
+ // Start reading on the server side.
+ bytes = bufsize;
+ rc = pj_ioqueue_recv(skey, &read_op, recv_buf, &bytes, 0);
+ if (rc < 0 && rc != PJ_EPENDING) {
+ app_perror("...error: pj_ioqueue_read()", rc);
+ break;
+ }
+
+ // Starts send on the client side.
+ bytes = bufsize;
+ rc = pj_ioqueue_sendto(ckey, &write_op, send_buf, &bytes, 0,
+ &addr, sizeof(addr));
+ if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
+ app_perror("...error: pj_ioqueue_write()", bytes);
+ rc = -1;
+ break;
+ }
+
+ // Begin time.
+ pj_get_timestamp(&t1);
+
+ // Poll the queue until we've got completion event in the server side.
+ callback_read_key = NULL;
+ callback_read_size = 0;
+ do {
+ rc = pj_ioqueue_poll(ioque, NULL);
+ } while (rc >= 0 && callback_read_key != skey);
+
+ // End time.
+ pj_get_timestamp(&t2);
+ t_elapsed.u64 += (t2.u64 - t1.u64);
+
+ if (rc < 0)
+ break;
+
+ // Compare recv buffer with send buffer.
+ if (callback_read_size != bufsize ||
+ memcmp(send_buf, recv_buf, bufsize))
+ {
+ rc = -1;
+ break;
+ }
+
+ // Poll until all events are exhausted, before we start the next loop.
+ do {
+ pj_time_val timeout = { 0, 10 };
+ rc = pj_ioqueue_poll(ioque, &timeout);
+ } while (rc>0);
+
+ rc = 0;
+ }
+
+ // Print results
+ if (rc == 0) {
+ pj_timestamp tzero;
+ pj_uint32_t usec_delay;
+
+ tzero.u32.hi = tzero.u32.lo = 0;
+ usec_delay = pj_elapsed_usec( &tzero, &t_elapsed);
+
+ PJ_LOG(3, (THIS_FILE, "...%10d %15d % 9d",
+ bufsize, inactive_sock_count, usec_delay));
+
+ } else {
+ PJ_LOG(2, (THIS_FILE, "...ERROR (buf:%d, fds:%d)",
+ bufsize, inactive_sock_count+2));
+ }
+
+ // Cleaning up.
+ for (i=0; i<inactive_sock_count; ++i)
+ pj_sock_close(inactive_sock[i]);
+ pj_sock_close(ssock);
+ pj_sock_close(csock);
+
+ pj_ioqueue_destroy(ioque);
+ pj_pool_release( pool);
+ return 0;
+
+on_error:
+ PJ_LOG(1,(THIS_FILE, "...ERROR: %s",
+ pj_strerror(pj_get_netos_error(), errbuf, sizeof(errbuf))));
+ if (ssock)
+ pj_sock_close(ssock);
+ if (csock)
+ pj_sock_close(csock);
+ for (i=0; i<inactive_sock_count && inactive_sock &&
+ inactive_sock[i]!=PJ_INVALID_SOCKET; ++i)
+ {
+ pj_sock_close(inactive_sock[i]);
+ }
+ if (ioque != NULL)
+ pj_ioqueue_destroy(ioque);
+ pj_pool_release( pool);
+ return -1;
+}
+
+int udp_ioqueue_test()
+{
+ int status;
+ int bufsize, sock_count;
+
+ PJ_LOG(3, (THIS_FILE, "...compliance test (%s)", pj_ioqueue_name()));
+ if ((status=compliance_test()) != 0) {
+ return status;
+ }
+ PJ_LOG(3, (THIS_FILE, "....compliance test ok"));
+
+ if ((status=many_handles_test()) != 0) {
+ return status;
+ }
+
+ PJ_LOG(4, (THIS_FILE, "...benchmarking different buffer size:"));
+ PJ_LOG(4, (THIS_FILE, "... note: buf=bytes sent, fds=# of fds, "
+ "elapsed=in timer ticks"));
+
+ PJ_LOG(3, (THIS_FILE, "...Benchmarking poll times for %s:", pj_ioqueue_name()));
+ PJ_LOG(3, (THIS_FILE, "...====================================="));
+ PJ_LOG(3, (THIS_FILE, "...Buf.size #inactive-socks Time/poll"));
+ PJ_LOG(3, (THIS_FILE, "... (bytes) (nanosec)"));
+ PJ_LOG(3, (THIS_FILE, "...====================================="));
+
+ for (bufsize=BUF_MIN_SIZE; bufsize <= BUF_MAX_SIZE; bufsize *= 2) {
+ if (bench_test(bufsize, SOCK_INACTIVE_MIN))
+ return -1;
+ }
+ bufsize = 512;
+ for (sock_count=SOCK_INACTIVE_MIN+2;
+ sock_count<=SOCK_INACTIVE_MAX+2;
+ sock_count *= 2)
+ {
+ //PJ_LOG(3,(THIS_FILE, "...testing with %d fds", sock_count));
+ if (bench_test(bufsize, sock_count-2))
+ return -1;
+ }
+ return 0;
+}
+
+#else
+/* To prevent warning about "translation unit is empty"
+ * when this test is disabled.
+ */
+int dummy_uiq_udp;
+#endif /* INCLUDE_UDP_IOQUEUE_TEST */
+
+
diff --git a/pjlib/src/pjlib-test/list.c b/pjlib/src/pjlib-test/list.c
index 4184e801..2a2dafb8 100644
--- a/pjlib/src/pjlib-test/list.c
+++ b/pjlib/src/pjlib-test/list.c
@@ -1,209 +1,230 @@
-/* $Id$
- */
-#include "test.h"
-
-/**
- * \page page_pjlib_list_test Test: Linked List
- *
- * This file provides implementation of \b list_test(). It tests the
- * functionality of the linked-list API.
- *
- * \section list_test_sec Scope of the Test
- *
- * API tested:
- * - pj_list_init()
- * - pj_list_insert_before()
- * - pj_list_insert_after()
- * - pj_list_merge_last()
- * - pj_list_empty()
- * - pj_list_insert_nodes_before()
- * - pj_list_erase()
- * - pj_list_find_node()
- * - pj_list_search()
- *
- *
- * This file is <b>pjlib-test/list.c</b>
- *
- * \include pjlib-test/list.c
- */
-
-#if INCLUDE_LIST_TEST
-
-#include <pjlib.h>
-
-typedef struct list_node
-{
- PJ_DECL_LIST_MEMBER(struct list_node);
- int value;
-} list_node;
-
-static int compare_node(void *value, const pj_list_type *nd)
-{
- list_node *node = (list_node*)nd;
- return ((long)value == node->value) ? 0 : -1;
-}
-
-#define PJ_SIGNED_ARRAY_SIZE(a) ((int)PJ_ARRAY_SIZE(a))
-
-int list_test()
-{
- list_node nodes[4]; // must be even number of nodes
- list_node list;
- list_node list2;
- list_node *p;
- int i; // don't change to unsigned!
-
- //
- // Test insert_before().
- //
- list.value = (unsigned)-1;
- pj_list_init(&list);
- for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {
- nodes[i].value = i;
- pj_list_insert_before(&list, &nodes[i]);
- }
- // check.
- for (i=0, p=list.next; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i, p=p->next) {
- pj_assert(p->value == i);
- if (p->value != i) {
- return -1;
- }
- }
-
- //
- // Test insert_after()
- //
- pj_list_init(&list);
- for (i=PJ_SIGNED_ARRAY_SIZE(nodes)-1; i>=0; --i) {
- pj_list_insert_after(&list, &nodes[i]);
- }
- // check.
- for (i=0, p=list.next; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i, p=p->next) {
- pj_assert(p->value == i);
- if (p->value != i) {
- return -1;
- }
- }
-
- //
- // Test merge_last()
- //
- // Init lists
- pj_list_init(&list);
- pj_list_init(&list2);
- for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes)/2; ++i) {
- pj_list_insert_before(&list, &nodes[i]);
- }
- for (i=PJ_SIGNED_ARRAY_SIZE(nodes)/2; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {
- pj_list_insert_before(&list2, &nodes[i]);
- }
- // merge
- pj_list_merge_last(&list, &list2);
- // check.
- for (i=0, p=list.next; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i, p=p->next) {
- pj_assert(p->value == i);
- if (p->value != i) {
- return -1;
- }
- }
- // check list is empty
- pj_assert( pj_list_empty(&list2) );
- if (!pj_list_empty(&list2)) {
- return -1;
- }
-
- //
- // Check merge_first()
- //
- pj_list_init(&list);
- pj_list_init(&list2);
- for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes)/2; ++i) {
- pj_list_insert_before(&list, &nodes[i]);
- }
- for (i=PJ_SIGNED_ARRAY_SIZE(nodes)/2; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {
- pj_list_insert_before(&list2, &nodes[i]);
- }
- // merge
- pj_list_merge_first(&list2, &list);
- // check (list2).
- for (i=0, p=list2.next; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i, p=p->next) {
- pj_assert(p->value == i);
- if (p->value != i) {
- return -1;
- }
- }
- // check list is empty
- pj_assert( pj_list_empty(&list) );
- if (!pj_list_empty(&list)) {
- return -1;
- }
-
- //
- // Test insert_nodes_before()
- //
- // init list
- pj_list_init(&list);
- for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes)/2; ++i) {
- pj_list_insert_before(&list, &nodes[i]);
- }
- // chain remaining nodes
- pj_list_init(&nodes[PJ_SIGNED_ARRAY_SIZE(nodes)/2]);
- for (i=PJ_SIGNED_ARRAY_SIZE(nodes)/2+1; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {
- pj_list_insert_before(&nodes[PJ_SIGNED_ARRAY_SIZE(nodes)/2], &nodes[i]);
- }
- // insert nodes
- pj_list_insert_nodes_before(&list, &nodes[PJ_SIGNED_ARRAY_SIZE(nodes)/2]);
- // check
- for (i=0, p=list.next; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i, p=p->next) {
- pj_assert(p->value == i);
- if (p->value != i) {
- return -1;
- }
- }
-
- // erase test.
- pj_list_init(&list);
- for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {
- nodes[i].value = i;
- pj_list_insert_before(&list, &nodes[i]);
- }
- for (i=PJ_SIGNED_ARRAY_SIZE(nodes)-1; i>=0; --i) {
- int j;
- pj_list_erase(&nodes[i]);
- for (j=0, p=list.next; j<i; ++j, p=p->next) {
- pj_assert(p->value == j);
- if (p->value != j) {
- return -1;
- }
- }
- }
-
- // find and search
- pj_list_init(&list);
- for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {
- nodes[i].value = i;
- pj_list_insert_before(&list, &nodes[i]);
- }
- for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {
- p = (list_node*) pj_list_find_node(&list, &nodes[i]);
- pj_assert( p == &nodes[i] );
- if (p != &nodes[i]) {
- return -1;
- }
- p = (list_node*) pj_list_search(&list, (void*)(long)i, &compare_node);
- pj_assert( p == &nodes[i] );
- if (p != &nodes[i]) {
- return -1;
- }
- }
- return 0;
-}
-
-#else
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled.
- */
-int dummy_list_test;
-#endif /* INCLUDE_LIST_TEST */
-
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "test.h"
+
+/**
+ * \page page_pjlib_list_test Test: Linked List
+ *
+ * This file provides implementation of \b list_test(). It tests the
+ * functionality of the linked-list API.
+ *
+ * \section list_test_sec Scope of the Test
+ *
+ * API tested:
+ * - pj_list_init()
+ * - pj_list_insert_before()
+ * - pj_list_insert_after()
+ * - pj_list_merge_last()
+ * - pj_list_empty()
+ * - pj_list_insert_nodes_before()
+ * - pj_list_erase()
+ * - pj_list_find_node()
+ * - pj_list_search()
+ *
+ *
+ * This file is <b>pjlib-test/list.c</b>
+ *
+ * \include pjlib-test/list.c
+ */
+
+#if INCLUDE_LIST_TEST
+
+#include <pjlib.h>
+
+typedef struct list_node
+{
+ PJ_DECL_LIST_MEMBER(struct list_node);
+ int value;
+} list_node;
+
+static int compare_node(void *value, const pj_list_type *nd)
+{
+ list_node *node = (list_node*)nd;
+ return ((long)value == node->value) ? 0 : -1;
+}
+
+#define PJ_SIGNED_ARRAY_SIZE(a) ((int)PJ_ARRAY_SIZE(a))
+
+int list_test()
+{
+ list_node nodes[4]; // must be even number of nodes
+ list_node list;
+ list_node list2;
+ list_node *p;
+ int i; // don't change to unsigned!
+
+ //
+ // Test insert_before().
+ //
+ list.value = (unsigned)-1;
+ pj_list_init(&list);
+ for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {
+ nodes[i].value = i;
+ pj_list_insert_before(&list, &nodes[i]);
+ }
+ // check.
+ for (i=0, p=list.next; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i, p=p->next) {
+ pj_assert(p->value == i);
+ if (p->value != i) {
+ return -1;
+ }
+ }
+
+ //
+ // Test insert_after()
+ //
+ pj_list_init(&list);
+ for (i=PJ_SIGNED_ARRAY_SIZE(nodes)-1; i>=0; --i) {
+ pj_list_insert_after(&list, &nodes[i]);
+ }
+ // check.
+ for (i=0, p=list.next; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i, p=p->next) {
+ pj_assert(p->value == i);
+ if (p->value != i) {
+ return -1;
+ }
+ }
+
+ //
+ // Test merge_last()
+ //
+ // Init lists
+ pj_list_init(&list);
+ pj_list_init(&list2);
+ for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes)/2; ++i) {
+ pj_list_insert_before(&list, &nodes[i]);
+ }
+ for (i=PJ_SIGNED_ARRAY_SIZE(nodes)/2; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {
+ pj_list_insert_before(&list2, &nodes[i]);
+ }
+ // merge
+ pj_list_merge_last(&list, &list2);
+ // check.
+ for (i=0, p=list.next; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i, p=p->next) {
+ pj_assert(p->value == i);
+ if (p->value != i) {
+ return -1;
+ }
+ }
+ // check list is empty
+ pj_assert( pj_list_empty(&list2) );
+ if (!pj_list_empty(&list2)) {
+ return -1;
+ }
+
+ //
+ // Check merge_first()
+ //
+ pj_list_init(&list);
+ pj_list_init(&list2);
+ for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes)/2; ++i) {
+ pj_list_insert_before(&list, &nodes[i]);
+ }
+ for (i=PJ_SIGNED_ARRAY_SIZE(nodes)/2; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {
+ pj_list_insert_before(&list2, &nodes[i]);
+ }
+ // merge
+ pj_list_merge_first(&list2, &list);
+ // check (list2).
+ for (i=0, p=list2.next; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i, p=p->next) {
+ pj_assert(p->value == i);
+ if (p->value != i) {
+ return -1;
+ }
+ }
+ // check list is empty
+ pj_assert( pj_list_empty(&list) );
+ if (!pj_list_empty(&list)) {
+ return -1;
+ }
+
+ //
+ // Test insert_nodes_before()
+ //
+ // init list
+ pj_list_init(&list);
+ for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes)/2; ++i) {
+ pj_list_insert_before(&list, &nodes[i]);
+ }
+ // chain remaining nodes
+ pj_list_init(&nodes[PJ_SIGNED_ARRAY_SIZE(nodes)/2]);
+ for (i=PJ_SIGNED_ARRAY_SIZE(nodes)/2+1; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {
+ pj_list_insert_before(&nodes[PJ_SIGNED_ARRAY_SIZE(nodes)/2], &nodes[i]);
+ }
+ // insert nodes
+ pj_list_insert_nodes_before(&list, &nodes[PJ_SIGNED_ARRAY_SIZE(nodes)/2]);
+ // check
+ for (i=0, p=list.next; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i, p=p->next) {
+ pj_assert(p->value == i);
+ if (p->value != i) {
+ return -1;
+ }
+ }
+
+ // erase test.
+ pj_list_init(&list);
+ for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {
+ nodes[i].value = i;
+ pj_list_insert_before(&list, &nodes[i]);
+ }
+ for (i=PJ_SIGNED_ARRAY_SIZE(nodes)-1; i>=0; --i) {
+ int j;
+ pj_list_erase(&nodes[i]);
+ for (j=0, p=list.next; j<i; ++j, p=p->next) {
+ pj_assert(p->value == j);
+ if (p->value != j) {
+ return -1;
+ }
+ }
+ }
+
+ // find and search
+ pj_list_init(&list);
+ for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {
+ nodes[i].value = i;
+ pj_list_insert_before(&list, &nodes[i]);
+ }
+ for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {
+ p = (list_node*) pj_list_find_node(&list, &nodes[i]);
+ pj_assert( p == &nodes[i] );
+ if (p != &nodes[i]) {
+ return -1;
+ }
+ p = (list_node*) pj_list_search(&list, (void*)(long)i, &compare_node);
+ pj_assert( p == &nodes[i] );
+ if (p != &nodes[i]) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+#else
+/* To prevent warning about "translation unit is empty"
+ * when this test is disabled.
+ */
+int dummy_list_test;
+#endif /* INCLUDE_LIST_TEST */
+
+
diff --git a/pjlib/src/pjlib-test/main.c b/pjlib/src/pjlib-test/main.c
index 6a764e64..bf8e99ce 100644
--- a/pjlib/src/pjlib-test/main.c
+++ b/pjlib/src/pjlib-test/main.c
@@ -1,77 +1,98 @@
-/* $Id$
- */
-#include "test.h"
-
-#include <pj/string.h>
-#include <pj/sock.h>
-#include <pj/log.h>
-
-extern int param_echo_sock_type;
-extern const char *param_echo_server;
-extern int param_echo_port;
-
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "test.h"
+
+#include <pj/string.h>
+#include <pj/sock.h>
+#include <pj/log.h>
+
+extern int param_echo_sock_type;
+extern const char *param_echo_server;
+extern int param_echo_port;
+
+
//#if defined(PJ_WIN32) && PJ_WIN32!=0
-#if 0
-#include <windows.h>
-static void boost(void)
-{
- SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
-}
-#else
-#define boost()
-#endif
-
-#if defined(PJ_SUNOS) && PJ_SUNOS!=0
-#include <signal.h>
-static void init_signals()
-{
- struct sigaction act;
-
- memset(&act, 0, sizeof(act));
- act.sa_handler = SIG_IGN;
-
- sigaction(SIGALRM, &act, NULL);
-}
-
-#else
-#define init_signals()
-#endif
-
-int main(int argc, char *argv[])
-{
- int rc;
-
- boost();
- init_signals();
-
- while (argc > 1) {
- char *arg = argv[--argc];
-
- if (*arg=='-' && *(arg+1)=='p') {
- pj_str_t port = pj_str(argv[--argc]);
-
- param_echo_port = pj_strtoul(&port);
-
- } else if (*arg=='-' && *(arg+1)=='s') {
- param_echo_server = argv[--argc];
-
- } else if (*arg=='-' && *(arg+1)=='t') {
- pj_str_t type = pj_str(argv[--argc]);
-
- if (pj_stricmp2(&type, "tcp")==0)
- param_echo_sock_type = PJ_SOCK_STREAM;
- else if (pj_stricmp2(&type, "udp")==0)
- param_echo_sock_type = PJ_SOCK_DGRAM;
- else {
- PJ_LOG(3,("", "error: unknown socket type %s", type.ptr));
- return 1;
- }
- }
- }
-
- rc = test_main();
-
- return rc;
-}
-
+#if 0
+#include <windows.h>
+static void boost(void)
+{
+ SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
+}
+#else
+#define boost()
+#endif
+
+#if defined(PJ_SUNOS) && PJ_SUNOS!=0
+#include <signal.h>
+static void init_signals()
+{
+ struct sigaction act;
+
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = SIG_IGN;
+
+ sigaction(SIGALRM, &act, NULL);
+}
+
+#else
+#define init_signals()
+#endif
+
+int main(int argc, char *argv[])
+{
+ int rc;
+
+ boost();
+ init_signals();
+
+ while (argc > 1) {
+ char *arg = argv[--argc];
+
+ if (*arg=='-' && *(arg+1)=='p') {
+ pj_str_t port = pj_str(argv[--argc]);
+
+ param_echo_port = pj_strtoul(&port);
+
+ } else if (*arg=='-' && *(arg+1)=='s') {
+ param_echo_server = argv[--argc];
+
+ } else if (*arg=='-' && *(arg+1)=='t') {
+ pj_str_t type = pj_str(argv[--argc]);
+
+ if (pj_stricmp2(&type, "tcp")==0)
+ param_echo_sock_type = PJ_SOCK_STREAM;
+ else if (pj_stricmp2(&type, "udp")==0)
+ param_echo_sock_type = PJ_SOCK_DGRAM;
+ else {
+ PJ_LOG(3,("", "error: unknown socket type %s", type.ptr));
+ return 1;
+ }
+ }
+ }
+
+ rc = test_main();
+
+ return rc;
+}
+
diff --git a/pjlib/src/pjlib-test/main_mod.c b/pjlib/src/pjlib-test/main_mod.c
index 7978e36b..34dfc707 100644
--- a/pjlib/src/pjlib-test/main_mod.c
+++ b/pjlib/src/pjlib-test/main_mod.c
@@ -1,23 +1,44 @@
-/* $Id$
- */
-#include "test.h"
-#include <linux/module.h>
-#include <linux/kernel.h>
-
-int init_module(void)
-{
- printk(KERN_INFO "PJLIB test module loaded. Starting tests...\n");
-
- test_main();
-
- /* Prevent module from loading. We've finished test anyway.. */
- return 1;
-}
-
-void cleanup_module(void)
-{
- printk(KERN_INFO "PJLIB test module unloading...\n");
-}
-
-MODULE_LICENSE("GPL");
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "test.h"
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+int init_module(void)
+{
+ printk(KERN_INFO "PJLIB test module loaded. Starting tests...\n");
+
+ test_main();
+
+ /* Prevent module from loading. We've finished test anyway.. */
+ return 1;
+}
+
+void cleanup_module(void)
+{
+ printk(KERN_INFO "PJLIB test module unloading...\n");
+}
+
+MODULE_LICENSE("GPL");
+
diff --git a/pjlib/src/pjlib-test/mutex.c b/pjlib/src/pjlib-test/mutex.c
index c7af51b5..f82987c2 100644
--- a/pjlib/src/pjlib-test/mutex.c
+++ b/pjlib/src/pjlib-test/mutex.c
@@ -1,158 +1,179 @@
-/* $Id$
- */
-#include "test.h"
-#include <pjlib.h>
-
-#if INCLUDE_MUTEX_TEST
-
-#undef TRACE_
-//#define TRACE_(x) PJ_LOG(3,x)
-#define TRACE_(x)
-
-/* Test witn non-recursive mutex. */
-static int simple_mutex_test(pj_pool_t *pool)
-{
- pj_status_t rc;
- pj_mutex_t *mutex;
-
- PJ_LOG(3,("", "...testing simple mutex"));
-
- /* Create mutex. */
- TRACE_(("", "....create mutex"));
- rc = pj_mutex_create( pool, "", PJ_MUTEX_SIMPLE, &mutex);
- if (rc != PJ_SUCCESS) {
- app_perror("...error: pj_mutex_create", rc);
- return -10;
- }
-
- /* Normal lock/unlock cycle. */
- TRACE_(("", "....lock mutex"));
- rc = pj_mutex_lock(mutex);
- if (rc != PJ_SUCCESS) {
- app_perror("...error: pj_mutex_lock", rc);
- return -20;
- }
- TRACE_(("", "....unlock mutex"));
- rc = pj_mutex_unlock(mutex);
- if (rc != PJ_SUCCESS) {
- app_perror("...error: pj_mutex_unlock", rc);
- return -30;
- }
-
- /* Lock again. */
- TRACE_(("", "....lock mutex"));
- rc = pj_mutex_lock(mutex);
- if (rc != PJ_SUCCESS) return -40;
-
- /* Try-lock should fail. It should not deadlocked. */
- TRACE_(("", "....trylock mutex"));
- rc = pj_mutex_trylock(mutex);
- if (rc == PJ_SUCCESS)
- PJ_LOG(3,("", "...info: looks like simple mutex is recursive"));
-
- /* Unlock and done. */
- TRACE_(("", "....unlock mutex"));
- rc = pj_mutex_unlock(mutex);
- if (rc != PJ_SUCCESS) return -50;
-
- TRACE_(("", "....destroy mutex"));
- rc = pj_mutex_destroy(mutex);
- if (rc != PJ_SUCCESS) return -60;
-
- TRACE_(("", "....done"));
- return PJ_SUCCESS;
-}
-
-
-/* Test with recursive mutex. */
-static int recursive_mutex_test(pj_pool_t *pool)
-{
- pj_status_t rc;
- pj_mutex_t *mutex;
-
- PJ_LOG(3,("", "...testing recursive mutex"));
-
- /* Create mutex. */
- TRACE_(("", "....create mutex"));
- rc = pj_mutex_create( pool, "", PJ_MUTEX_RECURSE, &mutex);
- if (rc != PJ_SUCCESS) {
- app_perror("...error: pj_mutex_create", rc);
- return -10;
- }
-
- /* Normal lock/unlock cycle. */
- TRACE_(("", "....lock mutex"));
- rc = pj_mutex_lock(mutex);
- if (rc != PJ_SUCCESS) {
- app_perror("...error: pj_mutex_lock", rc);
- return -20;
- }
- TRACE_(("", "....unlock mutex"));
- rc = pj_mutex_unlock(mutex);
- if (rc != PJ_SUCCESS) {
- app_perror("...error: pj_mutex_unlock", rc);
- return -30;
- }
-
- /* Lock again. */
- TRACE_(("", "....lock mutex"));
- rc = pj_mutex_lock(mutex);
- if (rc != PJ_SUCCESS) return -40;
-
- /* Try-lock should NOT fail. . */
- TRACE_(("", "....trylock mutex"));
- rc = pj_mutex_trylock(mutex);
- if (rc != PJ_SUCCESS) {
- app_perror("...error: recursive mutex is not recursive!", rc);
- return -40;
- }
-
- /* Locking again should not fail. */
- TRACE_(("", "....lock mutex"));
- rc = pj_mutex_lock(mutex);
- if (rc != PJ_SUCCESS) {
- app_perror("...error: recursive mutex is not recursive!", rc);
- return -45;
- }
-
- /* Unlock several times and done. */
- TRACE_(("", "....unlock mutex 3x"));
- rc = pj_mutex_unlock(mutex);
- if (rc != PJ_SUCCESS) return -50;
- rc = pj_mutex_unlock(mutex);
- if (rc != PJ_SUCCESS) return -51;
- rc = pj_mutex_unlock(mutex);
- if (rc != PJ_SUCCESS) return -52;
-
- TRACE_(("", "....destroy mutex"));
- rc = pj_mutex_destroy(mutex);
- if (rc != PJ_SUCCESS) return -60;
-
- TRACE_(("", "....done"));
- return PJ_SUCCESS;
-}
-
-int mutex_test(void)
-{
- pj_pool_t *pool;
- int rc;
-
- pool = pj_pool_create(mem, "", 4000, 4000, NULL);
-
- rc = simple_mutex_test(pool);
- if (rc != 0)
- return rc;
-
- rc = recursive_mutex_test(pool);
- if (rc != 0)
- return rc;
-
- pj_pool_release(pool);
-
- return 0;
-}
-
-#else
-int dummy_mutex_test;
-#endif
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "test.h"
+#include <pjlib.h>
+
+#if INCLUDE_MUTEX_TEST
+
+#undef TRACE_
+//#define TRACE_(x) PJ_LOG(3,x)
+#define TRACE_(x)
+
+/* Test witn non-recursive mutex. */
+static int simple_mutex_test(pj_pool_t *pool)
+{
+ pj_status_t rc;
+ pj_mutex_t *mutex;
+
+ PJ_LOG(3,("", "...testing simple mutex"));
+
+ /* Create mutex. */
+ TRACE_(("", "....create mutex"));
+ rc = pj_mutex_create( pool, "", PJ_MUTEX_SIMPLE, &mutex);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error: pj_mutex_create", rc);
+ return -10;
+ }
+
+ /* Normal lock/unlock cycle. */
+ TRACE_(("", "....lock mutex"));
+ rc = pj_mutex_lock(mutex);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error: pj_mutex_lock", rc);
+ return -20;
+ }
+ TRACE_(("", "....unlock mutex"));
+ rc = pj_mutex_unlock(mutex);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error: pj_mutex_unlock", rc);
+ return -30;
+ }
+
+ /* Lock again. */
+ TRACE_(("", "....lock mutex"));
+ rc = pj_mutex_lock(mutex);
+ if (rc != PJ_SUCCESS) return -40;
+
+ /* Try-lock should fail. It should not deadlocked. */
+ TRACE_(("", "....trylock mutex"));
+ rc = pj_mutex_trylock(mutex);
+ if (rc == PJ_SUCCESS)
+ PJ_LOG(3,("", "...info: looks like simple mutex is recursive"));
+
+ /* Unlock and done. */
+ TRACE_(("", "....unlock mutex"));
+ rc = pj_mutex_unlock(mutex);
+ if (rc != PJ_SUCCESS) return -50;
+
+ TRACE_(("", "....destroy mutex"));
+ rc = pj_mutex_destroy(mutex);
+ if (rc != PJ_SUCCESS) return -60;
+
+ TRACE_(("", "....done"));
+ return PJ_SUCCESS;
+}
+
+
+/* Test with recursive mutex. */
+static int recursive_mutex_test(pj_pool_t *pool)
+{
+ pj_status_t rc;
+ pj_mutex_t *mutex;
+
+ PJ_LOG(3,("", "...testing recursive mutex"));
+
+ /* Create mutex. */
+ TRACE_(("", "....create mutex"));
+ rc = pj_mutex_create( pool, "", PJ_MUTEX_RECURSE, &mutex);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error: pj_mutex_create", rc);
+ return -10;
+ }
+
+ /* Normal lock/unlock cycle. */
+ TRACE_(("", "....lock mutex"));
+ rc = pj_mutex_lock(mutex);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error: pj_mutex_lock", rc);
+ return -20;
+ }
+ TRACE_(("", "....unlock mutex"));
+ rc = pj_mutex_unlock(mutex);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error: pj_mutex_unlock", rc);
+ return -30;
+ }
+
+ /* Lock again. */
+ TRACE_(("", "....lock mutex"));
+ rc = pj_mutex_lock(mutex);
+ if (rc != PJ_SUCCESS) return -40;
+
+ /* Try-lock should NOT fail. . */
+ TRACE_(("", "....trylock mutex"));
+ rc = pj_mutex_trylock(mutex);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error: recursive mutex is not recursive!", rc);
+ return -40;
+ }
+
+ /* Locking again should not fail. */
+ TRACE_(("", "....lock mutex"));
+ rc = pj_mutex_lock(mutex);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error: recursive mutex is not recursive!", rc);
+ return -45;
+ }
+
+ /* Unlock several times and done. */
+ TRACE_(("", "....unlock mutex 3x"));
+ rc = pj_mutex_unlock(mutex);
+ if (rc != PJ_SUCCESS) return -50;
+ rc = pj_mutex_unlock(mutex);
+ if (rc != PJ_SUCCESS) return -51;
+ rc = pj_mutex_unlock(mutex);
+ if (rc != PJ_SUCCESS) return -52;
+
+ TRACE_(("", "....destroy mutex"));
+ rc = pj_mutex_destroy(mutex);
+ if (rc != PJ_SUCCESS) return -60;
+
+ TRACE_(("", "....done"));
+ return PJ_SUCCESS;
+}
+
+int mutex_test(void)
+{
+ pj_pool_t *pool;
+ int rc;
+
+ pool = pj_pool_create(mem, "", 4000, 4000, NULL);
+
+ rc = simple_mutex_test(pool);
+ if (rc != 0)
+ return rc;
+
+ rc = recursive_mutex_test(pool);
+ if (rc != 0)
+ return rc;
+
+ pj_pool_release(pool);
+
+ return 0;
+}
+
+#else
+int dummy_mutex_test;
+#endif
+
diff --git a/pjlib/src/pjlib-test/os.c b/pjlib/src/pjlib-test/os.c
index 6ae733cf..da466821 100644
--- a/pjlib/src/pjlib-test/os.c
+++ b/pjlib/src/pjlib-test/os.c
@@ -1,3 +1,24 @@
-/* $Id$
- */
-int dummy_os_var;
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+int dummy_os_var;
diff --git a/pjlib/src/pjlib-test/pool.c b/pjlib/src/pjlib-test/pool.c
index c07d6a74..75414750 100644
--- a/pjlib/src/pjlib-test/pool.c
+++ b/pjlib/src/pjlib-test/pool.c
@@ -1,156 +1,177 @@
-/* $Id$
- */
-#include <pj/pool.h>
-#include <pj/rand.h>
-#include <pj/log.h>
-#include "test.h"
-
-/**
- * \page page_pjlib_pool_test Test: Pool
- *
- * This file provides implementation of \b pool_test(). It tests the
- * functionality of the memory pool.
- *
- *
- * This file is <b>pjlib-test/pool.c</b>
- *
- * \include pjlib-test/pool.c
- */
-
-
-#if INCLUDE_POOL_TEST
-
-#define SIZE 4096
-
-/* Normally we should throw exception when memory alloc fails.
- * Here we do nothing so that the flow will go back to original caller,
- * which will test the result using NULL comparison. Normally caller will
- * catch the exception instead of checking for NULLs.
- */
-static void null_callback(pj_pool_t *pool, pj_size_t size)
-{
- PJ_UNUSED_ARG(pool);
- PJ_UNUSED_ARG(size);
-}
-
-#define GET_FREE(p) (pj_pool_get_capacity(p)-pj_pool_get_used_size(p))
-
-/* Test that the capacity and used size reported by the pool is correct.
- */
-static int capacity_test(void)
-{
- pj_pool_t *pool = pj_pool_create(mem, NULL, SIZE, 0, &null_callback);
- pj_size_t freesize;
-
- PJ_LOG(3,("test", "...capacity_test()"));
-
- if (!pool)
- return -200;
-
- freesize = GET_FREE(pool);
-
- if (pj_pool_alloc(pool, freesize) == NULL) {
- PJ_LOG(3,("test", "...error: wrong freesize %u reported",
- freesize));
- pj_pool_release(pool);
- return -210;
- }
-
- pj_pool_release(pool);
- return 0;
-}
-
-/* Test function to drain the pool's space.
- */
-static int drain_test(pj_size_t size, pj_size_t increment)
-{
- pj_pool_t *pool = pj_pool_create(mem, NULL, size, increment,
- &null_callback);
- pj_size_t freesize;
- void *p;
- int status = 0;
-
- PJ_LOG(3,("test", "...drain_test(%d,%d)", size, increment));
-
- if (!pool)
- return -10;
-
- /* Get free size */
- freesize = GET_FREE(pool);
- if (freesize < 1) {
- status=-15;
- goto on_error;
- }
-
- /* Drain the pool until there's nothing left. */
- while (freesize > 0) {
- int size;
-
- if (freesize > 255)
- size = ((pj_rand() & 0x000000FF) + 4) & ~0x03L;
- else
- size = freesize;
-
- p = pj_pool_alloc(pool, size);
- if (!p) {
- status=-20; goto on_error;
- }
-
- freesize -= size;
- }
-
- /* Check that capacity is zero. */
- if (GET_FREE(pool) != 0) {
- PJ_LOG(3,("test", "....error: returned free=%u (expecting 0)",
- GET_FREE(pool)));
- status=-30; goto on_error;
- }
-
- /* Try to allocate once more */
- p = pj_pool_alloc(pool, 257);
- if (!p) {
- status=-40; goto on_error;
- }
-
- /* Check that capacity is NOT zero. */
- if (GET_FREE(pool) == 0) {
- status=-50; goto on_error;
- }
-
-
-on_error:
- pj_pool_release(pool);
- return status;
-}
-
-int pool_test(void)
-{
- enum { LOOP = 2 };
- int loop;
- int rc;
-
- rc = capacity_test();
- if (rc) return rc;
-
- for (loop=0; loop<LOOP; ++loop) {
- /* Test that the pool should grow automaticly. */
- rc = drain_test(SIZE, SIZE);
- if (rc != 0) return rc;
-
- /* Test situation where pool is not allowed to grow.
- * We expect the test to return correct error.
- */
- rc = drain_test(SIZE, 0);
- if (rc != -40) return rc;
- }
-
- return 0;
-}
-
-#else
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled.
- */
-int dummy_pool_test;
-#endif /* INCLUDE_POOL_TEST */
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/pool.h>
+#include <pj/rand.h>
+#include <pj/log.h>
+#include "test.h"
+
+/**
+ * \page page_pjlib_pool_test Test: Pool
+ *
+ * This file provides implementation of \b pool_test(). It tests the
+ * functionality of the memory pool.
+ *
+ *
+ * This file is <b>pjlib-test/pool.c</b>
+ *
+ * \include pjlib-test/pool.c
+ */
+
+
+#if INCLUDE_POOL_TEST
+
+#define SIZE 4096
+
+/* Normally we should throw exception when memory alloc fails.
+ * Here we do nothing so that the flow will go back to original caller,
+ * which will test the result using NULL comparison. Normally caller will
+ * catch the exception instead of checking for NULLs.
+ */
+static void null_callback(pj_pool_t *pool, pj_size_t size)
+{
+ PJ_UNUSED_ARG(pool);
+ PJ_UNUSED_ARG(size);
+}
+
+#define GET_FREE(p) (pj_pool_get_capacity(p)-pj_pool_get_used_size(p))
+
+/* Test that the capacity and used size reported by the pool is correct.
+ */
+static int capacity_test(void)
+{
+ pj_pool_t *pool = pj_pool_create(mem, NULL, SIZE, 0, &null_callback);
+ pj_size_t freesize;
+
+ PJ_LOG(3,("test", "...capacity_test()"));
+
+ if (!pool)
+ return -200;
+
+ freesize = GET_FREE(pool);
+
+ if (pj_pool_alloc(pool, freesize) == NULL) {
+ PJ_LOG(3,("test", "...error: wrong freesize %u reported",
+ freesize));
+ pj_pool_release(pool);
+ return -210;
+ }
+
+ pj_pool_release(pool);
+ return 0;
+}
+
+/* Test function to drain the pool's space.
+ */
+static int drain_test(pj_size_t size, pj_size_t increment)
+{
+ pj_pool_t *pool = pj_pool_create(mem, NULL, size, increment,
+ &null_callback);
+ pj_size_t freesize;
+ void *p;
+ int status = 0;
+
+ PJ_LOG(3,("test", "...drain_test(%d,%d)", size, increment));
+
+ if (!pool)
+ return -10;
+
+ /* Get free size */
+ freesize = GET_FREE(pool);
+ if (freesize < 1) {
+ status=-15;
+ goto on_error;
+ }
+
+ /* Drain the pool until there's nothing left. */
+ while (freesize > 0) {
+ int size;
+
+ if (freesize > 255)
+ size = ((pj_rand() & 0x000000FF) + 4) & ~0x03L;
+ else
+ size = freesize;
+
+ p = pj_pool_alloc(pool, size);
+ if (!p) {
+ status=-20; goto on_error;
+ }
+
+ freesize -= size;
+ }
+
+ /* Check that capacity is zero. */
+ if (GET_FREE(pool) != 0) {
+ PJ_LOG(3,("test", "....error: returned free=%u (expecting 0)",
+ GET_FREE(pool)));
+ status=-30; goto on_error;
+ }
+
+ /* Try to allocate once more */
+ p = pj_pool_alloc(pool, 257);
+ if (!p) {
+ status=-40; goto on_error;
+ }
+
+ /* Check that capacity is NOT zero. */
+ if (GET_FREE(pool) == 0) {
+ status=-50; goto on_error;
+ }
+
+
+on_error:
+ pj_pool_release(pool);
+ return status;
+}
+
+int pool_test(void)
+{
+ enum { LOOP = 2 };
+ int loop;
+ int rc;
+
+ rc = capacity_test();
+ if (rc) return rc;
+
+ for (loop=0; loop<LOOP; ++loop) {
+ /* Test that the pool should grow automaticly. */
+ rc = drain_test(SIZE, SIZE);
+ if (rc != 0) return rc;
+
+ /* Test situation where pool is not allowed to grow.
+ * We expect the test to return correct error.
+ */
+ rc = drain_test(SIZE, 0);
+ if (rc != -40) return rc;
+ }
+
+ return 0;
+}
+
+#else
+/* To prevent warning about "translation unit is empty"
+ * when this test is disabled.
+ */
+int dummy_pool_test;
+#endif /* INCLUDE_POOL_TEST */
+
diff --git a/pjlib/src/pjlib-test/pool_perf.c b/pjlib/src/pjlib-test/pool_perf.c
index 74827107..d5c55a65 100644
--- a/pjlib/src/pjlib-test/pool_perf.c
+++ b/pjlib/src/pjlib-test/pool_perf.c
@@ -1,124 +1,145 @@
-/* $Id$
- */
-#include "test.h"
-
-#if INCLUDE_POOL_PERF_TEST
-
-#include <pjlib.h>
-#include <pj/compat/malloc.h>
-
-#if !PJ_HAS_HIGH_RES_TIMER
-# error Need high resolution timer for this test.
-#endif
-
-#define THIS_FILE "test"
-
-#define LOOP 10
-#define COUNT 1024
-static unsigned sizes[COUNT];
-#define MIN_SIZE 4
-#define MAX_SIZE 512
-static unsigned total_size;
-
-static int pool_test_pool()
-{
- int i;
- pj_pool_t *pool = pj_pool_create(mem, NULL, total_size + 4*COUNT, 0, NULL);
- if (!pool)
- return -1;
-
- for (i=0; i<COUNT; ++i) {
- char *p;
- if ( (p=(char*)pj_pool_alloc(pool, sizes[i])) == NULL)
- return -1;
- *p = '\0';
- }
-
- pj_pool_release(pool);
- return 0;
-}
-
-static int pool_test_malloc_free()
-{
- char *p[COUNT];
- int i;
-
- for (i=0; i<COUNT; ++i) {
- p[i] = (char*)malloc(sizes[i]);
- if (!p[i]) {
- // Don't care for memory leak in this test
- return -1;
- }
- *p[i] = '\0';
- }
-
- for (i=0; i<COUNT; ++i) {
- free(p[i]);
- }
-
- return 0;
-}
-
-int pool_perf_test()
-{
- unsigned i;
- pj_uint32_t pool_time=0, malloc_time=0, pool_time2=0;
- pj_timestamp start, end;
- pj_uint32_t best, worst;
-
- // Initialize sizes.
- for (i=0; i<COUNT; ++i) {
- sizes[i] = MIN_SIZE + pj_rand() % MAX_SIZE;
- total_size += sizes[i];
- }
-
- PJ_LOG(3, (THIS_FILE, "Benchmarking pool.."));
-
- // Warmup
- pool_test_pool();
- pool_test_malloc_free();
-
- for (i=0; i<LOOP; ++i) {
- pj_get_timestamp(&start);
- if (pool_test_pool()) {
- return 1;
- }
- pj_get_timestamp(&end);
- pool_time += (end.u32.lo - start.u32.lo);
-
- pj_get_timestamp(&start);
- if (pool_test_malloc_free()) {
- return 2;
- }
- pj_get_timestamp(&end);
- malloc_time += (end.u32.lo - start.u32.lo);
-
- pj_get_timestamp(&start);
- if (pool_test_pool()) {
- return 4;
- }
- pj_get_timestamp(&end);
- pool_time2 += (end.u32.lo - start.u32.lo);
- }
-
- PJ_LOG(4, (THIS_FILE, "..LOOP count: %u", LOOP));
- PJ_LOG(4, (THIS_FILE, "..number of alloc/dealloc per loop: %u", COUNT));
- PJ_LOG(4, (THIS_FILE, "..pool allocation/deallocation time: %u", pool_time));
- PJ_LOG(4, (THIS_FILE, "..malloc/free time: %u", malloc_time));
- PJ_LOG(4, (THIS_FILE, "..pool again, second invocation: %u", pool_time2));
-
- if (pool_time2==0) pool_time2=1;
- if (pool_time < pool_time2)
- best = pool_time, worst = pool_time2;
- else
- best = pool_time2, worst = pool_time;
-
- PJ_LOG(3, (THIS_FILE, "..malloc Speedup best=%dx, worst=%dx",
- (int)(malloc_time/best),
- (int)(malloc_time/worst)));
- return 0;
-}
-
-
-#endif /* INCLUDE_POOL_PERF_TEST */
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "test.h"
+
+#if INCLUDE_POOL_PERF_TEST
+
+#include <pjlib.h>
+#include <pj/compat/malloc.h>
+
+#if !PJ_HAS_HIGH_RES_TIMER
+# error Need high resolution timer for this test.
+#endif
+
+#define THIS_FILE "test"
+
+#define LOOP 10
+#define COUNT 1024
+static unsigned sizes[COUNT];
+#define MIN_SIZE 4
+#define MAX_SIZE 512
+static unsigned total_size;
+
+static int pool_test_pool()
+{
+ int i;
+ pj_pool_t *pool = pj_pool_create(mem, NULL, total_size + 4*COUNT, 0, NULL);
+ if (!pool)
+ return -1;
+
+ for (i=0; i<COUNT; ++i) {
+ char *p;
+ if ( (p=(char*)pj_pool_alloc(pool, sizes[i])) == NULL)
+ return -1;
+ *p = '\0';
+ }
+
+ pj_pool_release(pool);
+ return 0;
+}
+
+static int pool_test_malloc_free()
+{
+ char *p[COUNT];
+ int i;
+
+ for (i=0; i<COUNT; ++i) {
+ p[i] = (char*)malloc(sizes[i]);
+ if (!p[i]) {
+ // Don't care for memory leak in this test
+ return -1;
+ }
+ *p[i] = '\0';
+ }
+
+ for (i=0; i<COUNT; ++i) {
+ free(p[i]);
+ }
+
+ return 0;
+}
+
+int pool_perf_test()
+{
+ unsigned i;
+ pj_uint32_t pool_time=0, malloc_time=0, pool_time2=0;
+ pj_timestamp start, end;
+ pj_uint32_t best, worst;
+
+ // Initialize sizes.
+ for (i=0; i<COUNT; ++i) {
+ sizes[i] = MIN_SIZE + pj_rand() % MAX_SIZE;
+ total_size += sizes[i];
+ }
+
+ PJ_LOG(3, (THIS_FILE, "Benchmarking pool.."));
+
+ // Warmup
+ pool_test_pool();
+ pool_test_malloc_free();
+
+ for (i=0; i<LOOP; ++i) {
+ pj_get_timestamp(&start);
+ if (pool_test_pool()) {
+ return 1;
+ }
+ pj_get_timestamp(&end);
+ pool_time += (end.u32.lo - start.u32.lo);
+
+ pj_get_timestamp(&start);
+ if (pool_test_malloc_free()) {
+ return 2;
+ }
+ pj_get_timestamp(&end);
+ malloc_time += (end.u32.lo - start.u32.lo);
+
+ pj_get_timestamp(&start);
+ if (pool_test_pool()) {
+ return 4;
+ }
+ pj_get_timestamp(&end);
+ pool_time2 += (end.u32.lo - start.u32.lo);
+ }
+
+ PJ_LOG(4, (THIS_FILE, "..LOOP count: %u", LOOP));
+ PJ_LOG(4, (THIS_FILE, "..number of alloc/dealloc per loop: %u", COUNT));
+ PJ_LOG(4, (THIS_FILE, "..pool allocation/deallocation time: %u", pool_time));
+ PJ_LOG(4, (THIS_FILE, "..malloc/free time: %u", malloc_time));
+ PJ_LOG(4, (THIS_FILE, "..pool again, second invocation: %u", pool_time2));
+
+ if (pool_time2==0) pool_time2=1;
+ if (pool_time < pool_time2)
+ best = pool_time, worst = pool_time2;
+ else
+ best = pool_time2, worst = pool_time;
+
+ PJ_LOG(3, (THIS_FILE, "..malloc Speedup best=%dx, worst=%dx",
+ (int)(malloc_time/best),
+ (int)(malloc_time/worst)));
+ return 0;
+}
+
+
+#endif /* INCLUDE_POOL_PERF_TEST */
+
diff --git a/pjlib/src/pjlib-test/rand.c b/pjlib/src/pjlib-test/rand.c
index 55efa86b..d39089d0 100644
--- a/pjlib/src/pjlib-test/rand.c
+++ b/pjlib/src/pjlib-test/rand.c
@@ -1,37 +1,58 @@
-/* $Id$
- */
-#include <pj/rand.h>
-#include <pj/log.h>
-#include "test.h"
-
-#if INCLUDE_RAND_TEST
-
-#define COUNT 1024
-static int values[COUNT];
-
-/*
- * rand_test(), simply generates COUNT number of random number and
- * check that there's no duplicate numbers.
- */
-int rand_test(void)
-{
- int i;
-
- for (i=0; i<COUNT; ++i) {
- int j;
-
- values[i] = pj_rand();
- for (j=0; j<i; ++j) {
- if (values[i] == values[j]) {
- PJ_LOG(3,("test", "error: duplicate value %d at %d-th index",
- values[i], i));
- return -10;
- }
- }
- }
-
- return 0;
-}
-
-#endif /* INCLUDE_RAND_TEST */
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/rand.h>
+#include <pj/log.h>
+#include "test.h"
+
+#if INCLUDE_RAND_TEST
+
+#define COUNT 1024
+static int values[COUNT];
+
+/*
+ * rand_test(), simply generates COUNT number of random number and
+ * check that there's no duplicate numbers.
+ */
+int rand_test(void)
+{
+ int i;
+
+ for (i=0; i<COUNT; ++i) {
+ int j;
+
+ values[i] = pj_rand();
+ for (j=0; j<i; ++j) {
+ if (values[i] == values[j]) {
+ PJ_LOG(3,("test", "error: duplicate value %d at %d-th index",
+ values[i], i));
+ return -10;
+ }
+ }
+ }
+
+ return 0;
+}
+
+#endif /* INCLUDE_RAND_TEST */
+
diff --git a/pjlib/src/pjlib-test/rbtree.c b/pjlib/src/pjlib-test/rbtree.c
index 475ce0c1..c7324ca0 100644
--- a/pjlib/src/pjlib-test/rbtree.c
+++ b/pjlib/src/pjlib-test/rbtree.c
@@ -1,151 +1,172 @@
-/* $Id$
- */
-#include "test.h"
-
-#if INCLUDE_RBTREE_TEST
-
-#include <pjlib.h>
-
-#define LOOP 32
-#define MIN_COUNT 64
-#define MAX_COUNT (LOOP * MIN_COUNT)
-#define STRSIZE 16
-#define THIS_FILE "rbtree_test"
-
-typedef struct node_key
-{
- pj_uint32_t hash;
- char str[STRSIZE];
-} node_key;
-
-static int compare_node(const node_key *k1, const node_key *k2)
-{
- if (k1->hash == k2->hash) {
- return strcmp(k1->str, k2->str);
- } else {
- return k1->hash < k2->hash ? -1 : 1;
- }
-}
-
-void randomize_string(char *str, int len)
-{
- int i;
- for (i=0; i<len-1; ++i)
- str[i] = (char)('a' + pj_rand() % 26);
- str[len-1] = '\0';
-}
-
-static int test(void)
-{
- pj_rbtree rb;
- node_key *key;
- pj_rbtree_node *node;
- pj_pool_t *pool;
- int err=0;
- int count = MIN_COUNT;
- int i;
- unsigned size;
-
- pj_rbtree_init(&rb, (pj_rbtree_comp*)&compare_node);
- size = MAX_COUNT*(sizeof(*key)+PJ_RBTREE_NODE_SIZE) +
- PJ_RBTREE_SIZE + PJ_POOL_SIZE;
- pool = pj_pool_create( mem, "pool", size, 0, NULL);
- if (!pool) {
- PJ_LOG(3,("test", "...error: creating pool of %u bytes", size));
- return -10;
- }
-
- key = (node_key *)pj_pool_alloc(pool, MAX_COUNT*sizeof(*key));
- if (!key)
- return -20;
-
- node = (pj_rbtree_node*)pj_pool_alloc(pool, MAX_COUNT*sizeof(*node));
- if (!node)
- return -30;
-
- for (i=0; i<LOOP; ++i) {
- int j;
- pj_rbtree_node *prev, *it;
- pj_timestamp t1, t2, t_setup, t_insert, t_search, t_erase;
-
- pj_assert(rb.size == 0);
-
- t_setup.u32.lo = t_insert.u32.lo = t_search.u32.lo = t_erase.u32.lo = 0;
-
- for (j=0; j<count; j++) {
- randomize_string(key[j].str, STRSIZE);
-
- pj_get_timestamp(&t1);
- node[j].key = &key[j];
- node[j].user_data = key[j].str;
- key[j].hash = pj_hash_calc(0, key[j].str, PJ_HASH_KEY_STRING);
- pj_get_timestamp(&t2);
- t_setup.u32.lo += (t2.u32.lo - t1.u32.lo);
-
- pj_get_timestamp(&t1);
- pj_rbtree_insert(&rb, &node[j]);
- pj_get_timestamp(&t2);
- t_insert.u32.lo += (t2.u32.lo - t1.u32.lo);
- }
-
- pj_assert(rb.size == (unsigned)count);
-
- // Iterate key, make sure they're sorted.
- prev = NULL;
- it = pj_rbtree_first(&rb);
- while (it) {
- if (prev) {
- if (compare_node((node_key*)prev->key,(node_key*)it->key)>=0) {
- ++err;
- PJ_LOG(3, (THIS_FILE, "Error: %s >= %s",
- (char*)prev->user_data, (char*)it->user_data));
- }
- }
- prev = it;
- it = pj_rbtree_next(&rb, it);
- }
-
- // Search.
- for (j=0; j<count; j++) {
- pj_get_timestamp(&t1);
- it = pj_rbtree_find(&rb, &key[j]);
- pj_get_timestamp(&t2);
- t_search.u32.lo += (t2.u32.lo - t1.u32.lo);
-
- pj_assert(it != NULL);
- if (it == NULL)
- ++err;
- }
-
- // Erase node.
- for (j=0; j<count; j++) {
- pj_get_timestamp(&t1);
- it = pj_rbtree_erase(&rb, &node[j]);
- pj_get_timestamp(&t2);
- t_erase.u32.lo += (t2.u32.lo - t1.u32.lo);
- }
-
- PJ_LOG(4, (THIS_FILE,
- "...count:%d, setup:%d, insert:%d, search:%d, erase:%d",
- count,
- t_setup.u32.lo / count, t_insert.u32.lo / count,
- t_search.u32.lo / count, t_erase.u32.lo / count));
-
- count = 2 * count;
- if (count > MAX_COUNT)
- break;
- }
-
- pj_pool_release(pool);
- return err;
-}
-
-
-int rbtree_test()
-{
- return test();
-}
-
-#endif /* INCLUDE_RBTREE_TEST */
-
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "test.h"
+
+#if INCLUDE_RBTREE_TEST
+
+#include <pjlib.h>
+
+#define LOOP 32
+#define MIN_COUNT 64
+#define MAX_COUNT (LOOP * MIN_COUNT)
+#define STRSIZE 16
+#define THIS_FILE "rbtree_test"
+
+typedef struct node_key
+{
+ pj_uint32_t hash;
+ char str[STRSIZE];
+} node_key;
+
+static int compare_node(const node_key *k1, const node_key *k2)
+{
+ if (k1->hash == k2->hash) {
+ return strcmp(k1->str, k2->str);
+ } else {
+ return k1->hash < k2->hash ? -1 : 1;
+ }
+}
+
+void randomize_string(char *str, int len)
+{
+ int i;
+ for (i=0; i<len-1; ++i)
+ str[i] = (char)('a' + pj_rand() % 26);
+ str[len-1] = '\0';
+}
+
+static int test(void)
+{
+ pj_rbtree rb;
+ node_key *key;
+ pj_rbtree_node *node;
+ pj_pool_t *pool;
+ int err=0;
+ int count = MIN_COUNT;
+ int i;
+ unsigned size;
+
+ pj_rbtree_init(&rb, (pj_rbtree_comp*)&compare_node);
+ size = MAX_COUNT*(sizeof(*key)+PJ_RBTREE_NODE_SIZE) +
+ PJ_RBTREE_SIZE + PJ_POOL_SIZE;
+ pool = pj_pool_create( mem, "pool", size, 0, NULL);
+ if (!pool) {
+ PJ_LOG(3,("test", "...error: creating pool of %u bytes", size));
+ return -10;
+ }
+
+ key = (node_key *)pj_pool_alloc(pool, MAX_COUNT*sizeof(*key));
+ if (!key)
+ return -20;
+
+ node = (pj_rbtree_node*)pj_pool_alloc(pool, MAX_COUNT*sizeof(*node));
+ if (!node)
+ return -30;
+
+ for (i=0; i<LOOP; ++i) {
+ int j;
+ pj_rbtree_node *prev, *it;
+ pj_timestamp t1, t2, t_setup, t_insert, t_search, t_erase;
+
+ pj_assert(rb.size == 0);
+
+ t_setup.u32.lo = t_insert.u32.lo = t_search.u32.lo = t_erase.u32.lo = 0;
+
+ for (j=0; j<count; j++) {
+ randomize_string(key[j].str, STRSIZE);
+
+ pj_get_timestamp(&t1);
+ node[j].key = &key[j];
+ node[j].user_data = key[j].str;
+ key[j].hash = pj_hash_calc(0, key[j].str, PJ_HASH_KEY_STRING);
+ pj_get_timestamp(&t2);
+ t_setup.u32.lo += (t2.u32.lo - t1.u32.lo);
+
+ pj_get_timestamp(&t1);
+ pj_rbtree_insert(&rb, &node[j]);
+ pj_get_timestamp(&t2);
+ t_insert.u32.lo += (t2.u32.lo - t1.u32.lo);
+ }
+
+ pj_assert(rb.size == (unsigned)count);
+
+ // Iterate key, make sure they're sorted.
+ prev = NULL;
+ it = pj_rbtree_first(&rb);
+ while (it) {
+ if (prev) {
+ if (compare_node((node_key*)prev->key,(node_key*)it->key)>=0) {
+ ++err;
+ PJ_LOG(3, (THIS_FILE, "Error: %s >= %s",
+ (char*)prev->user_data, (char*)it->user_data));
+ }
+ }
+ prev = it;
+ it = pj_rbtree_next(&rb, it);
+ }
+
+ // Search.
+ for (j=0; j<count; j++) {
+ pj_get_timestamp(&t1);
+ it = pj_rbtree_find(&rb, &key[j]);
+ pj_get_timestamp(&t2);
+ t_search.u32.lo += (t2.u32.lo - t1.u32.lo);
+
+ pj_assert(it != NULL);
+ if (it == NULL)
+ ++err;
+ }
+
+ // Erase node.
+ for (j=0; j<count; j++) {
+ pj_get_timestamp(&t1);
+ it = pj_rbtree_erase(&rb, &node[j]);
+ pj_get_timestamp(&t2);
+ t_erase.u32.lo += (t2.u32.lo - t1.u32.lo);
+ }
+
+ PJ_LOG(4, (THIS_FILE,
+ "...count:%d, setup:%d, insert:%d, search:%d, erase:%d",
+ count,
+ t_setup.u32.lo / count, t_insert.u32.lo / count,
+ t_search.u32.lo / count, t_erase.u32.lo / count));
+
+ count = 2 * count;
+ if (count > MAX_COUNT)
+ break;
+ }
+
+ pj_pool_release(pool);
+ return err;
+}
+
+
+int rbtree_test()
+{
+ return test();
+}
+
+#endif /* INCLUDE_RBTREE_TEST */
+
+
diff --git a/pjlib/src/pjlib-test/select.c b/pjlib/src/pjlib-test/select.c
index 4d1fe1b9..6ebc76a8 100644
--- a/pjlib/src/pjlib-test/select.c
+++ b/pjlib/src/pjlib-test/select.c
@@ -1,201 +1,222 @@
-/* $Id$
- */
-#include "test.h"
-
-/**
- * \page page_pjlib_select_test Test: Socket Select()
- *
- * This file provides implementation of \b select_test(). It tests the
- * functionality of the pj_sock_select() API.
- *
- *
- * This file is <b>pjlib-test/select.c</b>
- *
- * \include pjlib-test/select.c
- */
-
-
-#if INCLUDE_SELECT_TEST
-
-#include <pj/sock.h>
-#include <pj/sock_select.h>
-#include <pj/log.h>
-#include <pj/string.h>
-#include <pj/assert.h>
-#include <pj/os.h>
-#include <pj/errno.h>
-
-enum
-{
- READ_FDS,
- WRITE_FDS,
- EXCEPT_FDS
-};
-
-#define UDP_PORT 51232
-#define THIS_FILE "select_test"
-
-/*
- * do_select()
- *
- * Perform pj_sock_select() and find out which sockets
- * are signalled.
- */
-static int do_select( pj_sock_t sock1, pj_sock_t sock2,
- int setcount[])
-{
- pj_fd_set_t fds[3];
- pj_time_val timeout;
- int i, n;
-
- for (i=0; i<3; ++i) {
- PJ_FD_ZERO(&fds[i]);
- PJ_FD_SET(sock1, &fds[i]);
- PJ_FD_SET(sock2, &fds[i]);
- setcount[i] = 0;
- }
-
- timeout.sec = 1;
- timeout.msec = 0;
-
- n = pj_sock_select(FD_SETSIZE, &fds[0], &fds[1], &fds[2],
- &timeout);
- if (n < 0)
- return n;
- if (n == 0)
- return 0;
-
- for (i=0; i<3; ++i) {
- if (PJ_FD_ISSET(sock1, &fds[i]))
- setcount[i]++;
- if (PJ_FD_ISSET(sock2, &fds[i]))
- setcount[i]++;
- }
-
- return n;
-}
-
-/*
- * select_test()
- *
- * Test main entry.
- */
-int select_test()
-{
- pj_sock_t udp1=PJ_INVALID_SOCKET, udp2=PJ_INVALID_SOCKET;
- pj_sockaddr_in udp_addr;
- int status;
- int setcount[3];
- pj_str_t s;
- const char data[] = "hello";
- const int datalen = 5;
- pj_ssize_t sent, received;
- char buf[10];
- pj_status_t rc;
-
- PJ_LOG(3, (THIS_FILE, "...Testing simple UDP select()"));
-
- // Create two UDP sockets.
- rc = pj_sock_socket( PJ_AF_INET, PJ_SOCK_DGRAM, 0, &udp1);
- if (rc != PJ_SUCCESS) {
- app_perror("...error: unable to create socket", rc);
- status=-10; goto on_return;
- }
- rc = pj_sock_socket( PJ_AF_INET, PJ_SOCK_DGRAM, 0, &udp2);
- if (udp2 == PJ_INVALID_SOCKET) {
- app_perror("...error: unable to create socket", rc);
- status=-20; goto on_return;
- }
-
- // Bind one of the UDP socket.
- pj_memset(&udp_addr, 0, sizeof(udp_addr));
- udp_addr.sin_family = PJ_AF_INET;
- udp_addr.sin_port = UDP_PORT;
- udp_addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));
-
- if (pj_sock_bind(udp2, &udp_addr, sizeof(udp_addr))) {
- status=-30; goto on_return;
- }
-
- // Send data.
- sent = datalen;
- rc = pj_sock_sendto(udp1, data, &sent, 0, &udp_addr, sizeof(udp_addr));
- if (rc != PJ_SUCCESS || sent != datalen) {
- app_perror("...error: sendto() error", rc);
- status=-40; goto on_return;
- }
-
- // Check that socket is marked as reable.
- // Note that select() may also report that sockets are writable.
- status = do_select(udp1, udp2, setcount);
- if (status < 0) {
- char errbuf[128];
- pj_strerror(pj_get_netos_error(), errbuf, sizeof(errbuf));
- PJ_LOG(1,(THIS_FILE, "...error: %s", errbuf));
- status=-50; goto on_return;
- }
- if (status == 0) {
- status=-60; goto on_return;
- }
-
- if (setcount[READ_FDS] != 1) {
- status=-70; goto on_return;
- }
- if (setcount[WRITE_FDS] != 0) {
- if (setcount[WRITE_FDS] == 2) {
- PJ_LOG(3,(THIS_FILE, "...info: system reports writable sockets"));
- } else {
- status=-80; goto on_return;
- }
- } else {
- PJ_LOG(3,(THIS_FILE,
- "...info: system doesn't report writable sockets"));
- }
- if (setcount[EXCEPT_FDS] != 0) {
- status=-90; goto on_return;
- }
-
- // Read the socket to clear readable sockets.
- received = sizeof(buf);
- rc = pj_sock_recv(udp2, buf, &received, 0);
- if (rc != PJ_SUCCESS || received != 5) {
- status=-100; goto on_return;
- }
-
- status = 0;
-
- // Test timeout on the read part.
- // This won't necessarily return zero, as select() may report that
- // sockets are writable.
- setcount[0] = setcount[1] = setcount[2] = 0;
- status = do_select(udp1, udp2, setcount);
- if (status != 0 && status != setcount[WRITE_FDS]) {
- PJ_LOG(3,(THIS_FILE, "...error: expecting timeout but got %d sks set",
- status));
- PJ_LOG(3,(THIS_FILE, " rdset: %d, wrset: %d, exset: %d",
- setcount[0], setcount[1], setcount[2]));
- status = -110; goto on_return;
- }
- if (setcount[READ_FDS] != 0) {
- PJ_LOG(3,(THIS_FILE, "...error: readable socket not expected"));
- status = -120; goto on_return;
- }
-
- status = 0;
-
-on_return:
- if (udp1 != PJ_INVALID_SOCKET)
- pj_sock_close(udp1);
- if (udp2 != PJ_INVALID_SOCKET)
- pj_sock_close(udp2);
- return status;
-}
-
-#else
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled.
- */
-int dummy_select_test;
-#endif /* INCLUDE_SELECT_TEST */
-
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "test.h"
+
+/**
+ * \page page_pjlib_select_test Test: Socket Select()
+ *
+ * This file provides implementation of \b select_test(). It tests the
+ * functionality of the pj_sock_select() API.
+ *
+ *
+ * This file is <b>pjlib-test/select.c</b>
+ *
+ * \include pjlib-test/select.c
+ */
+
+
+#if INCLUDE_SELECT_TEST
+
+#include <pj/sock.h>
+#include <pj/sock_select.h>
+#include <pj/log.h>
+#include <pj/string.h>
+#include <pj/assert.h>
+#include <pj/os.h>
+#include <pj/errno.h>
+
+enum
+{
+ READ_FDS,
+ WRITE_FDS,
+ EXCEPT_FDS
+};
+
+#define UDP_PORT 51232
+#define THIS_FILE "select_test"
+
+/*
+ * do_select()
+ *
+ * Perform pj_sock_select() and find out which sockets
+ * are signalled.
+ */
+static int do_select( pj_sock_t sock1, pj_sock_t sock2,
+ int setcount[])
+{
+ pj_fd_set_t fds[3];
+ pj_time_val timeout;
+ int i, n;
+
+ for (i=0; i<3; ++i) {
+ PJ_FD_ZERO(&fds[i]);
+ PJ_FD_SET(sock1, &fds[i]);
+ PJ_FD_SET(sock2, &fds[i]);
+ setcount[i] = 0;
+ }
+
+ timeout.sec = 1;
+ timeout.msec = 0;
+
+ n = pj_sock_select(FD_SETSIZE, &fds[0], &fds[1], &fds[2],
+ &timeout);
+ if (n < 0)
+ return n;
+ if (n == 0)
+ return 0;
+
+ for (i=0; i<3; ++i) {
+ if (PJ_FD_ISSET(sock1, &fds[i]))
+ setcount[i]++;
+ if (PJ_FD_ISSET(sock2, &fds[i]))
+ setcount[i]++;
+ }
+
+ return n;
+}
+
+/*
+ * select_test()
+ *
+ * Test main entry.
+ */
+int select_test()
+{
+ pj_sock_t udp1=PJ_INVALID_SOCKET, udp2=PJ_INVALID_SOCKET;
+ pj_sockaddr_in udp_addr;
+ int status;
+ int setcount[3];
+ pj_str_t s;
+ const char data[] = "hello";
+ const int datalen = 5;
+ pj_ssize_t sent, received;
+ char buf[10];
+ pj_status_t rc;
+
+ PJ_LOG(3, (THIS_FILE, "...Testing simple UDP select()"));
+
+ // Create two UDP sockets.
+ rc = pj_sock_socket( PJ_AF_INET, PJ_SOCK_DGRAM, 0, &udp1);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error: unable to create socket", rc);
+ status=-10; goto on_return;
+ }
+ rc = pj_sock_socket( PJ_AF_INET, PJ_SOCK_DGRAM, 0, &udp2);
+ if (udp2 == PJ_INVALID_SOCKET) {
+ app_perror("...error: unable to create socket", rc);
+ status=-20; goto on_return;
+ }
+
+ // Bind one of the UDP socket.
+ pj_memset(&udp_addr, 0, sizeof(udp_addr));
+ udp_addr.sin_family = PJ_AF_INET;
+ udp_addr.sin_port = UDP_PORT;
+ udp_addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));
+
+ if (pj_sock_bind(udp2, &udp_addr, sizeof(udp_addr))) {
+ status=-30; goto on_return;
+ }
+
+ // Send data.
+ sent = datalen;
+ rc = pj_sock_sendto(udp1, data, &sent, 0, &udp_addr, sizeof(udp_addr));
+ if (rc != PJ_SUCCESS || sent != datalen) {
+ app_perror("...error: sendto() error", rc);
+ status=-40; goto on_return;
+ }
+
+ // Check that socket is marked as reable.
+ // Note that select() may also report that sockets are writable.
+ status = do_select(udp1, udp2, setcount);
+ if (status < 0) {
+ char errbuf[128];
+ pj_strerror(pj_get_netos_error(), errbuf, sizeof(errbuf));
+ PJ_LOG(1,(THIS_FILE, "...error: %s", errbuf));
+ status=-50; goto on_return;
+ }
+ if (status == 0) {
+ status=-60; goto on_return;
+ }
+
+ if (setcount[READ_FDS] != 1) {
+ status=-70; goto on_return;
+ }
+ if (setcount[WRITE_FDS] != 0) {
+ if (setcount[WRITE_FDS] == 2) {
+ PJ_LOG(3,(THIS_FILE, "...info: system reports writable sockets"));
+ } else {
+ status=-80; goto on_return;
+ }
+ } else {
+ PJ_LOG(3,(THIS_FILE,
+ "...info: system doesn't report writable sockets"));
+ }
+ if (setcount[EXCEPT_FDS] != 0) {
+ status=-90; goto on_return;
+ }
+
+ // Read the socket to clear readable sockets.
+ received = sizeof(buf);
+ rc = pj_sock_recv(udp2, buf, &received, 0);
+ if (rc != PJ_SUCCESS || received != 5) {
+ status=-100; goto on_return;
+ }
+
+ status = 0;
+
+ // Test timeout on the read part.
+ // This won't necessarily return zero, as select() may report that
+ // sockets are writable.
+ setcount[0] = setcount[1] = setcount[2] = 0;
+ status = do_select(udp1, udp2, setcount);
+ if (status != 0 && status != setcount[WRITE_FDS]) {
+ PJ_LOG(3,(THIS_FILE, "...error: expecting timeout but got %d sks set",
+ status));
+ PJ_LOG(3,(THIS_FILE, " rdset: %d, wrset: %d, exset: %d",
+ setcount[0], setcount[1], setcount[2]));
+ status = -110; goto on_return;
+ }
+ if (setcount[READ_FDS] != 0) {
+ PJ_LOG(3,(THIS_FILE, "...error: readable socket not expected"));
+ status = -120; goto on_return;
+ }
+
+ status = 0;
+
+on_return:
+ if (udp1 != PJ_INVALID_SOCKET)
+ pj_sock_close(udp1);
+ if (udp2 != PJ_INVALID_SOCKET)
+ pj_sock_close(udp2);
+ return status;
+}
+
+#else
+/* To prevent warning about "translation unit is empty"
+ * when this test is disabled.
+ */
+int dummy_select_test;
+#endif /* INCLUDE_SELECT_TEST */
+
+
diff --git a/pjlib/src/pjlib-test/sleep.c b/pjlib/src/pjlib-test/sleep.c
index 6281e4df..07b56962 100644
--- a/pjlib/src/pjlib-test/sleep.c
+++ b/pjlib/src/pjlib-test/sleep.c
@@ -1,184 +1,205 @@
-/* $Id$
- */
-#include "test.h"
-
-/**
- * \page page_pjlib_sleep_test Test: Sleep, Time, and Timestamp
- *
- * This file provides implementation of \b sleep_test().
- *
- * \section sleep_test_sec Scope of the Test
- *
- * This tests:
- * - whether pj_thread_sleep() works.
- * - whether pj_gettimeofday() works.
- * - whether pj_get_timestamp() and friends works.
- *
- * API tested:
- * - pj_thread_sleep()
- * - pj_gettimeofday()
- * - PJ_TIME_VAL_SUB()
- * - PJ_TIME_VAL_LTE()
- * - pj_get_timestamp()
- * - pj_get_timestamp_freq() (implicitly)
- * - pj_elapsed_time()
- * - pj_elapsed_usec()
- *
- *
- * This file is <b>pjlib-test/sleep.c</b>
- *
- * \include pjlib-test/sleep.c
- */
-
-#if INCLUDE_SLEEP_TEST
-
-#include <pjlib.h>
-
-#define THIS_FILE "sleep_test"
-
-static int simple_sleep_test(void)
-{
- enum { COUNT = 5 };
- int i;
- pj_status_t rc;
-
- PJ_LOG(3,(THIS_FILE, "..will write messages every 1 second:"));
-
- for (i=0; i<COUNT; ++i) {
- rc = pj_thread_sleep(1000);
- if (rc != PJ_SUCCESS) {
- app_perror("...error: pj_thread_sleep()", rc);
- return -10;
- }
- PJ_LOG(3,(THIS_FILE, "...wake up.."));
- }
-
- return 0;
-}
-
-static int sleep_duration_test(void)
-{
- enum { MIS = 20, DURATION = 1000, DURATION2 = 500 };
- pj_status_t rc;
-
- PJ_LOG(3,(THIS_FILE, "..running sleep duration test"));
-
- /* Test pj_thread_sleep() and pj_gettimeofday() */
- {
- pj_time_val start, stop;
- pj_uint32_t msec;
-
- /* Mark start of test. */
- rc = pj_gettimeofday(&start);
- if (rc != PJ_SUCCESS) {
- app_perror("...error: pj_gettimeofday()", rc);
- return -10;
- }
-
- /* Sleep */
- rc = pj_thread_sleep(DURATION);
- if (rc != PJ_SUCCESS) {
- app_perror("...error: pj_thread_sleep()", rc);
- return -20;
- }
-
- /* Mark end of test. */
- rc = pj_gettimeofday(&stop);
-
- /* Calculate duration (store in stop). */
- PJ_TIME_VAL_SUB(stop, start);
-
- /* Convert to msec. */
- msec = PJ_TIME_VAL_MSEC(stop);
-
- /* Check if it's within range. */
- if (msec < DURATION * (100-MIS)/100 ||
- msec > DURATION * (100+MIS)/100)
- {
- PJ_LOG(3,(THIS_FILE,
- "...error: slept for %d ms instead of %d ms "
- "(outside %d%% err window)",
- msec, DURATION, MIS));
- return -30;
- }
- }
-
-
- /* Test pj_thread_sleep() and pj_get_timestamp() and friends */
- {
- pj_time_val t1, t2;
- pj_timestamp start, stop;
- pj_time_val elapsed;
- pj_uint32_t msec;
-
- /* Mark start of test. */
- rc = pj_get_timestamp(&start);
- if (rc != PJ_SUCCESS) {
- app_perror("...error: pj_get_timestamp()", rc);
- return -60;
- }
-
- /* ..also with gettimeofday() */
- pj_gettimeofday(&t1);
-
- /* Sleep */
- rc = pj_thread_sleep(DURATION2);
- if (rc != PJ_SUCCESS) {
- app_perror("...error: pj_thread_sleep()", rc);
- return -70;
- }
-
- /* Mark end of test. */
- pj_get_timestamp(&stop);
-
- /* ..also with gettimeofday() */
- pj_gettimeofday(&t2);
-
- /* Compare t1 and t2. */
- if (PJ_TIME_VAL_LTE(t2, t1)) {
- PJ_LOG(3,(THIS_FILE, "...error: t2 is less than t1!!"));
- return -75;
- }
-
- /* Get elapsed time in time_val */
- elapsed = pj_elapsed_time(&start, &stop);
-
- msec = PJ_TIME_VAL_MSEC(elapsed);
-
- /* Check if it's within range. */
- if (msec < DURATION2 * (100-MIS)/100 ||
- msec > DURATION2 * (100+MIS)/100)
- {
- PJ_LOG(3,(THIS_FILE,
- "...error: slept for %d ms instead of %d ms "
- "(outside %d%% err window)",
- msec, DURATION2, MIS));
- return -30;
- }
- }
-
- /* All done. */
- return 0;
-}
-
-int sleep_test()
-{
- int rc;
-
- rc = simple_sleep_test();
- if (rc != PJ_SUCCESS)
- return rc;
-
- rc = sleep_duration_test();
- if (rc != PJ_SUCCESS)
- return rc;
-
- return 0;
-}
-
-#else
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled.
- */
-int dummy_sleep_test;
-#endif /* INCLUDE_SLEEP_TEST */
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "test.h"
+
+/**
+ * \page page_pjlib_sleep_test Test: Sleep, Time, and Timestamp
+ *
+ * This file provides implementation of \b sleep_test().
+ *
+ * \section sleep_test_sec Scope of the Test
+ *
+ * This tests:
+ * - whether pj_thread_sleep() works.
+ * - whether pj_gettimeofday() works.
+ * - whether pj_get_timestamp() and friends works.
+ *
+ * API tested:
+ * - pj_thread_sleep()
+ * - pj_gettimeofday()
+ * - PJ_TIME_VAL_SUB()
+ * - PJ_TIME_VAL_LTE()
+ * - pj_get_timestamp()
+ * - pj_get_timestamp_freq() (implicitly)
+ * - pj_elapsed_time()
+ * - pj_elapsed_usec()
+ *
+ *
+ * This file is <b>pjlib-test/sleep.c</b>
+ *
+ * \include pjlib-test/sleep.c
+ */
+
+#if INCLUDE_SLEEP_TEST
+
+#include <pjlib.h>
+
+#define THIS_FILE "sleep_test"
+
+static int simple_sleep_test(void)
+{
+ enum { COUNT = 5 };
+ int i;
+ pj_status_t rc;
+
+ PJ_LOG(3,(THIS_FILE, "..will write messages every 1 second:"));
+
+ for (i=0; i<COUNT; ++i) {
+ rc = pj_thread_sleep(1000);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error: pj_thread_sleep()", rc);
+ return -10;
+ }
+ PJ_LOG(3,(THIS_FILE, "...wake up.."));
+ }
+
+ return 0;
+}
+
+static int sleep_duration_test(void)
+{
+ enum { MIS = 20, DURATION = 1000, DURATION2 = 500 };
+ pj_status_t rc;
+
+ PJ_LOG(3,(THIS_FILE, "..running sleep duration test"));
+
+ /* Test pj_thread_sleep() and pj_gettimeofday() */
+ {
+ pj_time_val start, stop;
+ pj_uint32_t msec;
+
+ /* Mark start of test. */
+ rc = pj_gettimeofday(&start);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error: pj_gettimeofday()", rc);
+ return -10;
+ }
+
+ /* Sleep */
+ rc = pj_thread_sleep(DURATION);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error: pj_thread_sleep()", rc);
+ return -20;
+ }
+
+ /* Mark end of test. */
+ rc = pj_gettimeofday(&stop);
+
+ /* Calculate duration (store in stop). */
+ PJ_TIME_VAL_SUB(stop, start);
+
+ /* Convert to msec. */
+ msec = PJ_TIME_VAL_MSEC(stop);
+
+ /* Check if it's within range. */
+ if (msec < DURATION * (100-MIS)/100 ||
+ msec > DURATION * (100+MIS)/100)
+ {
+ PJ_LOG(3,(THIS_FILE,
+ "...error: slept for %d ms instead of %d ms "
+ "(outside %d%% err window)",
+ msec, DURATION, MIS));
+ return -30;
+ }
+ }
+
+
+ /* Test pj_thread_sleep() and pj_get_timestamp() and friends */
+ {
+ pj_time_val t1, t2;
+ pj_timestamp start, stop;
+ pj_time_val elapsed;
+ pj_uint32_t msec;
+
+ /* Mark start of test. */
+ rc = pj_get_timestamp(&start);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error: pj_get_timestamp()", rc);
+ return -60;
+ }
+
+ /* ..also with gettimeofday() */
+ pj_gettimeofday(&t1);
+
+ /* Sleep */
+ rc = pj_thread_sleep(DURATION2);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error: pj_thread_sleep()", rc);
+ return -70;
+ }
+
+ /* Mark end of test. */
+ pj_get_timestamp(&stop);
+
+ /* ..also with gettimeofday() */
+ pj_gettimeofday(&t2);
+
+ /* Compare t1 and t2. */
+ if (PJ_TIME_VAL_LTE(t2, t1)) {
+ PJ_LOG(3,(THIS_FILE, "...error: t2 is less than t1!!"));
+ return -75;
+ }
+
+ /* Get elapsed time in time_val */
+ elapsed = pj_elapsed_time(&start, &stop);
+
+ msec = PJ_TIME_VAL_MSEC(elapsed);
+
+ /* Check if it's within range. */
+ if (msec < DURATION2 * (100-MIS)/100 ||
+ msec > DURATION2 * (100+MIS)/100)
+ {
+ PJ_LOG(3,(THIS_FILE,
+ "...error: slept for %d ms instead of %d ms "
+ "(outside %d%% err window)",
+ msec, DURATION2, MIS));
+ return -30;
+ }
+ }
+
+ /* All done. */
+ return 0;
+}
+
+int sleep_test()
+{
+ int rc;
+
+ rc = simple_sleep_test();
+ if (rc != PJ_SUCCESS)
+ return rc;
+
+ rc = sleep_duration_test();
+ if (rc != PJ_SUCCESS)
+ return rc;
+
+ return 0;
+}
+
+#else
+/* To prevent warning about "translation unit is empty"
+ * when this test is disabled.
+ */
+int dummy_sleep_test;
+#endif /* INCLUDE_SLEEP_TEST */
diff --git a/pjlib/src/pjlib-test/sock.c b/pjlib/src/pjlib-test/sock.c
index 56da4bec..3a635b1b 100644
--- a/pjlib/src/pjlib-test/sock.c
+++ b/pjlib/src/pjlib-test/sock.c
@@ -1,440 +1,461 @@
-/* $Id$
- */
-#include <pjlib.h>
-#include "test.h"
-
-
-/**
- * \page page_pjlib_sock_test Test: Socket
- *
- * This file provides implementation of \b sock_test(). It tests the
- * various aspects of the socket API.
- *
- * \section sock_test_scope_sec Scope of the Test
- *
- * The scope of the test:
- * - verify the validity of the address structs.
- * - verify that address manipulation API works.
- * - simple socket creation and destruction.
- * - simple socket send/recv and sendto/recvfrom.
- * - UDP connect()
- * - send/recv big data.
- * - all for both UDP and TCP.
- *
- * The APIs tested in this test:
- * - pj_inet_aton()
- * - pj_inet_ntoa()
- * - pj_gethostname()
- * - pj_sock_socket()
- * - pj_sock_close()
- * - pj_sock_send()
- * - pj_sock_sendto()
- * - pj_sock_recv()
- * - pj_sock_recvfrom()
- * - pj_sock_bind()
- * - pj_sock_connect()
- * - pj_sock_listen()
- * - pj_sock_accept()
- *
- *
- * This file is <b>pjlib-test/sock.c</b>
- *
- * \include pjlib-test/sock.c
- */
-
-#if INCLUDE_SOCK_TEST
-
-#define UDP_PORT 51234
-#define TCP_PORT (UDP_PORT+10)
-#define BIG_DATA_LEN 9000
-
-static char bigdata[BIG_DATA_LEN];
-static char bigbuffer[BIG_DATA_LEN];
-
-static int format_test(void)
-{
- pj_str_t s = pj_str("127.0.0.1");
- char *p;
- pj_in_addr addr;
- const pj_str_t *hostname;
-
- PJ_LOG(3,("test", "...format_test()"));
-
- /* pj_inet_aton() */
- if (pj_inet_aton(&s, &addr) != 1)
- return -10;
-
- /* Check the result. */
- p = (char*)&addr;
- if (p[0]!=127 || p[1]!=0 || p[2]!=0 || p[3]!=1)
- return -15;
-
- /* pj_inet_ntoa() */
- p = pj_inet_ntoa(addr);
- if (!p)
- return -20;
-
- if (pj_strcmp2(&s, p) != 0)
- return -30;
-
- /* pj_gethostname() */
- hostname = pj_gethostname();
- if (!hostname || !hostname->ptr || !hostname->slen)
- return -40;
-
- /* pj_gethostaddr() */
-
- return 0;
-}
-
-static int simple_sock_test(void)
-{
- int types[2];
- pj_sock_t sock;
- int i;
- pj_status_t rc = PJ_SUCCESS;
-
- types[0] = PJ_SOCK_STREAM;
- types[1] = PJ_SOCK_DGRAM;
-
- PJ_LOG(3,("test", "...simple_sock_test()"));
-
- for (i=0; i<sizeof(types)/sizeof(types[0]); ++i) {
-
- rc = pj_sock_socket(PJ_AF_INET, types[i], 0, &sock);
- if (rc != PJ_SUCCESS) {
- app_perror("...error: unable to create socket type %d", rc);
- break;
- } else {
- rc = pj_sock_close(sock);
- if (rc != 0) {
- app_perror("...error: close socket", rc);
- break;
- }
- }
- }
- return rc;
-}
-
-
-static int send_recv_test(int sock_type,
- pj_sock_t ss, pj_sock_t cs,
- pj_sockaddr_in *dstaddr, pj_sockaddr_in *srcaddr,
- int addrlen)
-{
- enum { DATA_LEN = 16 };
- char senddata[DATA_LEN+4], recvdata[DATA_LEN+4];
- pj_ssize_t sent, received, total_received;
- pj_status_t rc;
-
- TRACE_(("test", "....create_random_string()"));
- pj_create_random_string(senddata, DATA_LEN);
- senddata[DATA_LEN-1] = '\0';
-
- /*
- * Test send/recv small data.
- */
- TRACE_(("test", "....sendto()"));
- if (dstaddr) {
- sent = DATA_LEN;
- rc = pj_sock_sendto(cs, senddata, &sent, 0, dstaddr, addrlen);
- if (rc != PJ_SUCCESS || sent != DATA_LEN) {
- app_perror("...sendto error", rc);
- rc = -140; goto on_error;
- }
- } else {
- sent = DATA_LEN;
- rc = pj_sock_send(cs, senddata, &sent, 0);
- if (rc != PJ_SUCCESS || sent != DATA_LEN) {
- app_perror("...send error", rc);
- rc = -145; goto on_error;
- }
- }
-
- TRACE_(("test", "....recv()"));
- if (srcaddr) {
- pj_sockaddr_in addr;
- int srclen = sizeof(addr);
-
- pj_memset(&addr, 0, sizeof(addr));
-
- received = DATA_LEN;
- rc = pj_sock_recvfrom(ss, recvdata, &received, 0, &addr, &srclen);
- if (rc != PJ_SUCCESS || received != DATA_LEN) {
- app_perror("...recvfrom error", rc);
- rc = -150; goto on_error;
- }
- if (srclen != addrlen)
- return -151;
- if (pj_memcmp(&addr, srcaddr, srclen) != 0) {
- char srcaddr_str[32], addr_str[32];
- strcpy(srcaddr_str, pj_inet_ntoa(srcaddr->sin_addr));
- strcpy(addr_str, pj_inet_ntoa(addr.sin_addr));
- PJ_LOG(3,("test", "...error: src address mismatch (original=%s, "
- "recvfrom addr=%s)",
- srcaddr_str, addr_str));
- return -152;
- }
-
- } else {
- /* Repeat recv() until all data is received.
- * This applies only for non-UDP of course, since for UDP
- * we would expect all data to be received in one packet.
- */
- total_received = 0;
- do {
- received = DATA_LEN-total_received;
- rc = pj_sock_recv(ss, recvdata+total_received, &received, 0);
- if (rc != PJ_SUCCESS) {
- app_perror("...recv error", rc);
- rc = -155; goto on_error;
- }
- if (received <= 0) {
- PJ_LOG(3,("", "...error: socket has closed! (received=%d)",
- received));
- rc = -156; goto on_error;
- }
- if (received != DATA_LEN-total_received) {
- if (sock_type != PJ_SOCK_STREAM) {
- PJ_LOG(3,("", "...error: expecting %u bytes, got %u bytes",
- DATA_LEN-total_received, received));
- rc = -157; goto on_error;
- }
- }
- total_received += received;
- } while (total_received < DATA_LEN);
- }
-
- TRACE_(("test", "....memcmp()"));
- if (pj_memcmp(senddata, recvdata, DATA_LEN) != 0) {
- PJ_LOG(3,("","...error: received data mismatch "
- "(got:'%s' expecting:'%s'",
- recvdata, senddata));
- rc = -160; goto on_error;
- }
-
- /*
- * Test send/recv big data.
- */
- TRACE_(("test", "....sendto()"));
- if (dstaddr) {
- sent = BIG_DATA_LEN;
- rc = pj_sock_sendto(cs, bigdata, &sent, 0, dstaddr, addrlen);
- if (rc != PJ_SUCCESS || sent != BIG_DATA_LEN) {
- app_perror("...sendto error", rc);
- rc = -161; goto on_error;
- }
- } else {
- sent = BIG_DATA_LEN;
- rc = pj_sock_send(cs, bigdata, &sent, 0);
- if (rc != PJ_SUCCESS || sent != BIG_DATA_LEN) {
- app_perror("...send error", rc);
- rc = -165; goto on_error;
- }
- }
-
- TRACE_(("test", "....recv()"));
-
- /* Repeat recv() until all data is received.
- * This applies only for non-UDP of course, since for UDP
- * we would expect all data to be received in one packet.
- */
- total_received = 0;
- do {
- received = BIG_DATA_LEN-total_received;
- rc = pj_sock_recv(ss, bigbuffer+total_received, &received, 0);
- if (rc != PJ_SUCCESS) {
- app_perror("...recv error", rc);
- rc = -170; goto on_error;
- }
- if (received <= 0) {
- PJ_LOG(3,("", "...error: socket has closed! (received=%d)",
- received));
- rc = -173; goto on_error;
- }
- if (received != BIG_DATA_LEN-total_received) {
- if (sock_type != PJ_SOCK_STREAM) {
- PJ_LOG(3,("", "...error: expecting %u bytes, got %u bytes",
- BIG_DATA_LEN-total_received, received));
- rc = -176; goto on_error;
- }
- }
- total_received += received;
- } while (total_received < BIG_DATA_LEN);
-
- TRACE_(("test", "....memcmp()"));
- if (pj_memcmp(bigdata, bigbuffer, BIG_DATA_LEN) != 0) {
- PJ_LOG(3,("", "...error: received data has been altered!"));
- rc = -180; goto on_error;
- }
-
- rc = 0;
-
-on_error:
- return rc;
-}
-
-static int udp_test(void)
-{
- pj_sock_t cs = PJ_INVALID_SOCKET, ss = PJ_INVALID_SOCKET;
- pj_sockaddr_in dstaddr, srcaddr;
- pj_str_t s;
- pj_status_t rc = 0, retval;
-
- PJ_LOG(3,("test", "...udp_test()"));
-
- rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &ss);
- if (rc != 0) {
- app_perror("...error: unable to create socket", rc);
- return -100;
- }
-
- rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &cs);
- if (rc != 0)
- return -110;
-
- /* Bind server socket. */
- pj_memset(&dstaddr, 0, sizeof(dstaddr));
- dstaddr.sin_family = PJ_AF_INET;
- dstaddr.sin_port = pj_htons(UDP_PORT);
- dstaddr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));
-
- if ((rc=pj_sock_bind(ss, &dstaddr, sizeof(dstaddr))) != 0) {
- app_perror("...bind error", rc);
- rc = -120; goto on_error;
- }
-
- /* Bind client socket. */
- pj_memset(&srcaddr, 0, sizeof(srcaddr));
- srcaddr.sin_family = PJ_AF_INET;
- srcaddr.sin_port = pj_htons(UDP_PORT-1);
- srcaddr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));
-
- if ((rc=pj_sock_bind(cs, &srcaddr, sizeof(srcaddr))) != 0) {
- app_perror("...bind error", rc);
- rc = -121; goto on_error;
- }
-
- /* Test send/recv, with sendto */
- rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, &dstaddr, NULL,
- sizeof(dstaddr));
- if (rc != 0)
- goto on_error;
-
- /* Test send/recv, with sendto and recvfrom */
- rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, &dstaddr,
- &srcaddr, sizeof(dstaddr));
- if (rc != 0)
- goto on_error;
-
- /* connect() the sockets. */
- rc = pj_sock_connect(cs, &dstaddr, sizeof(dstaddr));
- if (rc != 0) {
- app_perror("...connect() error", rc);
- rc = -122; goto on_error;
- }
-
- /* Test send/recv with send() */
- rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, NULL, NULL, 0);
- if (rc != 0)
- goto on_error;
-
- /* Test send/recv with send() and recvfrom */
- rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, NULL, &srcaddr,
- sizeof(srcaddr));
- if (rc != 0)
- goto on_error;
-
-on_error:
- retval = rc;
- if (cs != PJ_INVALID_SOCKET) {
- rc = pj_sock_close(cs);
- if (rc != PJ_SUCCESS) {
- app_perror("...error in closing socket", rc);
- return -1000;
- }
- }
- if (ss != PJ_INVALID_SOCKET) {
- rc = pj_sock_close(ss);
- if (rc != PJ_SUCCESS) {
- app_perror("...error in closing socket", rc);
- return -1010;
- }
- }
-
- return retval;
-}
-
-static int tcp_test(void)
-{
- pj_sock_t cs, ss;
- pj_status_t rc = 0, retval;
-
- PJ_LOG(3,("test", "...tcp_test()"));
-
- rc = app_socketpair(PJ_AF_INET, PJ_SOCK_STREAM, 0, &ss, &cs);
- if (rc != PJ_SUCCESS) {
- app_perror("...error: app_socketpair():", rc);
- return -2000;
- }
-
- /* Test send/recv with send() and recv() */
- retval = send_recv_test(PJ_SOCK_STREAM, ss, cs, NULL, NULL, 0);
-
- rc = pj_sock_close(cs);
- if (rc != PJ_SUCCESS) {
- app_perror("...error in closing socket", rc);
- return -2000;
- }
-
- rc = pj_sock_close(ss);
- if (rc != PJ_SUCCESS) {
- app_perror("...error in closing socket", rc);
- return -2010;
- }
-
- return retval;
-}
-
-static int ioctl_test(void)
-{
- return 0;
-}
-
-int sock_test()
-{
- int rc;
-
- pj_create_random_string(bigdata, BIG_DATA_LEN);
-
- rc = format_test();
- if (rc != 0)
- return rc;
-
- rc = simple_sock_test();
- if (rc != 0)
- return rc;
-
- rc = ioctl_test();
- if (rc != 0)
- return rc;
-
- rc = udp_test();
- if (rc != 0)
- return rc;
-
- rc = tcp_test();
- if (rc != 0)
- return rc;
-
- return 0;
-}
-
-
-#else
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled.
- */
-int dummy_sock_test;
-#endif /* INCLUDE_SOCK_TEST */
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pjlib.h>
+#include "test.h"
+
+
+/**
+ * \page page_pjlib_sock_test Test: Socket
+ *
+ * This file provides implementation of \b sock_test(). It tests the
+ * various aspects of the socket API.
+ *
+ * \section sock_test_scope_sec Scope of the Test
+ *
+ * The scope of the test:
+ * - verify the validity of the address structs.
+ * - verify that address manipulation API works.
+ * - simple socket creation and destruction.
+ * - simple socket send/recv and sendto/recvfrom.
+ * - UDP connect()
+ * - send/recv big data.
+ * - all for both UDP and TCP.
+ *
+ * The APIs tested in this test:
+ * - pj_inet_aton()
+ * - pj_inet_ntoa()
+ * - pj_gethostname()
+ * - pj_sock_socket()
+ * - pj_sock_close()
+ * - pj_sock_send()
+ * - pj_sock_sendto()
+ * - pj_sock_recv()
+ * - pj_sock_recvfrom()
+ * - pj_sock_bind()
+ * - pj_sock_connect()
+ * - pj_sock_listen()
+ * - pj_sock_accept()
+ *
+ *
+ * This file is <b>pjlib-test/sock.c</b>
+ *
+ * \include pjlib-test/sock.c
+ */
+
+#if INCLUDE_SOCK_TEST
+
+#define UDP_PORT 51234
+#define TCP_PORT (UDP_PORT+10)
+#define BIG_DATA_LEN 9000
+
+static char bigdata[BIG_DATA_LEN];
+static char bigbuffer[BIG_DATA_LEN];
+
+static int format_test(void)
+{
+ pj_str_t s = pj_str("127.0.0.1");
+ char *p;
+ pj_in_addr addr;
+ const pj_str_t *hostname;
+
+ PJ_LOG(3,("test", "...format_test()"));
+
+ /* pj_inet_aton() */
+ if (pj_inet_aton(&s, &addr) != 1)
+ return -10;
+
+ /* Check the result. */
+ p = (char*)&addr;
+ if (p[0]!=127 || p[1]!=0 || p[2]!=0 || p[3]!=1)
+ return -15;
+
+ /* pj_inet_ntoa() */
+ p = pj_inet_ntoa(addr);
+ if (!p)
+ return -20;
+
+ if (pj_strcmp2(&s, p) != 0)
+ return -30;
+
+ /* pj_gethostname() */
+ hostname = pj_gethostname();
+ if (!hostname || !hostname->ptr || !hostname->slen)
+ return -40;
+
+ /* pj_gethostaddr() */
+
+ return 0;
+}
+
+static int simple_sock_test(void)
+{
+ int types[2];
+ pj_sock_t sock;
+ int i;
+ pj_status_t rc = PJ_SUCCESS;
+
+ types[0] = PJ_SOCK_STREAM;
+ types[1] = PJ_SOCK_DGRAM;
+
+ PJ_LOG(3,("test", "...simple_sock_test()"));
+
+ for (i=0; i<sizeof(types)/sizeof(types[0]); ++i) {
+
+ rc = pj_sock_socket(PJ_AF_INET, types[i], 0, &sock);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error: unable to create socket type %d", rc);
+ break;
+ } else {
+ rc = pj_sock_close(sock);
+ if (rc != 0) {
+ app_perror("...error: close socket", rc);
+ break;
+ }
+ }
+ }
+ return rc;
+}
+
+
+static int send_recv_test(int sock_type,
+ pj_sock_t ss, pj_sock_t cs,
+ pj_sockaddr_in *dstaddr, pj_sockaddr_in *srcaddr,
+ int addrlen)
+{
+ enum { DATA_LEN = 16 };
+ char senddata[DATA_LEN+4], recvdata[DATA_LEN+4];
+ pj_ssize_t sent, received, total_received;
+ pj_status_t rc;
+
+ TRACE_(("test", "....create_random_string()"));
+ pj_create_random_string(senddata, DATA_LEN);
+ senddata[DATA_LEN-1] = '\0';
+
+ /*
+ * Test send/recv small data.
+ */
+ TRACE_(("test", "....sendto()"));
+ if (dstaddr) {
+ sent = DATA_LEN;
+ rc = pj_sock_sendto(cs, senddata, &sent, 0, dstaddr, addrlen);
+ if (rc != PJ_SUCCESS || sent != DATA_LEN) {
+ app_perror("...sendto error", rc);
+ rc = -140; goto on_error;
+ }
+ } else {
+ sent = DATA_LEN;
+ rc = pj_sock_send(cs, senddata, &sent, 0);
+ if (rc != PJ_SUCCESS || sent != DATA_LEN) {
+ app_perror("...send error", rc);
+ rc = -145; goto on_error;
+ }
+ }
+
+ TRACE_(("test", "....recv()"));
+ if (srcaddr) {
+ pj_sockaddr_in addr;
+ int srclen = sizeof(addr);
+
+ pj_memset(&addr, 0, sizeof(addr));
+
+ received = DATA_LEN;
+ rc = pj_sock_recvfrom(ss, recvdata, &received, 0, &addr, &srclen);
+ if (rc != PJ_SUCCESS || received != DATA_LEN) {
+ app_perror("...recvfrom error", rc);
+ rc = -150; goto on_error;
+ }
+ if (srclen != addrlen)
+ return -151;
+ if (pj_memcmp(&addr, srcaddr, srclen) != 0) {
+ char srcaddr_str[32], addr_str[32];
+ strcpy(srcaddr_str, pj_inet_ntoa(srcaddr->sin_addr));
+ strcpy(addr_str, pj_inet_ntoa(addr.sin_addr));
+ PJ_LOG(3,("test", "...error: src address mismatch (original=%s, "
+ "recvfrom addr=%s)",
+ srcaddr_str, addr_str));
+ return -152;
+ }
+
+ } else {
+ /* Repeat recv() until all data is received.
+ * This applies only for non-UDP of course, since for UDP
+ * we would expect all data to be received in one packet.
+ */
+ total_received = 0;
+ do {
+ received = DATA_LEN-total_received;
+ rc = pj_sock_recv(ss, recvdata+total_received, &received, 0);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...recv error", rc);
+ rc = -155; goto on_error;
+ }
+ if (received <= 0) {
+ PJ_LOG(3,("", "...error: socket has closed! (received=%d)",
+ received));
+ rc = -156; goto on_error;
+ }
+ if (received != DATA_LEN-total_received) {
+ if (sock_type != PJ_SOCK_STREAM) {
+ PJ_LOG(3,("", "...error: expecting %u bytes, got %u bytes",
+ DATA_LEN-total_received, received));
+ rc = -157; goto on_error;
+ }
+ }
+ total_received += received;
+ } while (total_received < DATA_LEN);
+ }
+
+ TRACE_(("test", "....memcmp()"));
+ if (pj_memcmp(senddata, recvdata, DATA_LEN) != 0) {
+ PJ_LOG(3,("","...error: received data mismatch "
+ "(got:'%s' expecting:'%s'",
+ recvdata, senddata));
+ rc = -160; goto on_error;
+ }
+
+ /*
+ * Test send/recv big data.
+ */
+ TRACE_(("test", "....sendto()"));
+ if (dstaddr) {
+ sent = BIG_DATA_LEN;
+ rc = pj_sock_sendto(cs, bigdata, &sent, 0, dstaddr, addrlen);
+ if (rc != PJ_SUCCESS || sent != BIG_DATA_LEN) {
+ app_perror("...sendto error", rc);
+ rc = -161; goto on_error;
+ }
+ } else {
+ sent = BIG_DATA_LEN;
+ rc = pj_sock_send(cs, bigdata, &sent, 0);
+ if (rc != PJ_SUCCESS || sent != BIG_DATA_LEN) {
+ app_perror("...send error", rc);
+ rc = -165; goto on_error;
+ }
+ }
+
+ TRACE_(("test", "....recv()"));
+
+ /* Repeat recv() until all data is received.
+ * This applies only for non-UDP of course, since for UDP
+ * we would expect all data to be received in one packet.
+ */
+ total_received = 0;
+ do {
+ received = BIG_DATA_LEN-total_received;
+ rc = pj_sock_recv(ss, bigbuffer+total_received, &received, 0);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...recv error", rc);
+ rc = -170; goto on_error;
+ }
+ if (received <= 0) {
+ PJ_LOG(3,("", "...error: socket has closed! (received=%d)",
+ received));
+ rc = -173; goto on_error;
+ }
+ if (received != BIG_DATA_LEN-total_received) {
+ if (sock_type != PJ_SOCK_STREAM) {
+ PJ_LOG(3,("", "...error: expecting %u bytes, got %u bytes",
+ BIG_DATA_LEN-total_received, received));
+ rc = -176; goto on_error;
+ }
+ }
+ total_received += received;
+ } while (total_received < BIG_DATA_LEN);
+
+ TRACE_(("test", "....memcmp()"));
+ if (pj_memcmp(bigdata, bigbuffer, BIG_DATA_LEN) != 0) {
+ PJ_LOG(3,("", "...error: received data has been altered!"));
+ rc = -180; goto on_error;
+ }
+
+ rc = 0;
+
+on_error:
+ return rc;
+}
+
+static int udp_test(void)
+{
+ pj_sock_t cs = PJ_INVALID_SOCKET, ss = PJ_INVALID_SOCKET;
+ pj_sockaddr_in dstaddr, srcaddr;
+ pj_str_t s;
+ pj_status_t rc = 0, retval;
+
+ PJ_LOG(3,("test", "...udp_test()"));
+
+ rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &ss);
+ if (rc != 0) {
+ app_perror("...error: unable to create socket", rc);
+ return -100;
+ }
+
+ rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &cs);
+ if (rc != 0)
+ return -110;
+
+ /* Bind server socket. */
+ pj_memset(&dstaddr, 0, sizeof(dstaddr));
+ dstaddr.sin_family = PJ_AF_INET;
+ dstaddr.sin_port = pj_htons(UDP_PORT);
+ dstaddr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));
+
+ if ((rc=pj_sock_bind(ss, &dstaddr, sizeof(dstaddr))) != 0) {
+ app_perror("...bind error", rc);
+ rc = -120; goto on_error;
+ }
+
+ /* Bind client socket. */
+ pj_memset(&srcaddr, 0, sizeof(srcaddr));
+ srcaddr.sin_family = PJ_AF_INET;
+ srcaddr.sin_port = pj_htons(UDP_PORT-1);
+ srcaddr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));
+
+ if ((rc=pj_sock_bind(cs, &srcaddr, sizeof(srcaddr))) != 0) {
+ app_perror("...bind error", rc);
+ rc = -121; goto on_error;
+ }
+
+ /* Test send/recv, with sendto */
+ rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, &dstaddr, NULL,
+ sizeof(dstaddr));
+ if (rc != 0)
+ goto on_error;
+
+ /* Test send/recv, with sendto and recvfrom */
+ rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, &dstaddr,
+ &srcaddr, sizeof(dstaddr));
+ if (rc != 0)
+ goto on_error;
+
+ /* connect() the sockets. */
+ rc = pj_sock_connect(cs, &dstaddr, sizeof(dstaddr));
+ if (rc != 0) {
+ app_perror("...connect() error", rc);
+ rc = -122; goto on_error;
+ }
+
+ /* Test send/recv with send() */
+ rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, NULL, NULL, 0);
+ if (rc != 0)
+ goto on_error;
+
+ /* Test send/recv with send() and recvfrom */
+ rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, NULL, &srcaddr,
+ sizeof(srcaddr));
+ if (rc != 0)
+ goto on_error;
+
+on_error:
+ retval = rc;
+ if (cs != PJ_INVALID_SOCKET) {
+ rc = pj_sock_close(cs);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error in closing socket", rc);
+ return -1000;
+ }
+ }
+ if (ss != PJ_INVALID_SOCKET) {
+ rc = pj_sock_close(ss);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error in closing socket", rc);
+ return -1010;
+ }
+ }
+
+ return retval;
+}
+
+static int tcp_test(void)
+{
+ pj_sock_t cs, ss;
+ pj_status_t rc = 0, retval;
+
+ PJ_LOG(3,("test", "...tcp_test()"));
+
+ rc = app_socketpair(PJ_AF_INET, PJ_SOCK_STREAM, 0, &ss, &cs);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error: app_socketpair():", rc);
+ return -2000;
+ }
+
+ /* Test send/recv with send() and recv() */
+ retval = send_recv_test(PJ_SOCK_STREAM, ss, cs, NULL, NULL, 0);
+
+ rc = pj_sock_close(cs);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error in closing socket", rc);
+ return -2000;
+ }
+
+ rc = pj_sock_close(ss);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error in closing socket", rc);
+ return -2010;
+ }
+
+ return retval;
+}
+
+static int ioctl_test(void)
+{
+ return 0;
+}
+
+int sock_test()
+{
+ int rc;
+
+ pj_create_random_string(bigdata, BIG_DATA_LEN);
+
+ rc = format_test();
+ if (rc != 0)
+ return rc;
+
+ rc = simple_sock_test();
+ if (rc != 0)
+ return rc;
+
+ rc = ioctl_test();
+ if (rc != 0)
+ return rc;
+
+ rc = udp_test();
+ if (rc != 0)
+ return rc;
+
+ rc = tcp_test();
+ if (rc != 0)
+ return rc;
+
+ return 0;
+}
+
+
+#else
+/* To prevent warning about "translation unit is empty"
+ * when this test is disabled.
+ */
+int dummy_sock_test;
+#endif /* INCLUDE_SOCK_TEST */
+
diff --git a/pjlib/src/pjlib-test/sock_perf.c b/pjlib/src/pjlib-test/sock_perf.c
index dfc480ce..c19b8ab6 100644
--- a/pjlib/src/pjlib-test/sock_perf.c
+++ b/pjlib/src/pjlib-test/sock_perf.c
@@ -1,167 +1,188 @@
-/* $Id$
- */
-#include "test.h"
-#include <pjlib.h>
-#include <pj/compat/high_precision.h>
-
-
-/**
- * \page page_pjlib_sock_perf_test Test: Socket Performance
- *
- * Test the performance of the socket communication. This will perform
- * simple producer-consumer type of test, where we calculate how long
- * does it take to send certain number of packets from producer to
- * consumer.
- *
- * This file is <b>pjlib-test/sock_perf.c</b>
- *
- * \include pjlib-test/sock_perf.c
- */
-
-#if INCLUDE_SOCK_PERF_TEST
-
-/*
- * sock_producer_consumer()
- *
- * Simple producer-consumer benchmarking. Send loop number of
- * buf_size size packets as fast as possible.
- */
-static int sock_producer_consumer(int sock_type,
- unsigned buf_size,
- unsigned loop,
- unsigned *p_bandwidth)
-{
- pj_sock_t consumer, producer;
- pj_pool_t *pool;
- char *outgoing_buffer, *incoming_buffer;
- pj_timestamp start, stop;
- unsigned i;
- pj_highprec_t elapsed, bandwidth;
- pj_size_t total_received;
- pj_status_t rc;
-
- /* Create pool. */
- pool = pj_pool_create(mem, NULL, 4096, 4096, NULL);
- if (!pool)
- return -10;
-
- /* Create producer-consumer pair. */
- rc = app_socketpair(PJ_AF_INET, sock_type, 0, &consumer, &producer);
- if (rc != PJ_SUCCESS) {
- app_perror("...error: create socket pair", rc);
- return -20;
- }
-
- /* Create buffers. */
- outgoing_buffer = pj_pool_alloc(pool, buf_size);
- incoming_buffer = pj_pool_alloc(pool, buf_size);
-
- /* Start loop. */
- pj_get_timestamp(&start);
- total_received = 0;
- for (i=0; i<loop; ++i) {
- pj_ssize_t sent, part_received, received;
- pj_time_val delay;
-
- sent = buf_size;
- rc = pj_sock_send(producer, outgoing_buffer, &sent, 0);
- if (rc != PJ_SUCCESS || sent != (pj_ssize_t)buf_size) {
- app_perror("...error: send()", rc);
- return -61;
- }
-
- /* Repeat recv() until all data is part_received.
- * This applies only for non-UDP of course, since for UDP
- * we would expect all data to be part_received in one packet.
- */
- received = 0;
- do {
- part_received = buf_size-received;
- rc = pj_sock_recv(consumer, incoming_buffer+received,
- &part_received, 0);
- if (rc != PJ_SUCCESS) {
- app_perror("...recv error", rc);
- return -70;
- }
- if (part_received <= 0) {
- PJ_LOG(3,("", "...error: socket has closed (part_received=%d)!",
- part_received));
- return -73;
- }
- if ((pj_size_t)part_received != buf_size-received) {
- if (sock_type != PJ_SOCK_STREAM) {
- PJ_LOG(3,("", "...error: expecting %u bytes, got %u bytes",
- buf_size-received, part_received));
- return -76;
- }
- }
- received += part_received;
- } while ((pj_size_t)received < buf_size);
-
- total_received += received;
-
- /* Stop test if it's been runnign for more than 10 secs. */
- pj_get_timestamp(&stop);
- delay = pj_elapsed_time(&start, &stop);
- if (delay.sec > 10)
- break;
- }
-
- /* Stop timer. */
- pj_get_timestamp(&stop);
-
- elapsed = pj_elapsed_usec(&start, &stop);
-
- /* bandwidth = total_received * 1000 / elapsed */
- bandwidth = total_received;
- pj_highprec_mul(bandwidth, 1000);
- pj_highprec_div(bandwidth, elapsed);
-
- *p_bandwidth = (pj_uint32_t)bandwidth;
-
- /* Close sockets. */
- pj_sock_close(consumer);
- pj_sock_close(producer);
-
- /* Done */
- pj_pool_release(pool);
-
- return 0;
-}
-
-/*
- * sock_perf_test()
- *
- * Main test entry.
- */
-int sock_perf_test(void)
-{
- enum { LOOP = 64 * 1024 };
- int rc;
- unsigned bandwidth;
-
- PJ_LOG(3,("", "...benchmarking socket "
- "(2 sockets, packet=512, single threaded):"));
-
- /* Benchmarking UDP */
- rc = sock_producer_consumer(PJ_SOCK_DGRAM, 512, LOOP, &bandwidth);
- if (rc != 0) return rc;
- PJ_LOG(3,("", "....bandwidth UDP = %d KB/s", bandwidth));
-
- /* Benchmarking TCP */
- rc = sock_producer_consumer(PJ_SOCK_STREAM, 512, LOOP, &bandwidth);
- if (rc != 0) return rc;
- PJ_LOG(3,("", "....bandwidth TCP = %d KB/s", bandwidth));
-
- return rc;
-}
-
-
-#else
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled.
- */
-int dummy_sock_perf_test;
-#endif /* INCLUDE_SOCK_PERF_TEST */
-
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "test.h"
+#include <pjlib.h>
+#include <pj/compat/high_precision.h>
+
+
+/**
+ * \page page_pjlib_sock_perf_test Test: Socket Performance
+ *
+ * Test the performance of the socket communication. This will perform
+ * simple producer-consumer type of test, where we calculate how long
+ * does it take to send certain number of packets from producer to
+ * consumer.
+ *
+ * This file is <b>pjlib-test/sock_perf.c</b>
+ *
+ * \include pjlib-test/sock_perf.c
+ */
+
+#if INCLUDE_SOCK_PERF_TEST
+
+/*
+ * sock_producer_consumer()
+ *
+ * Simple producer-consumer benchmarking. Send loop number of
+ * buf_size size packets as fast as possible.
+ */
+static int sock_producer_consumer(int sock_type,
+ unsigned buf_size,
+ unsigned loop,
+ unsigned *p_bandwidth)
+{
+ pj_sock_t consumer, producer;
+ pj_pool_t *pool;
+ char *outgoing_buffer, *incoming_buffer;
+ pj_timestamp start, stop;
+ unsigned i;
+ pj_highprec_t elapsed, bandwidth;
+ pj_size_t total_received;
+ pj_status_t rc;
+
+ /* Create pool. */
+ pool = pj_pool_create(mem, NULL, 4096, 4096, NULL);
+ if (!pool)
+ return -10;
+
+ /* Create producer-consumer pair. */
+ rc = app_socketpair(PJ_AF_INET, sock_type, 0, &consumer, &producer);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error: create socket pair", rc);
+ return -20;
+ }
+
+ /* Create buffers. */
+ outgoing_buffer = pj_pool_alloc(pool, buf_size);
+ incoming_buffer = pj_pool_alloc(pool, buf_size);
+
+ /* Start loop. */
+ pj_get_timestamp(&start);
+ total_received = 0;
+ for (i=0; i<loop; ++i) {
+ pj_ssize_t sent, part_received, received;
+ pj_time_val delay;
+
+ sent = buf_size;
+ rc = pj_sock_send(producer, outgoing_buffer, &sent, 0);
+ if (rc != PJ_SUCCESS || sent != (pj_ssize_t)buf_size) {
+ app_perror("...error: send()", rc);
+ return -61;
+ }
+
+ /* Repeat recv() until all data is part_received.
+ * This applies only for non-UDP of course, since for UDP
+ * we would expect all data to be part_received in one packet.
+ */
+ received = 0;
+ do {
+ part_received = buf_size-received;
+ rc = pj_sock_recv(consumer, incoming_buffer+received,
+ &part_received, 0);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...recv error", rc);
+ return -70;
+ }
+ if (part_received <= 0) {
+ PJ_LOG(3,("", "...error: socket has closed (part_received=%d)!",
+ part_received));
+ return -73;
+ }
+ if ((pj_size_t)part_received != buf_size-received) {
+ if (sock_type != PJ_SOCK_STREAM) {
+ PJ_LOG(3,("", "...error: expecting %u bytes, got %u bytes",
+ buf_size-received, part_received));
+ return -76;
+ }
+ }
+ received += part_received;
+ } while ((pj_size_t)received < buf_size);
+
+ total_received += received;
+
+ /* Stop test if it's been runnign for more than 10 secs. */
+ pj_get_timestamp(&stop);
+ delay = pj_elapsed_time(&start, &stop);
+ if (delay.sec > 10)
+ break;
+ }
+
+ /* Stop timer. */
+ pj_get_timestamp(&stop);
+
+ elapsed = pj_elapsed_usec(&start, &stop);
+
+ /* bandwidth = total_received * 1000 / elapsed */
+ bandwidth = total_received;
+ pj_highprec_mul(bandwidth, 1000);
+ pj_highprec_div(bandwidth, elapsed);
+
+ *p_bandwidth = (pj_uint32_t)bandwidth;
+
+ /* Close sockets. */
+ pj_sock_close(consumer);
+ pj_sock_close(producer);
+
+ /* Done */
+ pj_pool_release(pool);
+
+ return 0;
+}
+
+/*
+ * sock_perf_test()
+ *
+ * Main test entry.
+ */
+int sock_perf_test(void)
+{
+ enum { LOOP = 64 * 1024 };
+ int rc;
+ unsigned bandwidth;
+
+ PJ_LOG(3,("", "...benchmarking socket "
+ "(2 sockets, packet=512, single threaded):"));
+
+ /* Benchmarking UDP */
+ rc = sock_producer_consumer(PJ_SOCK_DGRAM, 512, LOOP, &bandwidth);
+ if (rc != 0) return rc;
+ PJ_LOG(3,("", "....bandwidth UDP = %d KB/s", bandwidth));
+
+ /* Benchmarking TCP */
+ rc = sock_producer_consumer(PJ_SOCK_STREAM, 512, LOOP, &bandwidth);
+ if (rc != 0) return rc;
+ PJ_LOG(3,("", "....bandwidth TCP = %d KB/s", bandwidth));
+
+ return rc;
+}
+
+
+#else
+/* To prevent warning about "translation unit is empty"
+ * when this test is disabled.
+ */
+int dummy_sock_perf_test;
+#endif /* INCLUDE_SOCK_PERF_TEST */
+
+
diff --git a/pjlib/src/pjlib-test/string.c b/pjlib/src/pjlib-test/string.c
index 5f1f13f7..99358d3b 100644
--- a/pjlib/src/pjlib-test/string.c
+++ b/pjlib/src/pjlib-test/string.c
@@ -1,158 +1,179 @@
-/* $Id$
- */
-#include <pj/string.h>
-#include <pj/pool.h>
-#include <pj/log.h>
-#include "test.h"
-
-/**
- * \page page_pjlib_string_test Test: String
- *
- * This file provides implementation of \b string_test(). It tests the
- * functionality of the string API.
- *
- * \section sleep_test_sec Scope of the Test
- *
- * API tested:
- * - pj_str()
- * - pj_strcmp()
- * - pj_strcmp2()
- * - pj_stricmp()
- * - pj_strlen()
- * - pj_strncmp()
- * - pj_strnicmp()
- * - pj_strchr()
- * - pj_strdup()
- * - pj_strdup2()
- * - pj_strcpy()
- * - pj_strcat()
- * - pj_strtrim()
- * - pj_utoa()
- * - pj_strtoul()
- * - pj_create_random_string()
- *
- *
- * This file is <b>pjlib-test/string.c</b>
- *
- * \include pjlib-test/string.c
- */
-
-#if INCLUDE_STRING_TEST
-
-#ifdef _MSC_VER
-# pragma warning(disable: 4204)
-#endif
-
-#define HELLO_WORLD "Hello World"
-#define JUST_HELLO "Hello"
-#define UL_VALUE 3456789012UL
-
-int string_test(void)
-{
- const pj_str_t hello_world = { HELLO_WORLD, strlen(HELLO_WORLD) };
- const pj_str_t just_hello = { JUST_HELLO, strlen(JUST_HELLO) };
- pj_str_t s1, s2, s3, s4, s5;
- enum { RCOUNT = 10, RLEN = 16 };
- pj_str_t random[RCOUNT];
- pj_pool_t *pool;
- int i;
-
- pool = pj_pool_create(mem, NULL, 4096, 0, NULL);
- if (!pool) return -5;
-
- /*
- * pj_str(), pj_strcmp(), pj_stricmp(), pj_strlen(),
- * pj_strncmp(), pj_strchr()
- */
- s1 = pj_str(HELLO_WORLD);
- if (pj_strcmp(&s1, &hello_world) != 0)
- return -10;
- if (pj_stricmp(&s1, &hello_world) != 0)
- return -20;
- if (pj_strcmp(&s1, &just_hello) <= 0)
- return -30;
- if (pj_stricmp(&s1, &just_hello) <= 0)
- return -40;
- if (pj_strlen(&s1) != strlen(HELLO_WORLD))
- return -50;
- if (pj_strncmp(&s1, &hello_world, 5) != 0)
- return -60;
- if (pj_strnicmp(&s1, &hello_world, 5) != 0)
- return -70;
- if (pj_strchr(&s1, HELLO_WORLD[1]) != s1.ptr+1)
- return -80;
-
- /*
- * pj_strdup()
- */
- if (!pj_strdup(pool, &s2, &s1))
- return -100;
- if (pj_strcmp(&s1, &s2) != 0)
- return -110;
-
- /*
- * pj_strcpy(), pj_strcat()
- */
- s3.ptr = pj_pool_alloc(pool, 256);
- if (!s3.ptr)
- return -200;
- pj_strcpy(&s3, &s2);
- pj_strcat(&s3, &just_hello);
-
- if (pj_strcmp2(&s3, HELLO_WORLD JUST_HELLO) != 0)
- return -210;
-
- /*
- * pj_strdup2(), pj_strtrim().
- */
- pj_strdup2(pool, &s4, " " HELLO_WORLD "\t ");
- pj_strtrim(&s4);
- if (pj_strcmp2(&s4, HELLO_WORLD) != 0)
- return -250;
-
- /*
- * pj_utoa()
- */
- s5.ptr = pj_pool_alloc(pool, 16);
- if (!s5.ptr)
- return -270;
- s5.slen = pj_utoa(UL_VALUE, s5.ptr);
-
- /*
- * pj_strtoul()
- */
- if (pj_strtoul(&s5) != UL_VALUE)
- return -280;
-
- /*
- * pj_create_random_string()
- * Check that no duplicate strings are returned.
- */
- for (i=0; i<RCOUNT; ++i) {
- int j;
-
- random[i].ptr = pj_pool_alloc(pool, RLEN);
- if (!random[i].ptr)
- return -320;
-
- random[i].slen = RLEN;
- pj_create_random_string(random[i].ptr, RLEN);
-
- for (j=0; j<i; ++j) {
- if (pj_strcmp(&random[i], &random[j])==0)
- return -330;
- }
- }
-
- /* Done. */
- pj_pool_release(pool);
- return 0;
-}
-
-#else
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled.
- */
-int dummy_string_test;
-#endif /* INCLUDE_STRING_TEST */
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/string.h>
+#include <pj/pool.h>
+#include <pj/log.h>
+#include "test.h"
+
+/**
+ * \page page_pjlib_string_test Test: String
+ *
+ * This file provides implementation of \b string_test(). It tests the
+ * functionality of the string API.
+ *
+ * \section sleep_test_sec Scope of the Test
+ *
+ * API tested:
+ * - pj_str()
+ * - pj_strcmp()
+ * - pj_strcmp2()
+ * - pj_stricmp()
+ * - pj_strlen()
+ * - pj_strncmp()
+ * - pj_strnicmp()
+ * - pj_strchr()
+ * - pj_strdup()
+ * - pj_strdup2()
+ * - pj_strcpy()
+ * - pj_strcat()
+ * - pj_strtrim()
+ * - pj_utoa()
+ * - pj_strtoul()
+ * - pj_create_random_string()
+ *
+ *
+ * This file is <b>pjlib-test/string.c</b>
+ *
+ * \include pjlib-test/string.c
+ */
+
+#if INCLUDE_STRING_TEST
+
+#ifdef _MSC_VER
+# pragma warning(disable: 4204)
+#endif
+
+#define HELLO_WORLD "Hello World"
+#define JUST_HELLO "Hello"
+#define UL_VALUE 3456789012UL
+
+int string_test(void)
+{
+ const pj_str_t hello_world = { HELLO_WORLD, strlen(HELLO_WORLD) };
+ const pj_str_t just_hello = { JUST_HELLO, strlen(JUST_HELLO) };
+ pj_str_t s1, s2, s3, s4, s5;
+ enum { RCOUNT = 10, RLEN = 16 };
+ pj_str_t random[RCOUNT];
+ pj_pool_t *pool;
+ int i;
+
+ pool = pj_pool_create(mem, NULL, 4096, 0, NULL);
+ if (!pool) return -5;
+
+ /*
+ * pj_str(), pj_strcmp(), pj_stricmp(), pj_strlen(),
+ * pj_strncmp(), pj_strchr()
+ */
+ s1 = pj_str(HELLO_WORLD);
+ if (pj_strcmp(&s1, &hello_world) != 0)
+ return -10;
+ if (pj_stricmp(&s1, &hello_world) != 0)
+ return -20;
+ if (pj_strcmp(&s1, &just_hello) <= 0)
+ return -30;
+ if (pj_stricmp(&s1, &just_hello) <= 0)
+ return -40;
+ if (pj_strlen(&s1) != strlen(HELLO_WORLD))
+ return -50;
+ if (pj_strncmp(&s1, &hello_world, 5) != 0)
+ return -60;
+ if (pj_strnicmp(&s1, &hello_world, 5) != 0)
+ return -70;
+ if (pj_strchr(&s1, HELLO_WORLD[1]) != s1.ptr+1)
+ return -80;
+
+ /*
+ * pj_strdup()
+ */
+ if (!pj_strdup(pool, &s2, &s1))
+ return -100;
+ if (pj_strcmp(&s1, &s2) != 0)
+ return -110;
+
+ /*
+ * pj_strcpy(), pj_strcat()
+ */
+ s3.ptr = pj_pool_alloc(pool, 256);
+ if (!s3.ptr)
+ return -200;
+ pj_strcpy(&s3, &s2);
+ pj_strcat(&s3, &just_hello);
+
+ if (pj_strcmp2(&s3, HELLO_WORLD JUST_HELLO) != 0)
+ return -210;
+
+ /*
+ * pj_strdup2(), pj_strtrim().
+ */
+ pj_strdup2(pool, &s4, " " HELLO_WORLD "\t ");
+ pj_strtrim(&s4);
+ if (pj_strcmp2(&s4, HELLO_WORLD) != 0)
+ return -250;
+
+ /*
+ * pj_utoa()
+ */
+ s5.ptr = pj_pool_alloc(pool, 16);
+ if (!s5.ptr)
+ return -270;
+ s5.slen = pj_utoa(UL_VALUE, s5.ptr);
+
+ /*
+ * pj_strtoul()
+ */
+ if (pj_strtoul(&s5) != UL_VALUE)
+ return -280;
+
+ /*
+ * pj_create_random_string()
+ * Check that no duplicate strings are returned.
+ */
+ for (i=0; i<RCOUNT; ++i) {
+ int j;
+
+ random[i].ptr = pj_pool_alloc(pool, RLEN);
+ if (!random[i].ptr)
+ return -320;
+
+ random[i].slen = RLEN;
+ pj_create_random_string(random[i].ptr, RLEN);
+
+ for (j=0; j<i; ++j) {
+ if (pj_strcmp(&random[i], &random[j])==0)
+ return -330;
+ }
+ }
+
+ /* Done. */
+ pj_pool_release(pool);
+ return 0;
+}
+
+#else
+/* To prevent warning about "translation unit is empty"
+ * when this test is disabled.
+ */
+int dummy_string_test;
+#endif /* INCLUDE_STRING_TEST */
+
diff --git a/pjlib/src/pjlib-test/test.c b/pjlib/src/pjlib-test/test.c
index c9349a21..9c69a775 100644
--- a/pjlib/src/pjlib-test/test.c
+++ b/pjlib/src/pjlib-test/test.c
@@ -1,183 +1,204 @@
-/* $Id$
- */
-#include "test.h"
-#include <pjlib.h>
-#ifdef _MSC_VER
-# pragma warning(disable:4127)
-#endif
-
-#define DO_TEST(test) do { \
- PJ_LOG(3, ("test", "Running %s...", #test)); \
- rc = test; \
- PJ_LOG(3, ("test", \
- "%s(%d)", \
- (rc ? "..ERROR" : "..success"), rc)); \
- if (rc!=0) goto on_return; \
- } while (0)
-
-
-pj_pool_factory *mem;
-
-int param_echo_sock_type;
-const char *param_echo_server = ECHO_SERVER_ADDRESS;
-int param_echo_port = ECHO_SERVER_START_PORT;
-
-int test_inner(void)
-{
- pj_caching_pool caching_pool;
- const char *filename;
- int line;
- int rc = 0;
-
- mem = &caching_pool.factory;
-
- pj_log_set_level(3);
- pj_log_set_decor(PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_TIME |
- PJ_LOG_HAS_MICRO_SEC);
-
- rc = pj_init();
- if (rc != 0) {
- app_perror("pj_init() error!!", rc);
- return rc;
- }
-
- pj_dump_config();
- pj_caching_pool_init( &caching_pool, &pj_pool_factory_default_policy, 0 );
-
-#if INCLUDE_ERRNO_TEST
- DO_TEST( errno_test() );
-#endif
-
-#if INCLUDE_TIMESTAMP_TEST
- DO_TEST( timestamp_test() );
-#endif
-
-#if INCLUDE_EXCEPTION_TEST
- DO_TEST( exception_test() );
-#endif
-
-#if INCLUDE_RAND_TEST
- DO_TEST( rand_test() );
-#endif
-
-#if INCLUDE_LIST_TEST
- DO_TEST( list_test() );
-#endif
-
-#if INCLUDE_POOL_TEST
- DO_TEST( pool_test() );
-#endif
-
-#if INCLUDE_POOL_PERF_TEST
- DO_TEST( pool_perf_test() );
-#endif
-
-#if INCLUDE_STRING_TEST
- DO_TEST( string_test() );
-#endif
-
-#if INCLUDE_FIFOBUF_TEST
- DO_TEST( fifobuf_test() );
-#endif
-
-#if INCLUDE_RBTREE_TEST
- DO_TEST( rbtree_test() );
-#endif
-
-#if INCLUDE_ATOMIC_TEST
- DO_TEST( atomic_test() );
-#endif
-
-#if INCLUDE_MUTEX_TEST
- DO_TEST( mutex_test() );
-#endif
-
-#if INCLUDE_TIMER_TEST
- DO_TEST( timer_test() );
-#endif
-
-#if INCLUDE_SLEEP_TEST
- DO_TEST( sleep_test() );
-#endif
-
-#if INCLUDE_THREAD_TEST
- DO_TEST( thread_test() );
-#endif
-
-#if INCLUDE_SOCK_TEST
- DO_TEST( sock_test() );
-#endif
-
-#if INCLUDE_SOCK_PERF_TEST
- DO_TEST( sock_perf_test() );
-#endif
-
-#if INCLUDE_SELECT_TEST
- DO_TEST( select_test() );
-#endif
-
-#if INCLUDE_UDP_IOQUEUE_TEST
- DO_TEST( udp_ioqueue_test() );
-#endif
-
-#if PJ_HAS_TCP && INCLUDE_TCP_IOQUEUE_TEST
- DO_TEST( tcp_ioqueue_test() );
-#endif
-
-#if INCLUDE_IOQUEUE_PERF_TEST
- DO_TEST( ioqueue_perf_test() );
-#endif
-
-#if INCLUDE_FILE_TEST
- DO_TEST( file_test() );
-#endif
-
-#if INCLUDE_ECHO_SERVER
- //echo_server();
- //echo_srv_sync();
- udp_echo_srv_ioqueue();
-
-#elif INCLUDE_ECHO_CLIENT
- if (param_echo_sock_type == 0)
- param_echo_sock_type = PJ_SOCK_DGRAM;
-
- echo_client( param_echo_sock_type,
- param_echo_server,
- param_echo_port);
-#endif
-
- goto on_return;
-
-on_return:
-
- pj_caching_pool_destroy( &caching_pool );
-
- PJ_LOG(3,("test", ""));
-
- pj_thread_get_stack_info(pj_thread_this(), &filename, &line);
- PJ_LOG(3,("test", "Stack max usage: %u, deepest: %s:%u",
- pj_thread_get_stack_max_usage(pj_thread_this()),
- filename, line));
- if (rc == 0)
- PJ_LOG(3,("test", "Looks like everything is okay!.."));
- else
- PJ_LOG(3,("test", "Test completed with error(s)"));
- return 0;
-}
-
-int test_main(void)
-{
- PJ_USE_EXCEPTION;
-
- PJ_TRY {
- return test_inner();
- }
- PJ_DEFAULT {
- int id = PJ_GET_EXCEPTION();
- PJ_LOG(3,("test", "FATAL: unhandled exception id %d (%s)",
- id, pj_exception_id_name(id)));
- }
- PJ_END;
-
- return -1;
-}
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "test.h"
+#include <pjlib.h>
+#ifdef _MSC_VER
+# pragma warning(disable:4127)
+#endif
+
+#define DO_TEST(test) do { \
+ PJ_LOG(3, ("test", "Running %s...", #test)); \
+ rc = test; \
+ PJ_LOG(3, ("test", \
+ "%s(%d)", \
+ (rc ? "..ERROR" : "..success"), rc)); \
+ if (rc!=0) goto on_return; \
+ } while (0)
+
+
+pj_pool_factory *mem;
+
+int param_echo_sock_type;
+const char *param_echo_server = ECHO_SERVER_ADDRESS;
+int param_echo_port = ECHO_SERVER_START_PORT;
+
+int test_inner(void)
+{
+ pj_caching_pool caching_pool;
+ const char *filename;
+ int line;
+ int rc = 0;
+
+ mem = &caching_pool.factory;
+
+ pj_log_set_level(3);
+ pj_log_set_decor(PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_TIME |
+ PJ_LOG_HAS_MICRO_SEC);
+
+ rc = pj_init();
+ if (rc != 0) {
+ app_perror("pj_init() error!!", rc);
+ return rc;
+ }
+
+ pj_dump_config();
+ pj_caching_pool_init( &caching_pool, &pj_pool_factory_default_policy, 0 );
+
+#if INCLUDE_ERRNO_TEST
+ DO_TEST( errno_test() );
+#endif
+
+#if INCLUDE_TIMESTAMP_TEST
+ DO_TEST( timestamp_test() );
+#endif
+
+#if INCLUDE_EXCEPTION_TEST
+ DO_TEST( exception_test() );
+#endif
+
+#if INCLUDE_RAND_TEST
+ DO_TEST( rand_test() );
+#endif
+
+#if INCLUDE_LIST_TEST
+ DO_TEST( list_test() );
+#endif
+
+#if INCLUDE_POOL_TEST
+ DO_TEST( pool_test() );
+#endif
+
+#if INCLUDE_POOL_PERF_TEST
+ DO_TEST( pool_perf_test() );
+#endif
+
+#if INCLUDE_STRING_TEST
+ DO_TEST( string_test() );
+#endif
+
+#if INCLUDE_FIFOBUF_TEST
+ DO_TEST( fifobuf_test() );
+#endif
+
+#if INCLUDE_RBTREE_TEST
+ DO_TEST( rbtree_test() );
+#endif
+
+#if INCLUDE_ATOMIC_TEST
+ DO_TEST( atomic_test() );
+#endif
+
+#if INCLUDE_MUTEX_TEST
+ DO_TEST( mutex_test() );
+#endif
+
+#if INCLUDE_TIMER_TEST
+ DO_TEST( timer_test() );
+#endif
+
+#if INCLUDE_SLEEP_TEST
+ DO_TEST( sleep_test() );
+#endif
+
+#if INCLUDE_THREAD_TEST
+ DO_TEST( thread_test() );
+#endif
+
+#if INCLUDE_SOCK_TEST
+ DO_TEST( sock_test() );
+#endif
+
+#if INCLUDE_SOCK_PERF_TEST
+ DO_TEST( sock_perf_test() );
+#endif
+
+#if INCLUDE_SELECT_TEST
+ DO_TEST( select_test() );
+#endif
+
+#if INCLUDE_UDP_IOQUEUE_TEST
+ DO_TEST( udp_ioqueue_test() );
+#endif
+
+#if PJ_HAS_TCP && INCLUDE_TCP_IOQUEUE_TEST
+ DO_TEST( tcp_ioqueue_test() );
+#endif
+
+#if INCLUDE_IOQUEUE_PERF_TEST
+ DO_TEST( ioqueue_perf_test() );
+#endif
+
+#if INCLUDE_FILE_TEST
+ DO_TEST( file_test() );
+#endif
+
+#if INCLUDE_ECHO_SERVER
+ //echo_server();
+ //echo_srv_sync();
+ udp_echo_srv_ioqueue();
+
+#elif INCLUDE_ECHO_CLIENT
+ if (param_echo_sock_type == 0)
+ param_echo_sock_type = PJ_SOCK_DGRAM;
+
+ echo_client( param_echo_sock_type,
+ param_echo_server,
+ param_echo_port);
+#endif
+
+ goto on_return;
+
+on_return:
+
+ pj_caching_pool_destroy( &caching_pool );
+
+ PJ_LOG(3,("test", ""));
+
+ pj_thread_get_stack_info(pj_thread_this(), &filename, &line);
+ PJ_LOG(3,("test", "Stack max usage: %u, deepest: %s:%u",
+ pj_thread_get_stack_max_usage(pj_thread_this()),
+ filename, line));
+ if (rc == 0)
+ PJ_LOG(3,("test", "Looks like everything is okay!.."));
+ else
+ PJ_LOG(3,("test", "Test completed with error(s)"));
+ return 0;
+}
+
+int test_main(void)
+{
+ PJ_USE_EXCEPTION;
+
+ PJ_TRY {
+ return test_inner();
+ }
+ PJ_DEFAULT {
+ int id = PJ_GET_EXCEPTION();
+ PJ_LOG(3,("test", "FATAL: unhandled exception id %d (%s)",
+ id, pj_exception_id_name(id)));
+ }
+ PJ_END;
+
+ return -1;
+}
diff --git a/pjlib/src/pjlib-test/test.h b/pjlib/src/pjlib-test/test.h
index 17592908..0ae010c7 100644
--- a/pjlib/src/pjlib-test/test.h
+++ b/pjlib/src/pjlib-test/test.h
@@ -1,95 +1,116 @@
-/* $Id$
- */
-#ifndef __PJLIB_TEST_H__
-#define __PJLIB_TEST_H__
-
-#include <pj/types.h>
-
-#define GROUP_LIBC 1
-#define GROUP_OS 1
-#define GROUP_DATA_STRUCTURE 1
-#define GROUP_NETWORK 1
-#define GROUP_FILE 1
-
-#define INCLUDE_ERRNO_TEST GROUP_LIBC
-#define INCLUDE_TIMESTAMP_TEST GROUP_OS
-#define INCLUDE_EXCEPTION_TEST GROUP_LIBC
-#define INCLUDE_RAND_TEST GROUP_LIBC
-#define INCLUDE_LIST_TEST GROUP_DATA_STRUCTURE
-#define INCLUDE_POOL_TEST GROUP_LIBC
-#define INCLUDE_POOL_PERF_TEST (PJ_HAS_MALLOC && GROUP_LIBC)
-#define INCLUDE_STRING_TEST GROUP_DATA_STRUCTURE
-#define INCLUDE_FIFOBUF_TEST 0 // GROUP_DATA_STRUCTURE
-#define INCLUDE_RBTREE_TEST GROUP_DATA_STRUCTURE
-#define INCLUDE_TIMER_TEST GROUP_DATA_STRUCTURE
-#define INCLUDE_ATOMIC_TEST GROUP_OS
-#define INCLUDE_MUTEX_TEST GROUP_OS
-#define INCLUDE_SLEEP_TEST GROUP_OS
-#define INCLUDE_THREAD_TEST GROUP_OS
-#define INCLUDE_SOCK_TEST GROUP_NETWORK
-#define INCLUDE_SOCK_PERF_TEST GROUP_NETWORK
-#define INCLUDE_SELECT_TEST GROUP_NETWORK
-#define INCLUDE_UDP_IOQUEUE_TEST GROUP_NETWORK
-#define INCLUDE_TCP_IOQUEUE_TEST GROUP_NETWORK
-#define INCLUDE_IOQUEUE_PERF_TEST GROUP_NETWORK
-#define INCLUDE_FILE_TEST GROUP_FILE
-
-#define INCLUDE_ECHO_SERVER 0
-#define INCLUDE_ECHO_CLIENT 0
-
-
-#define ECHO_SERVER_MAX_THREADS 2
-#define ECHO_SERVER_START_PORT 65000
-#define ECHO_SERVER_ADDRESS "compaq.home"
-#define ECHO_SERVER_DURATION_MSEC (60*60*1000)
-
-#define ECHO_CLIENT_MAX_THREADS 6
-
-PJ_BEGIN_DECL
-
-extern int errno_test(void);
-extern int timestamp_test(void);
-extern int exception_test(void);
-extern int rand_test(void);
-extern int list_test(void);
-extern int pool_test(void);
-extern int pool_perf_test(void);
-extern int string_test(void);
-extern int fifobuf_test(void);
-extern int timer_test(void);
-extern int rbtree_test(void);
-extern int atomic_test(void);
-extern int mutex_test(void);
-extern int sleep_test(void);
-extern int thread_test(void);
-extern int sock_test(void);
-extern int sock_perf_test(void);
-extern int select_test(void);
-extern int udp_ioqueue_test(void);
-extern int tcp_ioqueue_test(void);
-extern int ioqueue_perf_test(void);
-extern int file_test(void);
-
-extern int echo_server(void);
-extern int echo_client(int sock_type, const char *server, int port);
-
-extern int echo_srv_sync(void);
-extern int udp_echo_srv_ioqueue(void);
-extern int echo_srv_common_loop(pj_atomic_t *bytes_counter);
-
-extern pj_pool_factory *mem;
-
-extern int test_main(void);
-extern void app_perror(const char *msg, pj_status_t err);
-extern pj_status_t app_socket(int family, int type, int proto, int port,
- pj_sock_t *ptr_sock);
-extern pj_status_t app_socketpair(int family, int type, int protocol,
- pj_sock_t *server, pj_sock_t *client);
-
-//#define TRACE_(expr) PJ_LOG(3,expr)
-#define TRACE_(expr)
-
-PJ_END_DECL
-
-#endif /* __PJLIB_TEST_H__ */
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __PJLIB_TEST_H__
+#define __PJLIB_TEST_H__
+
+#include <pj/types.h>
+
+#define GROUP_LIBC 1
+#define GROUP_OS 1
+#define GROUP_DATA_STRUCTURE 1
+#define GROUP_NETWORK 1
+#define GROUP_FILE 1
+
+#define INCLUDE_ERRNO_TEST GROUP_LIBC
+#define INCLUDE_TIMESTAMP_TEST GROUP_OS
+#define INCLUDE_EXCEPTION_TEST GROUP_LIBC
+#define INCLUDE_RAND_TEST GROUP_LIBC
+#define INCLUDE_LIST_TEST GROUP_DATA_STRUCTURE
+#define INCLUDE_POOL_TEST GROUP_LIBC
+#define INCLUDE_POOL_PERF_TEST (PJ_HAS_MALLOC && GROUP_LIBC)
+#define INCLUDE_STRING_TEST GROUP_DATA_STRUCTURE
+#define INCLUDE_FIFOBUF_TEST 0 // GROUP_DATA_STRUCTURE
+#define INCLUDE_RBTREE_TEST GROUP_DATA_STRUCTURE
+#define INCLUDE_TIMER_TEST GROUP_DATA_STRUCTURE
+#define INCLUDE_ATOMIC_TEST GROUP_OS
+#define INCLUDE_MUTEX_TEST GROUP_OS
+#define INCLUDE_SLEEP_TEST GROUP_OS
+#define INCLUDE_THREAD_TEST GROUP_OS
+#define INCLUDE_SOCK_TEST GROUP_NETWORK
+#define INCLUDE_SOCK_PERF_TEST GROUP_NETWORK
+#define INCLUDE_SELECT_TEST GROUP_NETWORK
+#define INCLUDE_UDP_IOQUEUE_TEST GROUP_NETWORK
+#define INCLUDE_TCP_IOQUEUE_TEST GROUP_NETWORK
+#define INCLUDE_IOQUEUE_PERF_TEST GROUP_NETWORK
+#define INCLUDE_FILE_TEST GROUP_FILE
+
+#define INCLUDE_ECHO_SERVER 0
+#define INCLUDE_ECHO_CLIENT 0
+
+
+#define ECHO_SERVER_MAX_THREADS 2
+#define ECHO_SERVER_START_PORT 65000
+#define ECHO_SERVER_ADDRESS "compaq.home"
+#define ECHO_SERVER_DURATION_MSEC (60*60*1000)
+
+#define ECHO_CLIENT_MAX_THREADS 6
+
+PJ_BEGIN_DECL
+
+extern int errno_test(void);
+extern int timestamp_test(void);
+extern int exception_test(void);
+extern int rand_test(void);
+extern int list_test(void);
+extern int pool_test(void);
+extern int pool_perf_test(void);
+extern int string_test(void);
+extern int fifobuf_test(void);
+extern int timer_test(void);
+extern int rbtree_test(void);
+extern int atomic_test(void);
+extern int mutex_test(void);
+extern int sleep_test(void);
+extern int thread_test(void);
+extern int sock_test(void);
+extern int sock_perf_test(void);
+extern int select_test(void);
+extern int udp_ioqueue_test(void);
+extern int tcp_ioqueue_test(void);
+extern int ioqueue_perf_test(void);
+extern int file_test(void);
+
+extern int echo_server(void);
+extern int echo_client(int sock_type, const char *server, int port);
+
+extern int echo_srv_sync(void);
+extern int udp_echo_srv_ioqueue(void);
+extern int echo_srv_common_loop(pj_atomic_t *bytes_counter);
+
+extern pj_pool_factory *mem;
+
+extern int test_main(void);
+extern void app_perror(const char *msg, pj_status_t err);
+extern pj_status_t app_socket(int family, int type, int proto, int port,
+ pj_sock_t *ptr_sock);
+extern pj_status_t app_socketpair(int family, int type, int protocol,
+ pj_sock_t *server, pj_sock_t *client);
+
+//#define TRACE_(expr) PJ_LOG(3,expr)
+#define TRACE_(expr)
+
+PJ_END_DECL
+
+#endif /* __PJLIB_TEST_H__ */
+
diff --git a/pjlib/src/pjlib-test/thread.c b/pjlib/src/pjlib-test/thread.c
index b35d9a58..a1c1bef2 100644
--- a/pjlib/src/pjlib-test/thread.c
+++ b/pjlib/src/pjlib-test/thread.c
@@ -1,273 +1,294 @@
-/* $Id$
- */
-#include "test.h"
-
-/**
- * \page page_pjlib_thread_test Test: Thread Test
- *
- * This file contains \a thread_test() definition.
- *
- * \section thread_test_scope_sec Scope of Test
- * This tests:
- * - whether PJ_THREAD_SUSPENDED flag works.
- * - whether multithreading works.
- * - whether thread timeslicing works, and threads have equal
- * time-slice proportion.
- *
- * APIs tested:
- * - pj_thread_create()
- * - pj_thread_register()
- * - pj_thread_this()
- * - pj_thread_get_name()
- * - pj_thread_destroy()
- * - pj_thread_resume()
- * - pj_thread_sleep()
- * - pj_thread_join()
- * - pj_thread_destroy()
- *
- *
- * This file is <b>pjlib-test/thread.c</b>
- *
- * \include pjlib-test/thread.c
- */
-#if INCLUDE_THREAD_TEST
-
-#include <pjlib.h>
-
-#define THIS_FILE "thread_test"
-
-static int quit_flag=0;
-
-/*
- * The thread's entry point.
- *
- * Each of the thread mainly will just execute the loop which
- * increments a variable.
- */
-static void* thread_proc(pj_uint32_t *pcounter)
-{
- /* Test that pj_thread_register() works. */
- pj_thread_desc desc;
- pj_thread_t *this_thread;
- pj_status_t rc;
-
- rc = pj_thread_register("thread", desc, &this_thread);
- if (rc != PJ_SUCCESS) {
- app_perror("...error in pj_thread_register", rc);
- return NULL;
- }
-
- /* Test that pj_thread_this() works */
- this_thread = pj_thread_this();
- if (this_thread == NULL) {
- PJ_LOG(3,(THIS_FILE, "...error: pj_thread_this() returns NULL!"));
- return NULL;
- }
-
- /* Test that pj_thread_get_name() works */
- if (pj_thread_get_name(this_thread) == NULL) {
- PJ_LOG(3,(THIS_FILE, "...error: pj_thread_get_name() returns NULL!"));
- return NULL;
- }
-
- /* Main loop */
- for (;!quit_flag;) {
- (*pcounter)++;
- //Must sleep if platform doesn't do time-slicing.
- pj_thread_sleep(0);
- }
-
- return NULL;
-}
-
-/*
- * simple_thread()
- */
-static int simple_thread(const char *title, unsigned flags)
-{
- pj_pool_t *pool;
- pj_thread_t *thread;
- pj_status_t rc;
- pj_uint32_t counter = 0;
-
- PJ_LOG(3,(THIS_FILE, "..%s", title));
-
- pool = pj_pool_create(mem, NULL, 4000, 4000, NULL);
- if (!pool)
- return -1000;
-
- quit_flag = 0;
-
- rc = pj_thread_create(pool, "thread", (pj_thread_proc*)&thread_proc,
- &counter,
- PJ_THREAD_DEFAULT_STACK_SIZE,
- flags,
- &thread);
-
- if (rc != PJ_SUCCESS) {
- app_perror("...error: unable to create thread", rc);
- return -1010;
- }
-
- if (flags & PJ_THREAD_SUSPENDED) {
- rc = pj_thread_resume(thread);
- if (rc != PJ_SUCCESS) {
- app_perror("...error: resume thread error", rc);
- return -1020;
- }
- }
-
- PJ_LOG(3,(THIS_FILE, "..waiting for thread to quit.."));
-
- quit_flag = 1;
- pj_thread_join(thread);
-
- pj_pool_release(pool);
-
- PJ_LOG(3,(THIS_FILE, "...%s success", title));
- return PJ_SUCCESS;
-}
-
-
-/*
- * timeslice_test()
- */
-static int timeslice_test(void)
-{
- enum { NUM_THREADS = 4 };
- pj_pool_t *pool;
- pj_uint32_t counter[NUM_THREADS], lowest, highest, diff;
- pj_thread_t *thread[NUM_THREADS];
- int i;
- pj_status_t rc;
-
- quit_flag = 0;
-
- pool = pj_pool_create(mem, NULL, 4096, 0, NULL);
- if (!pool)
- return -10;
-
- PJ_LOG(3,(THIS_FILE, "..timeslice testing with %d threads", NUM_THREADS));
-
- /* Create all threads in suspended mode. */
- for (i=0; i<NUM_THREADS; ++i) {
- counter[i] = 0;
- rc = pj_thread_create(pool, "thread", (pj_thread_proc*)&thread_proc,
- &counter[i],
- PJ_THREAD_DEFAULT_STACK_SIZE,
- PJ_THREAD_SUSPENDED,
- &thread[i]);
- if (rc!=PJ_SUCCESS) {
- app_perror("...ERROR in pj_thread_create()", rc);
- return -20;
- }
- }
-
- /* Sleep for 1 second.
- * The purpose of this is to test whether all threads are suspended.
- */
- pj_thread_sleep(1000);
-
- /* Check that all counters are still zero. */
- for (i=0; i<NUM_THREADS; ++i) {
- if (counter[i] != 0) {
- PJ_LOG(3,(THIS_FILE, "....ERROR! Thread %d-th is not suspended!",
- i));
- return -30;
- }
- }
-
- /* Now resume all threads. */
- for (i=0; i<NUM_THREADS; ++i) {
- rc = pj_thread_resume(thread[i]);
- if (rc != PJ_SUCCESS) {
- app_perror("...ERROR in pj_thread_resume()", rc);
- return -40;
- }
- }
-
- /* Main thread sleeps for some time to allow threads to run.
- * The longer we sleep, the more accurate the calculation will be,
- * but it'll make user waits for longer for the test to finish.
- */
- pj_thread_sleep(5000);
-
- /* Signal all threads to quit. */
- quit_flag = 1;
-
- /* Wait until all threads quit, then destroy. */
- for (i=0; i<NUM_THREADS; ++i) {
- rc = pj_thread_join(thread[i]);
- if (rc != PJ_SUCCESS) {
- app_perror("...ERROR in pj_thread_join()", rc);
- return -50;
- }
- rc = pj_thread_destroy(thread[i]);
- if (rc != PJ_SUCCESS) {
- app_perror("...ERROR in pj_thread_destroy()", rc);
- return -60;
- }
- }
-
- /* Now examine the value of the counters.
- * Check that all threads had equal proportion of processing.
- */
- lowest = 0xFFFFFFFF;
- highest = 0;
- for (i=0; i<NUM_THREADS; ++i) {
- if (counter[i] < lowest)
- lowest = counter[i];
- if (counter[i] > highest)
- highest = counter[i];
- }
-
- /* Check that all threads are running. */
- if (lowest < 2) {
- PJ_LOG(3,(THIS_FILE, "...ERROR: not all threads were running!"));
- return -70;
- }
-
- /* The difference between lowest and higest should be lower than 50%.
- */
- diff = (highest-lowest)*100 / ((highest+lowest)/2);
- if ( diff >= 50) {
- PJ_LOG(3,(THIS_FILE, "...ERROR: thread didn't have equal timeslice!"));
- PJ_LOG(3,(THIS_FILE, ".....lowest counter=%u, highest counter=%u, diff=%u%%",
- lowest, highest, diff));
- return -80;
- } else {
- PJ_LOG(3,(THIS_FILE,
- "...info: timeslice diff between lowest & highest=%u%%",
- diff));
- }
-
- return 0;
-}
-
-int thread_test(void)
-{
- int rc;
-
- rc = simple_thread("simple thread test", 0);
- if (rc != PJ_SUCCESS)
- return rc;
-
- rc = simple_thread("suspended thread test", PJ_THREAD_SUSPENDED);
- if (rc != PJ_SUCCESS)
- return rc;
-
- rc = timeslice_test();
- if (rc != PJ_SUCCESS)
- return rc;
-
- return rc;
-}
-
-#else
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled.
- */
-int dummy_thread_test;
-#endif /* INCLUDE_THREAD_TEST */
-
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "test.h"
+
+/**
+ * \page page_pjlib_thread_test Test: Thread Test
+ *
+ * This file contains \a thread_test() definition.
+ *
+ * \section thread_test_scope_sec Scope of Test
+ * This tests:
+ * - whether PJ_THREAD_SUSPENDED flag works.
+ * - whether multithreading works.
+ * - whether thread timeslicing works, and threads have equal
+ * time-slice proportion.
+ *
+ * APIs tested:
+ * - pj_thread_create()
+ * - pj_thread_register()
+ * - pj_thread_this()
+ * - pj_thread_get_name()
+ * - pj_thread_destroy()
+ * - pj_thread_resume()
+ * - pj_thread_sleep()
+ * - pj_thread_join()
+ * - pj_thread_destroy()
+ *
+ *
+ * This file is <b>pjlib-test/thread.c</b>
+ *
+ * \include pjlib-test/thread.c
+ */
+#if INCLUDE_THREAD_TEST
+
+#include <pjlib.h>
+
+#define THIS_FILE "thread_test"
+
+static int quit_flag=0;
+
+/*
+ * The thread's entry point.
+ *
+ * Each of the thread mainly will just execute the loop which
+ * increments a variable.
+ */
+static void* thread_proc(pj_uint32_t *pcounter)
+{
+ /* Test that pj_thread_register() works. */
+ pj_thread_desc desc;
+ pj_thread_t *this_thread;
+ pj_status_t rc;
+
+ rc = pj_thread_register("thread", desc, &this_thread);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error in pj_thread_register", rc);
+ return NULL;
+ }
+
+ /* Test that pj_thread_this() works */
+ this_thread = pj_thread_this();
+ if (this_thread == NULL) {
+ PJ_LOG(3,(THIS_FILE, "...error: pj_thread_this() returns NULL!"));
+ return NULL;
+ }
+
+ /* Test that pj_thread_get_name() works */
+ if (pj_thread_get_name(this_thread) == NULL) {
+ PJ_LOG(3,(THIS_FILE, "...error: pj_thread_get_name() returns NULL!"));
+ return NULL;
+ }
+
+ /* Main loop */
+ for (;!quit_flag;) {
+ (*pcounter)++;
+ //Must sleep if platform doesn't do time-slicing.
+ pj_thread_sleep(0);
+ }
+
+ return NULL;
+}
+
+/*
+ * simple_thread()
+ */
+static int simple_thread(const char *title, unsigned flags)
+{
+ pj_pool_t *pool;
+ pj_thread_t *thread;
+ pj_status_t rc;
+ pj_uint32_t counter = 0;
+
+ PJ_LOG(3,(THIS_FILE, "..%s", title));
+
+ pool = pj_pool_create(mem, NULL, 4000, 4000, NULL);
+ if (!pool)
+ return -1000;
+
+ quit_flag = 0;
+
+ rc = pj_thread_create(pool, "thread", (pj_thread_proc*)&thread_proc,
+ &counter,
+ PJ_THREAD_DEFAULT_STACK_SIZE,
+ flags,
+ &thread);
+
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error: unable to create thread", rc);
+ return -1010;
+ }
+
+ if (flags & PJ_THREAD_SUSPENDED) {
+ rc = pj_thread_resume(thread);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error: resume thread error", rc);
+ return -1020;
+ }
+ }
+
+ PJ_LOG(3,(THIS_FILE, "..waiting for thread to quit.."));
+
+ quit_flag = 1;
+ pj_thread_join(thread);
+
+ pj_pool_release(pool);
+
+ PJ_LOG(3,(THIS_FILE, "...%s success", title));
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * timeslice_test()
+ */
+static int timeslice_test(void)
+{
+ enum { NUM_THREADS = 4 };
+ pj_pool_t *pool;
+ pj_uint32_t counter[NUM_THREADS], lowest, highest, diff;
+ pj_thread_t *thread[NUM_THREADS];
+ int i;
+ pj_status_t rc;
+
+ quit_flag = 0;
+
+ pool = pj_pool_create(mem, NULL, 4096, 0, NULL);
+ if (!pool)
+ return -10;
+
+ PJ_LOG(3,(THIS_FILE, "..timeslice testing with %d threads", NUM_THREADS));
+
+ /* Create all threads in suspended mode. */
+ for (i=0; i<NUM_THREADS; ++i) {
+ counter[i] = 0;
+ rc = pj_thread_create(pool, "thread", (pj_thread_proc*)&thread_proc,
+ &counter[i],
+ PJ_THREAD_DEFAULT_STACK_SIZE,
+ PJ_THREAD_SUSPENDED,
+ &thread[i]);
+ if (rc!=PJ_SUCCESS) {
+ app_perror("...ERROR in pj_thread_create()", rc);
+ return -20;
+ }
+ }
+
+ /* Sleep for 1 second.
+ * The purpose of this is to test whether all threads are suspended.
+ */
+ pj_thread_sleep(1000);
+
+ /* Check that all counters are still zero. */
+ for (i=0; i<NUM_THREADS; ++i) {
+ if (counter[i] != 0) {
+ PJ_LOG(3,(THIS_FILE, "....ERROR! Thread %d-th is not suspended!",
+ i));
+ return -30;
+ }
+ }
+
+ /* Now resume all threads. */
+ for (i=0; i<NUM_THREADS; ++i) {
+ rc = pj_thread_resume(thread[i]);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...ERROR in pj_thread_resume()", rc);
+ return -40;
+ }
+ }
+
+ /* Main thread sleeps for some time to allow threads to run.
+ * The longer we sleep, the more accurate the calculation will be,
+ * but it'll make user waits for longer for the test to finish.
+ */
+ pj_thread_sleep(5000);
+
+ /* Signal all threads to quit. */
+ quit_flag = 1;
+
+ /* Wait until all threads quit, then destroy. */
+ for (i=0; i<NUM_THREADS; ++i) {
+ rc = pj_thread_join(thread[i]);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...ERROR in pj_thread_join()", rc);
+ return -50;
+ }
+ rc = pj_thread_destroy(thread[i]);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...ERROR in pj_thread_destroy()", rc);
+ return -60;
+ }
+ }
+
+ /* Now examine the value of the counters.
+ * Check that all threads had equal proportion of processing.
+ */
+ lowest = 0xFFFFFFFF;
+ highest = 0;
+ for (i=0; i<NUM_THREADS; ++i) {
+ if (counter[i] < lowest)
+ lowest = counter[i];
+ if (counter[i] > highest)
+ highest = counter[i];
+ }
+
+ /* Check that all threads are running. */
+ if (lowest < 2) {
+ PJ_LOG(3,(THIS_FILE, "...ERROR: not all threads were running!"));
+ return -70;
+ }
+
+ /* The difference between lowest and higest should be lower than 50%.
+ */
+ diff = (highest-lowest)*100 / ((highest+lowest)/2);
+ if ( diff >= 50) {
+ PJ_LOG(3,(THIS_FILE, "...ERROR: thread didn't have equal timeslice!"));
+ PJ_LOG(3,(THIS_FILE, ".....lowest counter=%u, highest counter=%u, diff=%u%%",
+ lowest, highest, diff));
+ return -80;
+ } else {
+ PJ_LOG(3,(THIS_FILE,
+ "...info: timeslice diff between lowest & highest=%u%%",
+ diff));
+ }
+
+ return 0;
+}
+
+int thread_test(void)
+{
+ int rc;
+
+ rc = simple_thread("simple thread test", 0);
+ if (rc != PJ_SUCCESS)
+ return rc;
+
+ rc = simple_thread("suspended thread test", PJ_THREAD_SUSPENDED);
+ if (rc != PJ_SUCCESS)
+ return rc;
+
+ rc = timeslice_test();
+ if (rc != PJ_SUCCESS)
+ return rc;
+
+ return rc;
+}
+
+#else
+/* To prevent warning about "translation unit is empty"
+ * when this test is disabled.
+ */
+int dummy_thread_test;
+#endif /* INCLUDE_THREAD_TEST */
+
+
diff --git a/pjlib/src/pjlib-test/timer.c b/pjlib/src/pjlib-test/timer.c
index c6922cf7..4f3d4b81 100644
--- a/pjlib/src/pjlib-test/timer.c
+++ b/pjlib/src/pjlib-test/timer.c
@@ -1,170 +1,191 @@
-/* $Id$
- */
-#include "test.h"
-
-/**
- * \page page_pjlib_timer_test Test: Timer
- *
- * This file provides implementation of \b timer_test(). It tests the
- * functionality of the timer heap.
- *
- *
- * This file is <b>pjlib-test/timer.c</b>
- *
- * \include pjlib-test/timer.c
- */
-
-
-#if INCLUDE_TIMER_TEST
-
-#include <pjlib.h>
-
-#define LOOP 16
-#define MIN_COUNT 250
-#define MAX_COUNT (LOOP * MIN_COUNT)
-#define MIN_DELAY 2
-#define D (MAX_COUNT / 32000)
-#define DELAY (D < MIN_DELAY ? MIN_DELAY : D)
-#define THIS_FILE "timer_test"
-
-
-static void timer_callback(pj_timer_heap_t *ht, pj_timer_entry *e)
-{
- PJ_UNUSED_ARG(ht);
- PJ_UNUSED_ARG(e);
-}
-
-static int test_timer_heap(void)
-{
- int i, j;
- pj_timer_entry *entry;
- pj_pool_t *pool;
- pj_timer_heap_t *timer;
- pj_time_val delay;
- pj_status_t rc; int err=0;
- unsigned size, count;
-
- size = pj_timer_heap_mem_size(MAX_COUNT)+MAX_COUNT*sizeof(pj_timer_entry);
- pool = pj_pool_create( mem, NULL, size, 4000, NULL);
- if (!pool) {
- PJ_LOG(3,("test", "...error: unable to create pool of %u bytes",
- size));
- return -10;
- }
-
- entry = (pj_timer_entry*)pj_pool_calloc(pool, MAX_COUNT, sizeof(*entry));
- if (!entry)
- return -20;
-
- for (i=0; i<MAX_COUNT; ++i) {
- entry[i].cb = &timer_callback;
- }
- rc = pj_timer_heap_create(pool, MAX_COUNT, 0, &timer);
- if (rc != PJ_SUCCESS) {
- app_perror("...error: unable to create timer heap", rc);
- return -30;
- }
-
- count = MIN_COUNT;
- for (i=0; i<LOOP; ++i) {
- int early = 0;
- int done=0;
- int cancelled=0;
- int rc;
- pj_timestamp t1, t2, t_sched, t_cancel, t_poll;
- pj_time_val now, expire;
-
- pj_gettimeofday(&now);
- pj_srand(now.sec);
- t_sched.u32.lo = t_cancel.u32.lo = t_poll.u32.lo = 0;
-
- // Register timers
- for (j=0; j<(int)count; ++j) {
- delay.sec = pj_rand() % DELAY;
- delay.msec = pj_rand() % 1000;
-
- // Schedule timer
- pj_get_timestamp(&t1);
- rc = pj_timer_heap_schedule(timer, &entry[j], &delay);
- if (rc != 0)
- return -40;
- pj_get_timestamp(&t2);
-
- t_sched.u32.lo += (t2.u32.lo - t1.u32.lo);
-
- // Poll timers.
- pj_get_timestamp(&t1);
- rc = pj_timer_heap_poll(timer, NULL);
- pj_get_timestamp(&t2);
- if (rc > 0) {
- t_poll.u32.lo += (t2.u32.lo - t1.u32.lo);
- early += rc;
- }
- }
-
- // Set the time where all timers should finish
- pj_gettimeofday(&expire);
- delay.sec = DELAY;
- delay.msec = 0;
- PJ_TIME_VAL_ADD(expire, delay);
-
- // Wait unfil all timers finish, cancel some of them.
- do {
- int index = pj_rand() % count;
- pj_get_timestamp(&t1);
- rc = pj_timer_heap_cancel(timer, &entry[index]);
- pj_get_timestamp(&t2);
- if (rc > 0) {
- cancelled += rc;
- t_cancel.u32.lo += (t2.u32.lo - t1.u32.lo);
- }
-
- pj_gettimeofday(&now);
-
- pj_get_timestamp(&t1);
- rc = pj_timer_heap_poll(timer, NULL);
- pj_get_timestamp(&t2);
- if (rc > 0) {
- done += rc;
- t_poll.u32.lo += (t2.u32.lo - t1.u32.lo);
- }
-
- } while (PJ_TIME_VAL_LTE(now, expire)&&pj_timer_heap_count(timer) > 0);
-
- if (pj_timer_heap_count(timer)) {
- PJ_LOG(3, (THIS_FILE, "ERROR: %d timers left",
- pj_timer_heap_count(timer)));
- ++err;
- }
- t_sched.u32.lo /= count;
- t_cancel.u32.lo /= count;
- t_poll.u32.lo /= count;
- PJ_LOG(4, (THIS_FILE,
- "...ok (count:%d, early:%d, cancelled:%d, "
- "sched:%d, cancel:%d poll:%d)",
- count, early, cancelled, t_sched.u32.lo, t_cancel.u32.lo,
- t_poll.u32.lo));
-
- count = count * 2;
- if (count > MAX_COUNT)
- break;
- }
-
- pj_pool_release(pool);
- return err;
-}
-
-
-int timer_test()
-{
- return test_timer_heap();
-}
-
-#else
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled.
- */
-int dummy_timer_test;
-#endif /* INCLUDE_TIMER_TEST */
-
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "test.h"
+
+/**
+ * \page page_pjlib_timer_test Test: Timer
+ *
+ * This file provides implementation of \b timer_test(). It tests the
+ * functionality of the timer heap.
+ *
+ *
+ * This file is <b>pjlib-test/timer.c</b>
+ *
+ * \include pjlib-test/timer.c
+ */
+
+
+#if INCLUDE_TIMER_TEST
+
+#include <pjlib.h>
+
+#define LOOP 16
+#define MIN_COUNT 250
+#define MAX_COUNT (LOOP * MIN_COUNT)
+#define MIN_DELAY 2
+#define D (MAX_COUNT / 32000)
+#define DELAY (D < MIN_DELAY ? MIN_DELAY : D)
+#define THIS_FILE "timer_test"
+
+
+static void timer_callback(pj_timer_heap_t *ht, pj_timer_entry *e)
+{
+ PJ_UNUSED_ARG(ht);
+ PJ_UNUSED_ARG(e);
+}
+
+static int test_timer_heap(void)
+{
+ int i, j;
+ pj_timer_entry *entry;
+ pj_pool_t *pool;
+ pj_timer_heap_t *timer;
+ pj_time_val delay;
+ pj_status_t rc; int err=0;
+ unsigned size, count;
+
+ size = pj_timer_heap_mem_size(MAX_COUNT)+MAX_COUNT*sizeof(pj_timer_entry);
+ pool = pj_pool_create( mem, NULL, size, 4000, NULL);
+ if (!pool) {
+ PJ_LOG(3,("test", "...error: unable to create pool of %u bytes",
+ size));
+ return -10;
+ }
+
+ entry = (pj_timer_entry*)pj_pool_calloc(pool, MAX_COUNT, sizeof(*entry));
+ if (!entry)
+ return -20;
+
+ for (i=0; i<MAX_COUNT; ++i) {
+ entry[i].cb = &timer_callback;
+ }
+ rc = pj_timer_heap_create(pool, MAX_COUNT, &timer);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...error: unable to create timer heap", rc);
+ return -30;
+ }
+
+ count = MIN_COUNT;
+ for (i=0; i<LOOP; ++i) {
+ int early = 0;
+ int done=0;
+ int cancelled=0;
+ int rc;
+ pj_timestamp t1, t2, t_sched, t_cancel, t_poll;
+ pj_time_val now, expire;
+
+ pj_gettimeofday(&now);
+ pj_srand(now.sec);
+ t_sched.u32.lo = t_cancel.u32.lo = t_poll.u32.lo = 0;
+
+ // Register timers
+ for (j=0; j<(int)count; ++j) {
+ delay.sec = pj_rand() % DELAY;
+ delay.msec = pj_rand() % 1000;
+
+ // Schedule timer
+ pj_get_timestamp(&t1);
+ rc = pj_timer_heap_schedule(timer, &entry[j], &delay);
+ if (rc != 0)
+ return -40;
+ pj_get_timestamp(&t2);
+
+ t_sched.u32.lo += (t2.u32.lo - t1.u32.lo);
+
+ // Poll timers.
+ pj_get_timestamp(&t1);
+ rc = pj_timer_heap_poll(timer, NULL);
+ pj_get_timestamp(&t2);
+ if (rc > 0) {
+ t_poll.u32.lo += (t2.u32.lo - t1.u32.lo);
+ early += rc;
+ }
+ }
+
+ // Set the time where all timers should finish
+ pj_gettimeofday(&expire);
+ delay.sec = DELAY;
+ delay.msec = 0;
+ PJ_TIME_VAL_ADD(expire, delay);
+
+ // Wait unfil all timers finish, cancel some of them.
+ do {
+ int index = pj_rand() % count;
+ pj_get_timestamp(&t1);
+ rc = pj_timer_heap_cancel(timer, &entry[index]);
+ pj_get_timestamp(&t2);
+ if (rc > 0) {
+ cancelled += rc;
+ t_cancel.u32.lo += (t2.u32.lo - t1.u32.lo);
+ }
+
+ pj_gettimeofday(&now);
+
+ pj_get_timestamp(&t1);
+ rc = pj_timer_heap_poll(timer, NULL);
+ pj_get_timestamp(&t2);
+ if (rc > 0) {
+ done += rc;
+ t_poll.u32.lo += (t2.u32.lo - t1.u32.lo);
+ }
+
+ } while (PJ_TIME_VAL_LTE(now, expire)&&pj_timer_heap_count(timer) > 0);
+
+ if (pj_timer_heap_count(timer)) {
+ PJ_LOG(3, (THIS_FILE, "ERROR: %d timers left",
+ pj_timer_heap_count(timer)));
+ ++err;
+ }
+ t_sched.u32.lo /= count;
+ t_cancel.u32.lo /= count;
+ t_poll.u32.lo /= count;
+ PJ_LOG(4, (THIS_FILE,
+ "...ok (count:%d, early:%d, cancelled:%d, "
+ "sched:%d, cancel:%d poll:%d)",
+ count, early, cancelled, t_sched.u32.lo, t_cancel.u32.lo,
+ t_poll.u32.lo));
+
+ count = count * 2;
+ if (count > MAX_COUNT)
+ break;
+ }
+
+ pj_pool_release(pool);
+ return err;
+}
+
+
+int timer_test()
+{
+ return test_timer_heap();
+}
+
+#else
+/* To prevent warning about "translation unit is empty"
+ * when this test is disabled.
+ */
+int dummy_timer_test;
+#endif /* INCLUDE_TIMER_TEST */
+
+
diff --git a/pjlib/src/pjlib-test/timestamp.c b/pjlib/src/pjlib-test/timestamp.c
index deeab055..347d256f 100644
--- a/pjlib/src/pjlib-test/timestamp.c
+++ b/pjlib/src/pjlib-test/timestamp.c
@@ -1,127 +1,148 @@
-/* $Id$
- */
-#include "test.h"
-#include <pj/os.h>
-#include <pj/log.h>
-
-
-/**
- * \page page_pjlib_timestamp_test Test: Timestamp
- *
- * This file provides implementation of timestamp_test()
- *
- * \section timestamp_test_sec Scope of the Test
- *
- * This tests whether timestamp API works.
- *
- * API tested:
- * - pj_get_timestamp_freq()
- * - pj_get_timestamp()
- * - pj_elapsed_usec()
- * - PJ_LOG()
- *
- *
- * This file is <b>pjlib-test/timestamp.c</b>
- *
- * \include pjlib-test/timestamp.c
- */
-
-#if INCLUDE_TIMESTAMP_TEST
-
-#define THIS_FILE "timestamp"
-
-int timestamp_test(void)
-{
- enum { CONSECUTIVE_LOOP = 1000 };
- volatile unsigned i;
- pj_timestamp freq, t1, t2;
- unsigned elapsed;
- pj_status_t rc;
-
- PJ_LOG(3,(THIS_FILE, "...Testing timestamp (high res time)"));
-
- /* Get and display timestamp frequency. */
- if ((rc=pj_get_timestamp_freq(&freq)) != PJ_SUCCESS) {
- app_perror("...ERROR: get timestamp freq", rc);
- return -1000;
- }
-
- PJ_LOG(3,(THIS_FILE, "....frequency: hiword=%lu loword=%lu",
- freq.u32.hi, freq.u32.lo));
-
- PJ_LOG(3,(THIS_FILE, "...checking if time can run backwards (pls wait).."));
-
- /*
- * Check if consecutive readings should yield timestamp value
- * that is bigger than previous value.
- * First we get the first timestamp.
- */
- rc = pj_get_timestamp(&t1);
- if (rc != PJ_SUCCESS) {
- app_perror("...ERROR: get timestamp", rc);
- return -1001;
- }
- for (i=0; i<CONSECUTIVE_LOOP; ++i) {
- /*
- volatile unsigned j;
- for (j=0; j<1000; ++j)
- ;
- */
- pj_thread_sleep(1);
- rc = pj_get_timestamp(&t2);
- if (rc != PJ_SUCCESS) {
- app_perror("...ERROR: get timestamp", rc);
- return -1002;
- }
- /* compare t2 with t1, expecting t2 >= t1. */
- if (t2.u32.hi < t1.u32.hi ||
- (t2.u32.hi == t1.u32.hi && t2.u32.lo < t1.u32.lo))
- {
- PJ_LOG(3,(THIS_FILE, "...ERROR: timestamp runs backwards!"));
- return -1003;
- }
- }
-
- /*
- * Simple test to time some loop.
- */
- PJ_LOG(3,(THIS_FILE, "....testing simple 1000000 loop"));
-
-
- /* Mark start time. */
- if ((rc=pj_get_timestamp(&t1)) != PJ_SUCCESS) {
- app_perror("....error: cat't get timestamp", rc);
- return -1010;
- }
-
- /* Loop.. */
- for (i=0; i<1000000; ++i)
- ;
-
- /* Mark end time. */
- pj_get_timestamp(&t2);
-
- /* Get elapsed time in usec. */
- elapsed = pj_elapsed_usec(&t1, &t2);
- PJ_LOG(3,(THIS_FILE, "....elapsed: %u usec", (unsigned)elapsed));
-
- /* See if elapsed time is reasonable. */
- if (elapsed < 1 || elapsed > 100000) {
- PJ_LOG(3,(THIS_FILE, "....error: elapsed time outside window (%u, "
- "t1.u32.hi=%u, t1.u32.lo=%u, "
- "t2.u32.hi=%u, t2.u32.lo=%u)",
- elapsed,
- t1.u32.hi, t1.u32.lo, t2.u32.hi, t2.u32.lo));
- return -1030;
- }
- return 0;
-}
-
-
-#else
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled.
- */
-int dummy_timestamp_test;
-#endif /* INCLUDE_TIMESTAMP_TEST */
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "test.h"
+#include <pj/os.h>
+#include <pj/log.h>
+
+
+/**
+ * \page page_pjlib_timestamp_test Test: Timestamp
+ *
+ * This file provides implementation of timestamp_test()
+ *
+ * \section timestamp_test_sec Scope of the Test
+ *
+ * This tests whether timestamp API works.
+ *
+ * API tested:
+ * - pj_get_timestamp_freq()
+ * - pj_get_timestamp()
+ * - pj_elapsed_usec()
+ * - PJ_LOG()
+ *
+ *
+ * This file is <b>pjlib-test/timestamp.c</b>
+ *
+ * \include pjlib-test/timestamp.c
+ */
+
+#if INCLUDE_TIMESTAMP_TEST
+
+#define THIS_FILE "timestamp"
+
+int timestamp_test(void)
+{
+ enum { CONSECUTIVE_LOOP = 1000 };
+ volatile unsigned i;
+ pj_timestamp freq, t1, t2;
+ unsigned elapsed;
+ pj_status_t rc;
+
+ PJ_LOG(3,(THIS_FILE, "...Testing timestamp (high res time)"));
+
+ /* Get and display timestamp frequency. */
+ if ((rc=pj_get_timestamp_freq(&freq)) != PJ_SUCCESS) {
+ app_perror("...ERROR: get timestamp freq", rc);
+ return -1000;
+ }
+
+ PJ_LOG(3,(THIS_FILE, "....frequency: hiword=%lu loword=%lu",
+ freq.u32.hi, freq.u32.lo));
+
+ PJ_LOG(3,(THIS_FILE, "...checking if time can run backwards (pls wait).."));
+
+ /*
+ * Check if consecutive readings should yield timestamp value
+ * that is bigger than previous value.
+ * First we get the first timestamp.
+ */
+ rc = pj_get_timestamp(&t1);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...ERROR: get timestamp", rc);
+ return -1001;
+ }
+ for (i=0; i<CONSECUTIVE_LOOP; ++i) {
+ /*
+ volatile unsigned j;
+ for (j=0; j<1000; ++j)
+ ;
+ */
+ pj_thread_sleep(1);
+ rc = pj_get_timestamp(&t2);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...ERROR: get timestamp", rc);
+ return -1002;
+ }
+ /* compare t2 with t1, expecting t2 >= t1. */
+ if (t2.u32.hi < t1.u32.hi ||
+ (t2.u32.hi == t1.u32.hi && t2.u32.lo < t1.u32.lo))
+ {
+ PJ_LOG(3,(THIS_FILE, "...ERROR: timestamp runs backwards!"));
+ return -1003;
+ }
+ }
+
+ /*
+ * Simple test to time some loop.
+ */
+ PJ_LOG(3,(THIS_FILE, "....testing simple 1000000 loop"));
+
+
+ /* Mark start time. */
+ if ((rc=pj_get_timestamp(&t1)) != PJ_SUCCESS) {
+ app_perror("....error: cat't get timestamp", rc);
+ return -1010;
+ }
+
+ /* Loop.. */
+ for (i=0; i<1000000; ++i)
+ ;
+
+ /* Mark end time. */
+ pj_get_timestamp(&t2);
+
+ /* Get elapsed time in usec. */
+ elapsed = pj_elapsed_usec(&t1, &t2);
+ PJ_LOG(3,(THIS_FILE, "....elapsed: %u usec", (unsigned)elapsed));
+
+ /* See if elapsed time is reasonable. */
+ if (elapsed < 1 || elapsed > 100000) {
+ PJ_LOG(3,(THIS_FILE, "....error: elapsed time outside window (%u, "
+ "t1.u32.hi=%u, t1.u32.lo=%u, "
+ "t2.u32.hi=%u, t2.u32.lo=%u)",
+ elapsed,
+ t1.u32.hi, t1.u32.lo, t2.u32.hi, t2.u32.lo));
+ return -1030;
+ }
+ return 0;
+}
+
+
+#else
+/* To prevent warning about "translation unit is empty"
+ * when this test is disabled.
+ */
+int dummy_timestamp_test;
+#endif /* INCLUDE_TIMESTAMP_TEST */
+
diff --git a/pjlib/src/pjlib-test/udp_echo_srv_ioqueue.c b/pjlib/src/pjlib-test/udp_echo_srv_ioqueue.c
index 981ff30e..d9b746dc 100644
--- a/pjlib/src/pjlib-test/udp_echo_srv_ioqueue.c
+++ b/pjlib/src/pjlib-test/udp_echo_srv_ioqueue.c
@@ -1,5 +1,26 @@
/* $Id$
*/
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
#include <pjlib.h>
#include "test.h"
diff --git a/pjlib/src/pjlib-test/udp_echo_srv_sync.c b/pjlib/src/pjlib-test/udp_echo_srv_sync.c
index b1a59e46..c229e614 100644
--- a/pjlib/src/pjlib-test/udp_echo_srv_sync.c
+++ b/pjlib/src/pjlib-test/udp_echo_srv_sync.c
@@ -1,147 +1,168 @@
-/* $Id$
- */
-#include "test.h"
-#include <pjlib.h>
-
-static pj_atomic_t *total_bytes;
-
-static int worker_thread(void *arg)
-{
- pj_sock_t sock = (pj_sock_t)arg;
- char buf[512];
- pj_status_t last_recv_err = PJ_SUCCESS, last_write_err = PJ_SUCCESS;
-
- for (;;) {
- pj_ssize_t len;
- pj_status_t rc;
- pj_sockaddr_in addr;
- int addrlen;
-
- len = sizeof(buf);
- addrlen = sizeof(addr);
- rc = pj_sock_recvfrom(sock, buf, &len, 0, &addr, &addrlen);
- if (rc != 0) {
- if (rc != last_recv_err) {
- app_perror("...recv error", rc);
- last_recv_err = rc;
- }
- continue;
- }
-
- pj_atomic_add(total_bytes, len);
-
- rc = pj_sock_sendto(sock, buf, &len, 0, &addr, addrlen);
- if (rc != PJ_SUCCESS) {
- if (rc != last_write_err) {
- app_perror("...send error", rc);
- last_write_err = rc;
- }
- continue;
- }
- }
-}
-
-
-int echo_srv_sync(void)
-{
- pj_pool_t *pool;
- pj_sock_t sock;
- pj_thread_t *thread[ECHO_SERVER_MAX_THREADS];
- pj_status_t rc;
- int i;
-
- pool = pj_pool_create(mem, NULL, 4000, 4000, NULL);
- if (!pool)
- return -5;
-
- rc = pj_atomic_create(pool, 0, &total_bytes);
- if (rc != PJ_SUCCESS) {
- app_perror("...unable to create atomic_var", rc);
- return -6;
- }
-
- rc = app_socket(PJ_AF_INET, PJ_SOCK_DGRAM,0, ECHO_SERVER_START_PORT, &sock);
- if (rc != PJ_SUCCESS) {
- app_perror("...socket error", rc);
- return -10;
- }
-
- for (i=0; i<ECHO_SERVER_MAX_THREADS; ++i) {
- rc = pj_thread_create(pool, NULL, &worker_thread, (void*)sock,
- PJ_THREAD_DEFAULT_STACK_SIZE, 0,
- &thread[i]);
- if (rc != PJ_SUCCESS) {
- app_perror("...unable to create thread", rc);
- return -20;
- }
- }
-
- PJ_LOG(3,("", "...UDP echo server running with %d threads at port %d",
- ECHO_SERVER_MAX_THREADS, ECHO_SERVER_START_PORT));
- PJ_LOG(3,("", "...Press Ctrl-C to abort"));
-
- echo_srv_common_loop(total_bytes);
- return 0;
-}
-
-
-int echo_srv_common_loop(pj_atomic_t *bytes_counter)
-{
- pj_highprec_t last_received, avg_bw, highest_bw;
- pj_time_val last_print;
- unsigned count;
- const char *ioqueue_name;
-
- last_received = 0;
- pj_gettimeofday(&last_print);
- avg_bw = highest_bw = 0;
- count = 0;
-
- ioqueue_name = pj_ioqueue_name();
-
- for (;;) {
- pj_highprec_t received, cur_received, bw;
- unsigned msec;
- pj_time_val now, duration;
-
- pj_thread_sleep(1000);
-
- received = cur_received = pj_atomic_get(bytes_counter);
- cur_received = cur_received - last_received;
-
- pj_gettimeofday(&now);
- duration = now;
- PJ_TIME_VAL_SUB(duration, last_print);
- msec = PJ_TIME_VAL_MSEC(duration);
-
- bw = cur_received;
- pj_highprec_mul(bw, 1000);
- pj_highprec_div(bw, msec);
-
- last_print = now;
- last_received = received;
-
- avg_bw = avg_bw + bw;
- count++;
-
- PJ_LOG(3,("", "%s UDP (%d threads): %u KB/s (avg=%u KB/s) %s",
- ioqueue_name,
- ECHO_SERVER_MAX_THREADS,
- (unsigned)(bw / 1000),
- (unsigned)(avg_bw / count / 1000),
- (count==20 ? "<ses avg>" : "")));
-
- if (count==20) {
- if (avg_bw/count > highest_bw)
- highest_bw = avg_bw/count;
-
- count = 0;
- avg_bw = 0;
-
- PJ_LOG(3,("", "Highest average bandwidth=%u KB/s",
- (unsigned)(highest_bw/1000)));
- }
- }
-}
-
-
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "test.h"
+#include <pjlib.h>
+
+static pj_atomic_t *total_bytes;
+
+static int worker_thread(void *arg)
+{
+ pj_sock_t sock = (pj_sock_t)arg;
+ char buf[512];
+ pj_status_t last_recv_err = PJ_SUCCESS, last_write_err = PJ_SUCCESS;
+
+ for (;;) {
+ pj_ssize_t len;
+ pj_status_t rc;
+ pj_sockaddr_in addr;
+ int addrlen;
+
+ len = sizeof(buf);
+ addrlen = sizeof(addr);
+ rc = pj_sock_recvfrom(sock, buf, &len, 0, &addr, &addrlen);
+ if (rc != 0) {
+ if (rc != last_recv_err) {
+ app_perror("...recv error", rc);
+ last_recv_err = rc;
+ }
+ continue;
+ }
+
+ pj_atomic_add(total_bytes, len);
+
+ rc = pj_sock_sendto(sock, buf, &len, 0, &addr, addrlen);
+ if (rc != PJ_SUCCESS) {
+ if (rc != last_write_err) {
+ app_perror("...send error", rc);
+ last_write_err = rc;
+ }
+ continue;
+ }
+ }
+}
+
+
+int echo_srv_sync(void)
+{
+ pj_pool_t *pool;
+ pj_sock_t sock;
+ pj_thread_t *thread[ECHO_SERVER_MAX_THREADS];
+ pj_status_t rc;
+ int i;
+
+ pool = pj_pool_create(mem, NULL, 4000, 4000, NULL);
+ if (!pool)
+ return -5;
+
+ rc = pj_atomic_create(pool, 0, &total_bytes);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...unable to create atomic_var", rc);
+ return -6;
+ }
+
+ rc = app_socket(PJ_AF_INET, PJ_SOCK_DGRAM,0, ECHO_SERVER_START_PORT, &sock);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...socket error", rc);
+ return -10;
+ }
+
+ for (i=0; i<ECHO_SERVER_MAX_THREADS; ++i) {
+ rc = pj_thread_create(pool, NULL, &worker_thread, (void*)sock,
+ PJ_THREAD_DEFAULT_STACK_SIZE, 0,
+ &thread[i]);
+ if (rc != PJ_SUCCESS) {
+ app_perror("...unable to create thread", rc);
+ return -20;
+ }
+ }
+
+ PJ_LOG(3,("", "...UDP echo server running with %d threads at port %d",
+ ECHO_SERVER_MAX_THREADS, ECHO_SERVER_START_PORT));
+ PJ_LOG(3,("", "...Press Ctrl-C to abort"));
+
+ echo_srv_common_loop(total_bytes);
+ return 0;
+}
+
+
+int echo_srv_common_loop(pj_atomic_t *bytes_counter)
+{
+ pj_highprec_t last_received, avg_bw, highest_bw;
+ pj_time_val last_print;
+ unsigned count;
+ const char *ioqueue_name;
+
+ last_received = 0;
+ pj_gettimeofday(&last_print);
+ avg_bw = highest_bw = 0;
+ count = 0;
+
+ ioqueue_name = pj_ioqueue_name();
+
+ for (;;) {
+ pj_highprec_t received, cur_received, bw;
+ unsigned msec;
+ pj_time_val now, duration;
+
+ pj_thread_sleep(1000);
+
+ received = cur_received = pj_atomic_get(bytes_counter);
+ cur_received = cur_received - last_received;
+
+ pj_gettimeofday(&now);
+ duration = now;
+ PJ_TIME_VAL_SUB(duration, last_print);
+ msec = PJ_TIME_VAL_MSEC(duration);
+
+ bw = cur_received;
+ pj_highprec_mul(bw, 1000);
+ pj_highprec_div(bw, msec);
+
+ last_print = now;
+ last_received = received;
+
+ avg_bw = avg_bw + bw;
+ count++;
+
+ PJ_LOG(3,("", "%s UDP (%d threads): %u KB/s (avg=%u KB/s) %s",
+ ioqueue_name,
+ ECHO_SERVER_MAX_THREADS,
+ (unsigned)(bw / 1000),
+ (unsigned)(avg_bw / count / 1000),
+ (count==20 ? "<ses avg>" : "")));
+
+ if (count==20) {
+ if (avg_bw/count > highest_bw)
+ highest_bw = avg_bw/count;
+
+ count = 0;
+ avg_bw = 0;
+
+ PJ_LOG(3,("", "Highest average bandwidth=%u KB/s",
+ (unsigned)(highest_bw/1000)));
+ }
+ }
+}
+
+
diff --git a/pjlib/src/pjlib-test/util.c b/pjlib/src/pjlib-test/util.c
index 2d985716..44281e26 100644
--- a/pjlib/src/pjlib-test/util.c
+++ b/pjlib/src/pjlib-test/util.c
@@ -1,115 +1,136 @@
-/* $Id$
- */
-#include "test.h"
-#include <pjlib.h>
-
-void app_perror(const char *msg, pj_status_t rc)
-{
- char errbuf[256];
-
- PJ_CHECK_STACK();
-
- pj_strerror(rc, errbuf, sizeof(errbuf));
- PJ_LOG(1,("test", "%s: [pj_status_t=%d] %s", msg, rc, errbuf));
-}
-
-#define SERVER 0
-#define CLIENT 1
-
-pj_status_t app_socket(int family, int type, int proto, int port,
- pj_sock_t *ptr_sock)
-{
- pj_sockaddr_in addr;
- pj_sock_t sock;
- pj_status_t rc;
-
- rc = pj_sock_socket(family, type, proto, &sock);
- if (rc != PJ_SUCCESS)
- return rc;
-
- pj_memset(&addr, 0, sizeof(addr));
- addr.sin_family = (pj_uint16_t)family;
- addr.sin_port = (short)(port!=-1 ? pj_htons((pj_uint16_t)port) : 0);
- rc = pj_sock_bind(sock, &addr, sizeof(addr));
- if (rc != PJ_SUCCESS)
- return rc;
-
- if (type == PJ_SOCK_STREAM) {
- rc = pj_sock_listen(sock, 5);
- if (rc != PJ_SUCCESS)
- return rc;
- }
-
- *ptr_sock = sock;
- return PJ_SUCCESS;
-}
-
-pj_status_t app_socketpair(int family, int type, int protocol,
- pj_sock_t *serverfd, pj_sock_t *clientfd)
-{
- int i;
- static unsigned short port = 11000;
- pj_sockaddr_in addr;
- pj_str_t s;
- pj_status_t rc = 0;
- pj_sock_t sock[2];
-
- /* Create both sockets. */
- for (i=0; i<2; ++i) {
- rc = pj_sock_socket(family, type, protocol, &sock[i]);
- if (rc != PJ_SUCCESS) {
- if (i==1)
- pj_sock_close(sock[0]);
- return rc;
- }
- }
-
- /* Retry bind */
- pj_memset(&addr, 0, sizeof(addr));
- addr.sin_family = PJ_AF_INET;
- for (i=0; i<5; ++i) {
- addr.sin_port = pj_htons(port++);
- rc = pj_sock_bind(sock[SERVER], &addr, sizeof(addr));
- if (rc == PJ_SUCCESS)
- break;
- }
-
- if (rc != PJ_SUCCESS)
- goto on_error;
-
- /* For TCP, listen the socket. */
- if (type == PJ_SOCK_STREAM) {
- rc = pj_sock_listen(sock[SERVER], PJ_SOMAXCONN);
- if (rc != PJ_SUCCESS)
- goto on_error;
- }
-
- /* Connect client socket. */
- addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));
- rc = pj_sock_connect(sock[CLIENT], &addr, sizeof(addr));
- if (rc != PJ_SUCCESS)
- goto on_error;
-
- /* For TCP, must accept(), and get the new socket. */
- if (type == PJ_SOCK_STREAM) {
- pj_sock_t newserver;
-
- rc = pj_sock_accept(sock[SERVER], &newserver, NULL, NULL);
- if (rc != PJ_SUCCESS)
- goto on_error;
-
- /* Replace server socket with new socket. */
- pj_sock_close(sock[SERVER]);
- sock[SERVER] = newserver;
- }
-
- *serverfd = sock[SERVER];
- *clientfd = sock[CLIENT];
-
- return rc;
-
-on_error:
- for (i=0; i<2; ++i)
- pj_sock_close(sock[i]);
- return rc;
-}
+/* $Id$
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "test.h"
+#include <pjlib.h>
+
+void app_perror(const char *msg, pj_status_t rc)
+{
+ char errbuf[256];
+
+ PJ_CHECK_STACK();
+
+ pj_strerror(rc, errbuf, sizeof(errbuf));
+ PJ_LOG(1,("test", "%s: [pj_status_t=%d] %s", msg, rc, errbuf));
+}
+
+#define SERVER 0
+#define CLIENT 1
+
+pj_status_t app_socket(int family, int type, int proto, int port,
+ pj_sock_t *ptr_sock)
+{
+ pj_sockaddr_in addr;
+ pj_sock_t sock;
+ pj_status_t rc;
+
+ rc = pj_sock_socket(family, type, proto, &sock);
+ if (rc != PJ_SUCCESS)
+ return rc;
+
+ pj_memset(&addr, 0, sizeof(addr));
+ addr.sin_family = (pj_uint16_t)family;
+ addr.sin_port = (short)(port!=-1 ? pj_htons((pj_uint16_t)port) : 0);
+ rc = pj_sock_bind(sock, &addr, sizeof(addr));
+ if (rc != PJ_SUCCESS)
+ return rc;
+
+ if (type == PJ_SOCK_STREAM) {
+ rc = pj_sock_listen(sock, 5);
+ if (rc != PJ_SUCCESS)
+ return rc;
+ }
+
+ *ptr_sock = sock;
+ return PJ_SUCCESS;
+}
+
+pj_status_t app_socketpair(int family, int type, int protocol,
+ pj_sock_t *serverfd, pj_sock_t *clientfd)
+{
+ int i;
+ static unsigned short port = 11000;
+ pj_sockaddr_in addr;
+ pj_str_t s;
+ pj_status_t rc = 0;
+ pj_sock_t sock[2];
+
+ /* Create both sockets. */
+ for (i=0; i<2; ++i) {
+ rc = pj_sock_socket(family, type, protocol, &sock[i]);
+ if (rc != PJ_SUCCESS) {
+ if (i==1)
+ pj_sock_close(sock[0]);
+ return rc;
+ }
+ }
+
+ /* Retry bind */
+ pj_memset(&addr, 0, sizeof(addr));
+ addr.sin_family = PJ_AF_INET;
+ for (i=0; i<5; ++i) {
+ addr.sin_port = pj_htons(port++);
+ rc = pj_sock_bind(sock[SERVER], &addr, sizeof(addr));
+ if (rc == PJ_SUCCESS)
+ break;
+ }
+
+ if (rc != PJ_SUCCESS)
+ goto on_error;
+
+ /* For TCP, listen the socket. */
+ if (type == PJ_SOCK_STREAM) {
+ rc = pj_sock_listen(sock[SERVER], PJ_SOMAXCONN);
+ if (rc != PJ_SUCCESS)
+ goto on_error;
+ }
+
+ /* Connect client socket. */
+ addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));
+ rc = pj_sock_connect(sock[CLIENT], &addr, sizeof(addr));
+ if (rc != PJ_SUCCESS)
+ goto on_error;
+
+ /* For TCP, must accept(), and get the new socket. */
+ if (type == PJ_SOCK_STREAM) {
+ pj_sock_t newserver;
+
+ rc = pj_sock_accept(sock[SERVER], &newserver, NULL, NULL);
+ if (rc != PJ_SUCCESS)
+ goto on_error;
+
+ /* Replace server socket with new socket. */
+ pj_sock_close(sock[SERVER]);
+ sock[SERVER] = newserver;
+ }
+
+ *serverfd = sock[SERVER];
+ *clientfd = sock[CLIENT];
+
+ return rc;
+
+on_error:
+ for (i=0; i<2; ++i)
+ pj_sock_close(sock[i]);
+ return rc;
+}