diff options
Diffstat (limited to 'pjlib')
163 files changed, 34733 insertions, 31322 deletions
diff --git a/pjlib/include/pj++/file.hpp b/pjlib/include/pj++/file.hpp index e45810c5..1c35123a 100644 --- a/pjlib/include/pj++/file.hpp +++ b/pjlib/include/pj++/file.hpp @@ -1,171 +1,192 @@ -/* $Id$ - */ -#ifndef __PJPP_FILE_HPP__ -#define __PJPP_FILE_HPP__ - -#include <pj/file_io.h> -#include <pj/file_access.h> -#include <pj++/types.hpp> -#include <pj++/pool.hpp> - -// -// File API. -// -class Pj_File_API -{ -public: - // - // Check file existance. - // - static bool file_exists(const char *filename) - { - return pj_file_exists(filename) != 0; - } - - // - // Get file size. - // - static pj_off_t file_size(const char *filename) - { - return pj_file_size(filename); - } - - // - // Delete file. - // - static pj_status_t file_delete(const char *filename) - { - return pj_file_delete(filename); - } - - // - // Move/rename file. - // - static pj_status_t file_move(const char *oldname, const char *newname) - { - return pj_file_move(oldname, newname); - } - - // - // Get stat. - // - static pj_status_t file_stat(const char *filename, pj_file_stat *buf) - { - return pj_file_getstat(filename, buf); - } -}; - - -// -// File. -// -class Pj_File : public Pj_Object -{ -public: - // - // Offset type to be used in setpos. - // - enum Offset_Type - { - SEEK_SET = PJ_SEEK_SET, - SEEK_CUR = PJ_SEEK_CUR, - SEEK_END = PJ_SEEK_END, - }; - - // - // Default constructor. - // - Pj_File() - : hnd_(0) - { - } - - // - // Construct and open a file. - // - Pj_File(Pj_Pool *pool, const char *filename, - unsigned access = PJ_O_RDONLY) - : hnd_(NULL) - { - open(pool, filename, access); - } - - // - // Destructor closes the file. - // - ~Pj_File() - { - close(); - } - - // - // Open a file. - // - pj_status_t open(Pj_Pool *pool, const char *filename, - unsigned access = PJ_O_RDONLY ) - { - close(); - return pj_file_open(pool->pool_(), filename, access, &hnd_); - } - - // - // Close a file. - // - void close() - { - if (hnd_ != 0) { - pj_file_close(hnd_); - hnd_ = 0; - } - } - - // - // Write data. - // - pj_ssize_t write(const void *buff, pj_size_t size) - { - pj_ssize_t bytes = size; - if (pj_file_write(hnd_, buff, &bytes) != PJ_SUCCESS) - return -1; - return bytes; - } - - // - // Read data. - // - pj_ssize_t read(void *buf, pj_size_t size) - { - pj_ssize_t bytes = size; - if (pj_file_read(hnd_, buf, &bytes) != PJ_SUCCESS) - return -1; - return bytes; - } - - // - // Set file position. - // - pj_status_t setpos(pj_off_t offset, Offset_Type whence) - { - return pj_file_setpos(hnd_, offset, - (enum pj_file_seek_type)whence); - } - - // - // Get file position. - // - pj_off_t getpos() - { - pj_off_t pos; - if (pj_file_getpos(hnd_, &pos) != PJ_SUCCESS) - return -1; - return pos; - } - -private: - pj_oshandle_t hnd_; -}; - - - -#endif /* __PJPP_FILE_HPP__ */ - +/* $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 __PJPP_FILE_HPP__
+#define __PJPP_FILE_HPP__
+
+#include <pj/file_io.h>
+#include <pj/file_access.h>
+#include <pj++/types.hpp>
+#include <pj++/pool.hpp>
+
+//
+// File API.
+//
+class Pj_File_API
+{
+public:
+ //
+ // Check file existance.
+ //
+ static bool file_exists(const char *filename)
+ {
+ return pj_file_exists(filename) != 0;
+ }
+
+ //
+ // Get file size.
+ //
+ static pj_off_t file_size(const char *filename)
+ {
+ return pj_file_size(filename);
+ }
+
+ //
+ // Delete file.
+ //
+ static pj_status_t file_delete(const char *filename)
+ {
+ return pj_file_delete(filename);
+ }
+
+ //
+ // Move/rename file.
+ //
+ static pj_status_t file_move(const char *oldname, const char *newname)
+ {
+ return pj_file_move(oldname, newname);
+ }
+
+ //
+ // Get stat.
+ //
+ static pj_status_t file_stat(const char *filename, pj_file_stat *buf)
+ {
+ return pj_file_getstat(filename, buf);
+ }
+};
+
+
+//
+// File.
+//
+class Pj_File : public Pj_Object
+{
+public:
+ //
+ // Offset type to be used in setpos.
+ //
+ enum Offset_Type
+ {
+ SEEK_SET = PJ_SEEK_SET,
+ SEEK_CUR = PJ_SEEK_CUR,
+ SEEK_END = PJ_SEEK_END,
+ };
+
+ //
+ // Default constructor.
+ //
+ Pj_File()
+ : hnd_(0)
+ {
+ }
+
+ //
+ // Construct and open a file.
+ //
+ Pj_File(Pj_Pool *pool, const char *filename,
+ unsigned access = PJ_O_RDONLY)
+ : hnd_(NULL)
+ {
+ open(pool, filename, access);
+ }
+
+ //
+ // Destructor closes the file.
+ //
+ ~Pj_File()
+ {
+ close();
+ }
+
+ //
+ // Open a file.
+ //
+ pj_status_t open(Pj_Pool *pool, const char *filename,
+ unsigned access = PJ_O_RDONLY )
+ {
+ close();
+ return pj_file_open(pool->pool_(), filename, access, &hnd_);
+ }
+
+ //
+ // Close a file.
+ //
+ void close()
+ {
+ if (hnd_ != 0) {
+ pj_file_close(hnd_);
+ hnd_ = 0;
+ }
+ }
+
+ //
+ // Write data.
+ //
+ pj_ssize_t write(const void *buff, pj_size_t size)
+ {
+ pj_ssize_t bytes = size;
+ if (pj_file_write(hnd_, buff, &bytes) != PJ_SUCCESS)
+ return -1;
+ return bytes;
+ }
+
+ //
+ // Read data.
+ //
+ pj_ssize_t read(void *buf, pj_size_t size)
+ {
+ pj_ssize_t bytes = size;
+ if (pj_file_read(hnd_, buf, &bytes) != PJ_SUCCESS)
+ return -1;
+ return bytes;
+ }
+
+ //
+ // Set file position.
+ //
+ pj_status_t setpos(pj_off_t offset, Offset_Type whence)
+ {
+ return pj_file_setpos(hnd_, offset,
+ (enum pj_file_seek_type)whence);
+ }
+
+ //
+ // Get file position.
+ //
+ pj_off_t getpos()
+ {
+ pj_off_t pos;
+ if (pj_file_getpos(hnd_, &pos) != PJ_SUCCESS)
+ return -1;
+ return pos;
+ }
+
+private:
+ pj_oshandle_t hnd_;
+};
+
+
+
+#endif /* __PJPP_FILE_HPP__ */
+
diff --git a/pjlib/include/pj++/hash.hpp b/pjlib/include/pj++/hash.hpp index 691ac3a8..c362625b 100644 --- a/pjlib/include/pj++/hash.hpp +++ b/pjlib/include/pj++/hash.hpp @@ -1,139 +1,160 @@ -/* $Id$ - */ -#ifndef __PJPP_HASH_HPP__ -#define __PJPP_HASH_HPP__ - -#include <pj++/types.hpp> -#include <pj++/pool.hpp> -#include <pj/hash.h> - -// -// Hash table. -// -class Pj_Hash_Table : public Pj_Object -{ -public: - // - // Hash table iterator. - // - class iterator - { - public: - iterator() - { - } - explicit iterator(pj_hash_table_t *h, pj_hash_iterator_t *i) - : ht_(h), it_(i) - { - } - iterator(const iterator &rhs) - : ht_(rhs.ht_), it_(rhs.it_) - { - } - void operator++() - { - it_ = pj_hash_next(ht_, it_); - } - bool operator==(const iterator &rhs) - { - return ht_ == rhs.ht_ && it_ == rhs.it_; - } - iterator & operator=(const iterator &rhs) - { - ht_=rhs.ht_; it_=rhs.it_; - return *this; - } - private: - pj_hash_table_t *ht_; - pj_hash_iterator_t it_val_; - pj_hash_iterator_t *it_; - - friend class Pj_Hash_Table; - }; - - // - // Construct hash table. - // - Pj_Hash_Table(Pj_Pool *pool, unsigned size) - { - table_ = pj_hash_create(pool->pool_(), size); - } - - // - // Destroy hash table. - // - ~Pj_Hash_Table() - { - } - - // - // Calculate hash value. - // - static pj_uint32_t calc( pj_uint32_t initial_hval, - const void *key, - unsigned keylen = PJ_HASH_KEY_STRING) - { - return pj_hash_calc(initial_hval, key, keylen); - } - - // - // Return pjlib compatible hash table object. - // - pj_hash_table_t *pj_hash_table_t_() - { - return table_; - } - - // - // Get the value associated with the specified key. - // - void *get(const void *key, unsigned keylen = PJ_HASH_KEY_STRING) - { - return pj_hash_get(table_, key, keylen); - } - - // - // Associate a value with a key. - // Set the value to NULL to delete the key from the hash table. - // - void set(Pj_Pool *pool, - const void *key, - void *value, - unsigned keylen = PJ_HASH_KEY_STRING) - { - pj_hash_set(pool->pool_(), table_, key, keylen, value); - } - - // - // Get number of items in the hash table. - // - unsigned count() - { - return pj_hash_count(table_); - } - - // - // Iterate hash table. - // - iterator begin() - { - iterator it(table_, NULL); - it.it_ = pj_hash_first(table_, &it.it_val_); - return it; - } - - // - // End of items. - // - iterator end() - { - return iterator(table_, NULL); - } - -private: - pj_hash_table_t *table_; -}; - - -#endif /* __PJPP_HASH_HPP__ */ - +/* $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 __PJPP_HASH_HPP__
+#define __PJPP_HASH_HPP__
+
+#include <pj++/types.hpp>
+#include <pj++/pool.hpp>
+#include <pj/hash.h>
+
+//
+// Hash table.
+//
+class Pj_Hash_Table : public Pj_Object
+{
+public:
+ //
+ // Hash table iterator.
+ //
+ class iterator
+ {
+ public:
+ iterator()
+ {
+ }
+ explicit iterator(pj_hash_table_t *h, pj_hash_iterator_t *i)
+ : ht_(h), it_(i)
+ {
+ }
+ iterator(const iterator &rhs)
+ : ht_(rhs.ht_), it_(rhs.it_)
+ {
+ }
+ void operator++()
+ {
+ it_ = pj_hash_next(ht_, it_);
+ }
+ bool operator==(const iterator &rhs)
+ {
+ return ht_ == rhs.ht_ && it_ == rhs.it_;
+ }
+ iterator & operator=(const iterator &rhs)
+ {
+ ht_=rhs.ht_; it_=rhs.it_;
+ return *this;
+ }
+ private:
+ pj_hash_table_t *ht_;
+ pj_hash_iterator_t it_val_;
+ pj_hash_iterator_t *it_;
+
+ friend class Pj_Hash_Table;
+ };
+
+ //
+ // Construct hash table.
+ //
+ Pj_Hash_Table(Pj_Pool *pool, unsigned size)
+ {
+ table_ = pj_hash_create(pool->pool_(), size);
+ }
+
+ //
+ // Destroy hash table.
+ //
+ ~Pj_Hash_Table()
+ {
+ }
+
+ //
+ // Calculate hash value.
+ //
+ static pj_uint32_t calc( pj_uint32_t initial_hval,
+ const void *key,
+ unsigned keylen = PJ_HASH_KEY_STRING)
+ {
+ return pj_hash_calc(initial_hval, key, keylen);
+ }
+
+ //
+ // Return pjlib compatible hash table object.
+ //
+ pj_hash_table_t *pj_hash_table_t_()
+ {
+ return table_;
+ }
+
+ //
+ // Get the value associated with the specified key.
+ //
+ void *get(const void *key, unsigned keylen = PJ_HASH_KEY_STRING)
+ {
+ return pj_hash_get(table_, key, keylen);
+ }
+
+ //
+ // Associate a value with a key.
+ // Set the value to NULL to delete the key from the hash table.
+ //
+ void set(Pj_Pool *pool,
+ const void *key,
+ void *value,
+ unsigned keylen = PJ_HASH_KEY_STRING)
+ {
+ pj_hash_set(pool->pool_(), table_, key, keylen, value);
+ }
+
+ //
+ // Get number of items in the hash table.
+ //
+ unsigned count()
+ {
+ return pj_hash_count(table_);
+ }
+
+ //
+ // Iterate hash table.
+ //
+ iterator begin()
+ {
+ iterator it(table_, NULL);
+ it.it_ = pj_hash_first(table_, &it.it_val_);
+ return it;
+ }
+
+ //
+ // End of items.
+ //
+ iterator end()
+ {
+ return iterator(table_, NULL);
+ }
+
+private:
+ pj_hash_table_t *table_;
+};
+
+
+#endif /* __PJPP_HASH_HPP__ */
+
diff --git a/pjlib/include/pj++/list.hpp b/pjlib/include/pj++/list.hpp index c3a8f386..363c1fad 100644 --- a/pjlib/include/pj++/list.hpp +++ b/pjlib/include/pj++/list.hpp @@ -1,311 +1,332 @@ -/* $Id$ - */ -#ifndef __PJPP_LIST_HPP__ -#define __PJPP_LIST_HPP__ - -#include <pj/list.h> -#include <pj++/pool.hpp> - - -// -// Linked-list. -// -// Note: -// List_Node must have public member next and prev. Normally -// it will be declared like: -// -// struct my_node -// { -// PJ_DECL_LIST_MEMBER(struct my_node); -// .. -// }; -// -// -template <class List_Node> -class Pj_List : public Pj_Object -{ -public: - // - // List const_iterator. - // - class const_iterator - { - public: - const_iterator() - : node_(NULL) - {} - const_iterator(const List_Node *nd) - : node_((List_Node*)nd) - {} - const List_Node * operator *() - { - return node_; - } - const List_Node * operator -> () - { - return node_; - } - const_iterator operator++() - { - return const_iterator(node_->next); - } - bool operator==(const const_iterator &rhs) - { - return node_ == rhs.node_; - } - bool operator!=(const const_iterator &rhs) - { - return node_ != rhs.node_; - } - - protected: - List_Node *node_; - }; - - // - // List iterator. - // - class iterator : public const_iterator - { - public: - iterator() - {} - iterator(List_Node *nd) - : const_iterator(nd) - {} - List_Node * operator *() - { - return node_; - } - List_Node * operator -> () - { - return node_; - } - iterator operator++() - { - return iterator(node_->next); - } - bool operator==(const iterator &rhs) - { - return node_ == rhs.node_; - } - bool operator!=(const iterator &rhs) - { - return node_ != rhs.node_; - } - }; - - // - // Default constructor. - // - Pj_List() - { - pj_list_init(&root_); - if (0) compiletest(); - } - - // - // Check if list is empty. - // - bool empty() const - { - return pj_list_empty(&root_); - } - - // - // Get first element. - // - iterator begin() - { - return iterator(root_.next); - } - - // - // Get first element. - // - const_iterator begin() const - { - return const_iterator(root_.next); - } - - // - // Get end-of-element - // - const_iterator end() const - { - return const_iterator((List_Node*)&root_); - } - - // - // Get end-of-element - // - iterator end() - { - return iterator((List_Node*)&root_); - } - - // - // Insert node. - // - void insert_before (iterator &pos, List_Node *node) - { - pj_list_insert_before( *pos, node ); - } - - // - // Insert node. - // - void insert_after(iterator &pos, List_Node *node) - { - pj_list_insert_after(*pos, node); - } - - // - // Merge list. - // - void merge_first(List_Node *list2) - { - pj_list_merge_first(&root_, list2); - } - - // - // Merge list. - // - void merge_last(Pj_List *list) - { - pj_list_merge_last(&root_, &list->root_); - } - - // - // Insert list. - // - void insert_nodes_before(iterator &pos, Pj_List *list2) - { - pj_list_insert_nodes_before(*pos, &list2->root_); - } - - // - // Insert list. - // - void insert_nodes_after(iterator &pos, Pj_List *list2) - { - pj_list_insert_nodes_after(*pos, &list2->root_); - } - - // - // Erase an element. - // - void erase(iterator &it) - { - pj_list_erase(*it); - } - - // - // Get first element. - // - List_Node *front() - { - return root_.next; - } - - // - // Get first element. - // - const List_Node *front() const - { - return root_.next; - } - - // - // Remove first element. - // - void pop_front() - { - pj_list_erase(root_.next); - } - - // - // Get last element. - // - List_Node *back() - { - return root_.prev; - } - - // - // Get last element. - // - const List_Node *back() const - { - return root_.prev; - } - - // - // Remove last element. - // - void pop_back() - { - pj_list_erase(root_.prev); - } - - // - // Find a node. - // - iterator find(List_Node *node) - { - List_Node *n = pj_list_find_node(&root_, node); - return n ? iterator(n) : end(); - } - - // - // Find a node. - // - const_iterator find(List_Node *node) const - { - List_Node *n = pj_list_find_node(&root_, node); - return n ? const_iterator(n) : end(); - } - - // - // Insert a node in the back. - // - void push_back(List_Node *node) - { - pj_list_insert_after(root_.prev, node); - } - - // - // Insert a node in the front. - // - void push_front(List_Node *node) - { - pj_list_insert_before(root_.next, node); - } - - // - // Remove all elements. - // - void clear() - { - root_.next = &root_; - root_.prev = &root_; - } - -private: - struct RootNode - { - PJ_DECL_LIST_MEMBER(List_Node); - } root_; - - void compiletest() - { - // If you see error in this line, - // it's because List_Node is not derived from Pj_List_Node. - List_Node *n = (List_Node*)0; - n = n->next; n = n->prev; - } -}; - - -#endif /* __PJPP_LIST_HPP__ */ - +/* $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 __PJPP_LIST_HPP__
+#define __PJPP_LIST_HPP__
+
+#include <pj/list.h>
+#include <pj++/pool.hpp>
+
+
+//
+// Linked-list.
+//
+// Note:
+// List_Node must have public member next and prev. Normally
+// it will be declared like:
+//
+// struct my_node
+// {
+// PJ_DECL_LIST_MEMBER(struct my_node);
+// ..
+// };
+//
+//
+template <class List_Node>
+class Pj_List : public Pj_Object
+{
+public:
+ //
+ // List const_iterator.
+ //
+ class const_iterator
+ {
+ public:
+ const_iterator()
+ : node_(NULL)
+ {}
+ const_iterator(const List_Node *nd)
+ : node_((List_Node*)nd)
+ {}
+ const List_Node * operator *()
+ {
+ return node_;
+ }
+ const List_Node * operator -> ()
+ {
+ return node_;
+ }
+ const_iterator operator++()
+ {
+ return const_iterator(node_->next);
+ }
+ bool operator==(const const_iterator &rhs)
+ {
+ return node_ == rhs.node_;
+ }
+ bool operator!=(const const_iterator &rhs)
+ {
+ return node_ != rhs.node_;
+ }
+
+ protected:
+ List_Node *node_;
+ };
+
+ //
+ // List iterator.
+ //
+ class iterator : public const_iterator
+ {
+ public:
+ iterator()
+ {}
+ iterator(List_Node *nd)
+ : const_iterator(nd)
+ {}
+ List_Node * operator *()
+ {
+ return node_;
+ }
+ List_Node * operator -> ()
+ {
+ return node_;
+ }
+ iterator operator++()
+ {
+ return iterator(node_->next);
+ }
+ bool operator==(const iterator &rhs)
+ {
+ return node_ == rhs.node_;
+ }
+ bool operator!=(const iterator &rhs)
+ {
+ return node_ != rhs.node_;
+ }
+ };
+
+ //
+ // Default constructor.
+ //
+ Pj_List()
+ {
+ pj_list_init(&root_);
+ if (0) compiletest();
+ }
+
+ //
+ // Check if list is empty.
+ //
+ bool empty() const
+ {
+ return pj_list_empty(&root_);
+ }
+
+ //
+ // Get first element.
+ //
+ iterator begin()
+ {
+ return iterator(root_.next);
+ }
+
+ //
+ // Get first element.
+ //
+ const_iterator begin() const
+ {
+ return const_iterator(root_.next);
+ }
+
+ //
+ // Get end-of-element
+ //
+ const_iterator end() const
+ {
+ return const_iterator((List_Node*)&root_);
+ }
+
+ //
+ // Get end-of-element
+ //
+ iterator end()
+ {
+ return iterator((List_Node*)&root_);
+ }
+
+ //
+ // Insert node.
+ //
+ void insert_before (iterator &pos, List_Node *node)
+ {
+ pj_list_insert_before( *pos, node );
+ }
+
+ //
+ // Insert node.
+ //
+ void insert_after(iterator &pos, List_Node *node)
+ {
+ pj_list_insert_after(*pos, node);
+ }
+
+ //
+ // Merge list.
+ //
+ void merge_first(List_Node *list2)
+ {
+ pj_list_merge_first(&root_, list2);
+ }
+
+ //
+ // Merge list.
+ //
+ void merge_last(Pj_List *list)
+ {
+ pj_list_merge_last(&root_, &list->root_);
+ }
+
+ //
+ // Insert list.
+ //
+ void insert_nodes_before(iterator &pos, Pj_List *list2)
+ {
+ pj_list_insert_nodes_before(*pos, &list2->root_);
+ }
+
+ //
+ // Insert list.
+ //
+ void insert_nodes_after(iterator &pos, Pj_List *list2)
+ {
+ pj_list_insert_nodes_after(*pos, &list2->root_);
+ }
+
+ //
+ // Erase an element.
+ //
+ void erase(iterator &it)
+ {
+ pj_list_erase(*it);
+ }
+
+ //
+ // Get first element.
+ //
+ List_Node *front()
+ {
+ return root_.next;
+ }
+
+ //
+ // Get first element.
+ //
+ const List_Node *front() const
+ {
+ return root_.next;
+ }
+
+ //
+ // Remove first element.
+ //
+ void pop_front()
+ {
+ pj_list_erase(root_.next);
+ }
+
+ //
+ // Get last element.
+ //
+ List_Node *back()
+ {
+ return root_.prev;
+ }
+
+ //
+ // Get last element.
+ //
+ const List_Node *back() const
+ {
+ return root_.prev;
+ }
+
+ //
+ // Remove last element.
+ //
+ void pop_back()
+ {
+ pj_list_erase(root_.prev);
+ }
+
+ //
+ // Find a node.
+ //
+ iterator find(List_Node *node)
+ {
+ List_Node *n = pj_list_find_node(&root_, node);
+ return n ? iterator(n) : end();
+ }
+
+ //
+ // Find a node.
+ //
+ const_iterator find(List_Node *node) const
+ {
+ List_Node *n = pj_list_find_node(&root_, node);
+ return n ? const_iterator(n) : end();
+ }
+
+ //
+ // Insert a node in the back.
+ //
+ void push_back(List_Node *node)
+ {
+ pj_list_insert_after(root_.prev, node);
+ }
+
+ //
+ // Insert a node in the front.
+ //
+ void push_front(List_Node *node)
+ {
+ pj_list_insert_before(root_.next, node);
+ }
+
+ //
+ // Remove all elements.
+ //
+ void clear()
+ {
+ root_.next = &root_;
+ root_.prev = &root_;
+ }
+
+private:
+ struct RootNode
+ {
+ PJ_DECL_LIST_MEMBER(List_Node);
+ } root_;
+
+ void compiletest()
+ {
+ // If you see error in this line,
+ // it's because List_Node is not derived from Pj_List_Node.
+ List_Node *n = (List_Node*)0;
+ n = n->next; n = n->prev;
+ }
+};
+
+
+#endif /* __PJPP_LIST_HPP__ */
+
diff --git a/pjlib/include/pj++/lock.hpp b/pjlib/include/pj++/lock.hpp index 95ea63b6..cf5a57da 100644 --- a/pjlib/include/pj++/lock.hpp +++ b/pjlib/include/pj++/lock.hpp @@ -1,132 +1,153 @@ -/* $Id$ - */ -#ifndef __PJPP_LOCK_HPP__ -#define __PJPP_LOCK_HPP__ - -#include <pj++/types.hpp> -#include <pj/lock.h> -#include <pj++/pool.hpp> - -////////////////////////////////////////////////////////////////////////////// -// Lock object. -// -class Pj_Lock : public Pj_Object -{ -public: - // - // Constructor. - // - explicit Pj_Lock(pj_lock_t *lock) - : lock_(lock) - { - } - - // - // Destructor. - // - ~Pj_Lock() - { - if (lock_) - pj_lock_destroy(lock_); - } - - // - // Get pjlib compatible lock object. - // - pj_lock_t *pj_lock_t_() - { - return lock_; - } - - // - // acquire lock. - // - pj_status_t acquire() - { - return pj_lock_acquire(lock_); - } - - // - // release lock,. - // - pj_status_t release() - { - return pj_lock_release(lock_); - } - -protected: - pj_lock_t *lock_; -}; - - -////////////////////////////////////////////////////////////////////////////// -// Null lock object. -// -class Pj_Null_Lock : public Pj_Lock -{ -public: - // - // Default constructor. - // - explicit Pj_Null_Lock(Pj_Pool *pool, const char *name = NULL) - : Pj_Lock(NULL) - { - pj_lock_create_null_mutex(pool->pool_(), name, &lock_); - } -}; - -////////////////////////////////////////////////////////////////////////////// -// Simple mutex lock object. -// -class Pj_Simple_Mutex_Lock : public Pj_Lock -{ -public: - // - // Default constructor. - // - explicit Pj_Simple_Mutex_Lock(Pj_Pool *pool, const char *name = NULL) - : Pj_Lock(NULL) - { - pj_lock_create_simple_mutex(pool->pool_(), name, &lock_); - } -}; - -////////////////////////////////////////////////////////////////////////////// -// Recursive mutex lock object. -// -class Pj_Recursive_Mutex_Lock : public Pj_Lock -{ -public: - // - // Default constructor. - // - explicit Pj_Recursive_Mutex_Lock(Pj_Pool *pool, const char *name = NULL) - : Pj_Lock(NULL) - { - pj_lock_create_recursive_mutex(pool->pool_(), name, &lock_); - } -}; - -////////////////////////////////////////////////////////////////////////////// -// Semaphore lock object. -// -class Pj_Semaphore_Lock : public Pj_Lock -{ -public: - // - // Default constructor. - // - explicit Pj_Semaphore_Lock(Pj_Pool *pool, - unsigned max=PJ_MAXINT32, - unsigned initial=0, - const char *name=NULL) - : Pj_Lock(NULL) - { - pj_lock_create_semaphore(pool->pool_(), name, initial, max, &lock_); - } -}; - - - -#endif /* __PJPP_LOCK_HPP__ */ - +/* $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 __PJPP_LOCK_HPP__
+#define __PJPP_LOCK_HPP__
+
+#include <pj++/types.hpp>
+#include <pj/lock.h>
+#include <pj++/pool.hpp>
+
+//////////////////////////////////////////////////////////////////////////////
+// Lock object.
+//
+class Pj_Lock : public Pj_Object
+{
+public:
+ //
+ // Constructor.
+ //
+ explicit Pj_Lock(pj_lock_t *lock)
+ : lock_(lock)
+ {
+ }
+
+ //
+ // Destructor.
+ //
+ ~Pj_Lock()
+ {
+ if (lock_)
+ pj_lock_destroy(lock_);
+ }
+
+ //
+ // Get pjlib compatible lock object.
+ //
+ pj_lock_t *pj_lock_t_()
+ {
+ return lock_;
+ }
+
+ //
+ // acquire lock.
+ //
+ pj_status_t acquire()
+ {
+ return pj_lock_acquire(lock_);
+ }
+
+ //
+ // release lock,.
+ //
+ pj_status_t release()
+ {
+ return pj_lock_release(lock_);
+ }
+
+protected:
+ pj_lock_t *lock_;
+};
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Null lock object.
+//
+class Pj_Null_Lock : public Pj_Lock
+{
+public:
+ //
+ // Default constructor.
+ //
+ explicit Pj_Null_Lock(Pj_Pool *pool, const char *name = NULL)
+ : Pj_Lock(NULL)
+ {
+ pj_lock_create_null_mutex(pool->pool_(), name, &lock_);
+ }
+};
+
+//////////////////////////////////////////////////////////////////////////////
+// Simple mutex lock object.
+//
+class Pj_Simple_Mutex_Lock : public Pj_Lock
+{
+public:
+ //
+ // Default constructor.
+ //
+ explicit Pj_Simple_Mutex_Lock(Pj_Pool *pool, const char *name = NULL)
+ : Pj_Lock(NULL)
+ {
+ pj_lock_create_simple_mutex(pool->pool_(), name, &lock_);
+ }
+};
+
+//////////////////////////////////////////////////////////////////////////////
+// Recursive mutex lock object.
+//
+class Pj_Recursive_Mutex_Lock : public Pj_Lock
+{
+public:
+ //
+ // Default constructor.
+ //
+ explicit Pj_Recursive_Mutex_Lock(Pj_Pool *pool, const char *name = NULL)
+ : Pj_Lock(NULL)
+ {
+ pj_lock_create_recursive_mutex(pool->pool_(), name, &lock_);
+ }
+};
+
+//////////////////////////////////////////////////////////////////////////////
+// Semaphore lock object.
+//
+class Pj_Semaphore_Lock : public Pj_Lock
+{
+public:
+ //
+ // Default constructor.
+ //
+ explicit Pj_Semaphore_Lock(Pj_Pool *pool,
+ unsigned max=PJ_MAXINT32,
+ unsigned initial=0,
+ const char *name=NULL)
+ : Pj_Lock(NULL)
+ {
+ pj_lock_create_semaphore(pool->pool_(), name, initial, max, &lock_);
+ }
+};
+
+
+
+#endif /* __PJPP_LOCK_HPP__ */
+
diff --git a/pjlib/include/pj++/os.hpp b/pjlib/include/pj++/os.hpp index 461a36e8..65553b00 100644 --- a/pjlib/include/pj++/os.hpp +++ b/pjlib/include/pj++/os.hpp @@ -1,788 +1,809 @@ -/* $Id$ - */ -#ifndef __PJPP_OS_HPP__ -#define __PJPP_OS_HPP__ - -#include <pj/os.h> -#include <pj++/types.hpp> -#include <pj++/pool.hpp> - -class Pj_Thread; - -// -// Thread API. -// -class Pj_Thread_API -{ -public: - // - // Create a thread. - // - static pj_status_t create( Pj_Pool *pool, pj_thread_t **thread, - pj_thread_proc *proc, void *arg, - unsigned flags = 0, - const char *name = NULL, - pj_size_t stack_size = 0 ) - { - return pj_thread_create(pool->pool_(), name, proc, arg, stack_size, - flags, thread); - } - - // - // Register a thread. - // - static pj_status_t register_this_thread( pj_thread_desc desc, - pj_thread_t **thread, - const char *name = NULL ) - { - return pj_thread_register( name, desc, thread ); - } - - // - // Get current thread. - // Will return pj_thread_t (sorry folks, not Pj_Thread). - // - static pj_thread_t *this_thread() - { - return pj_thread_this(); - } - - // - // Get thread name. - // - static const char *get_name(pj_thread_t *thread) - { - return pj_thread_get_name(thread); - } - - // - // Resume thread. - // - static pj_status_t resume(pj_thread_t *thread) - { - return pj_thread_resume(thread); - } - - // - // Sleep. - // - static pj_status_t sleep(unsigned msec) - { - return pj_thread_sleep(msec); - } - - // - // Join the specified thread. - // - static pj_status_t join(pj_thread_t *thread) - { - return pj_thread_join(thread); - } - - // - // Destroy thread - // - static pj_status_t destroy(pj_thread_t *thread) - { - return pj_thread_destroy(thread); - } -}; - - - -// -// Thread object. -// -// How to use: -// Derive a class from this class, then override main(). -// -class Pj_Thread : public Pj_Object -{ -public: - enum Flags - { - FLAG_SUSPENDED = PJ_THREAD_SUSPENDED - }; - - // - // Default constructor. - // - Pj_Thread() - : thread_(NULL) - { - } - - // - // Destroy thread. - // - ~Pj_Thread() - { - destroy(); - } - - // - // This is the main thread function. - // - virtual int main() = 0; - - // - // Start a thread. - // - pj_status_t create( Pj_Pool *pool, - unsigned flags = 0, - const char *thread_name = NULL, - pj_size_t stack_size = PJ_THREAD_DEFAULT_STACK_SIZE) - { - destroy(); - return Pj_Thread_API::create( pool, &thread_, &thread_proc, this, - flags, thread_name); - } - - // - // Get pjlib compatible thread object. - // - pj_thread_t *pj_thread_t_() - { - return thread_; - } - - // - // Get thread name. - // - const char *get_name() - { - return Pj_Thread_API::get_name(thread_); - } - - // - // Resume a suspended thread. - // - pj_status_t resume() - { - return Pj_Thread_API::resume(thread_); - } - - // - // Join this thread. - // - pj_status_t join() - { - return Pj_Thread_API::join(thread_); - } - - // - // Destroy thread. - // - pj_status_t destroy() - { - if (thread_) { - Pj_Thread_API::destroy(thread_); - thread_ = NULL; - } - } - -protected: - pj_thread_t *thread_; - - static int PJ_THREAD_FUNC thread_proc(void *obj) - { - Pj_Thread *thread_class = (Pj_Thread*)obj; - return thread_class->main(); - } -}; - - -// -// External Thread -// (threads that were started by external means, i.e. not -// with Pj_Thread::create). -// -// This class will normally be defined as local variable in -// external thread's stack, normally inside thread's main proc. -// But be aware that the handle will be destroyed on destructor! -// -class Pj_External_Thread : public Pj_Thread -{ -public: - Pj_External_Thread() - { - } - - // - // Register external thread so that pjlib functions can work - // in that thread. - // - pj_status_t register_this_thread( const char *name=NULL ) - { - return Pj_Thread_API::register_this_thread(desc_, &thread_,name); - } - -private: - pj_thread_desc desc_; -}; - - -// -// Thread specific data/thread local storage/TLS. -// -class Pj_Thread_Local_API -{ -public: - // - // Allocate thread local storage (TLS) index. - // - static pj_status_t alloc(long *index) - { - return pj_thread_local_alloc(index); - } - - // - // Free TLS index. - // - static void free(long index) - { - pj_thread_local_free(index); - } - - // - // Set thread specific data. - // - static pj_status_t set(long index, void *value) - { - return pj_thread_local_set(index, value); - } - - // - // Get thread specific data. - // - static void *get(long index) - { - return pj_thread_local_get(index); - } - -}; - -// -// Atomic variable -// -// How to use: -// Pj_Atomic_Var var(pool, 0); -// var.set(..); -// -class Pj_Atomic_Var : public Pj_Object -{ -public: - // - // Default constructor, initialize variable with NULL. - // - Pj_Atomic_Var() - : var_(NULL) - { - } - - // - // Construct atomic variable. - // - Pj_Atomic_Var(Pj_Pool *pool, pj_atomic_value_t value) - : var_(NULL) - { - create(pool, value); - } - - // - // Destructor. - // - ~Pj_Atomic_Var() - { - destroy(); - } - - // - // Create atomic variable. - // - pj_status_t create( Pj_Pool *pool, pj_atomic_value_t value) - { - destroy(); - return pj_atomic_create(pool->pool_(), value, &var_); - } - - // - // Destroy. - // - void destroy() - { - if (var_) { - pj_atomic_destroy(var_); - var_ = NULL; - } - } - - // - // Get pjlib compatible atomic variable. - // - pj_atomic_t *pj_atomic_t_() - { - return var_; - } - - // - // Set the value. - // - void set(pj_atomic_value_t val) - { - pj_atomic_set(var_, val); - } - - // - // Get the value. - // - pj_atomic_value_t get() - { - return pj_atomic_get(var_); - } - - // - // Increment. - // - void inc() - { - pj_atomic_inc(var_); - } - - // - // Increment and get the result. - // - pj_atomic_value_t inc_and_get() - { - return pj_atomic_inc_and_get(var_); - } - - // - // Decrement. - // - void dec() - { - pj_atomic_dec(var_); - } - - // - // Decrement and get the result. - // - pj_atomic_value_t dec_and_get() - { - return pj_atomic_dec_and_get(var_); - } - - // - // Add the variable. - // - void add(pj_atomic_value_t value) - { - pj_atomic_add(var_, value); - } - - // - // Add the variable and get the value. - // - pj_atomic_value_t add_and_get(pj_atomic_value_t value) - { - return pj_atomic_add_and_get(var_, value ); - } - -private: - pj_atomic_t *var_; -}; - - -// -// Mutex -// -class Pj_Mutex : public Pj_Object -{ -public: - // - // Mutex type. - // - enum Type - { - DEFAULT = PJ_MUTEX_DEFAULT, - SIMPLE = PJ_MUTEX_SIMPLE, - RECURSE = PJ_MUTEX_RECURSE, - }; - - // - // Default constructor will create default mutex. - // - explicit Pj_Mutex(Pj_Pool *pool, Type type = DEFAULT, - const char *name = NULL) - : mutex_(NULL) - { - create(pool, type, name); - } - - // - // Destructor. - // - ~Pj_Mutex() - { - destroy(); - } - - // - // Create mutex. - // - pj_status_t create( Pj_Pool *pool, Type type, const char *name = NULL) - { - destroy(); - return pj_mutex_create( pool->pool_(), name, type, - &mutex_ ); - } - - // - // Create simple mutex. - // - pj_status_t create_simple( Pj_Pool *pool,const char *name = NULL) - { - return create(pool, SIMPLE, name); - } - - // - // Create recursive mutex. - // - pj_status_t create_recursive( Pj_Pool *pool, const char *name = NULL ) - { - return create(pool, RECURSE, name); - } - - // - // Get pjlib compatible mutex object. - // - pj_mutex_t *pj_mutex_t_() - { - return mutex_; - } - - // - // Destroy mutex. - // - void destroy() - { - if (mutex_) { - pj_mutex_destroy(mutex_); - mutex_ = NULL; - } - } - - // - // Lock mutex. - // - pj_status_t acquire() - { - return pj_mutex_lock(mutex_); - } - - // - // Unlock mutex. - // - pj_status_t release() - { - return pj_mutex_unlock(mutex_); - } - - // - // Try locking the mutex. - // - pj_status_t tryacquire() - { - return pj_mutex_trylock(mutex_); - } - -private: - pj_mutex_t *mutex_; -}; - - -// -// Semaphore -// -class Pj_Semaphore : public Pj_Object -{ -public: - // - // Construct semaphore - // - Pj_Semaphore(Pj_Pool *pool, unsigned max, - unsigned initial = 0, const char *name = NULL) - : sem_(NULL) - { - } - - // - // Destructor. - // - ~Pj_Semaphore() - { - destroy(); - } - - // - // Create semaphore - // - pj_status_t create( Pj_Pool *pool, unsigned max, - unsigned initial = 0, const char *name = NULL ) - { - destroy(); - return pj_sem_create( pool->pool_(), name, initial, max, &sem_); - } - - // - // Destroy semaphore. - // - void destroy() - { - if (sem_) { - pj_sem_destroy(sem_); - sem_ = NULL; - } - } - - // - // Get pjlib compatible semaphore object. - // - pj_sem_t *pj_sem_t_() - { - return (pj_sem_t*)this; - } - - // - // Wait semaphore. - // - pj_status_t wait() - { - return pj_sem_wait(this->pj_sem_t_()); - } - - // - // Wait semaphore. - // - pj_status_t acquire() - { - return wait(); - } - - // - // Try wait semaphore. - // - pj_status_t trywait() - { - return pj_sem_trywait(this->pj_sem_t_()); - } - - // - // Try wait semaphore. - // - pj_status_t tryacquire() - { - return trywait(); - } - - // - // Post semaphore. - // - pj_status_t post() - { - return pj_sem_post(this->pj_sem_t_()); - } - - // - // Post semaphore. - // - pj_status_t release() - { - return post(); - } - -private: - pj_sem_t *sem_; -}; - - -// -// Event object. -// -class Pj_Event -{ -public: - // - // Construct event object. - // - Pj_Event( Pj_Pool *pool, bool manual_reset = false, - bool initial = false, const char *name = NULL ) - : event_(NULL) - { - create(pool, manual_reset, initial, name); - } - - // - // Destructor. - // - ~Pj_Event() - { - destroy(); - } - - // - // Create event object. - // - pj_status_t create( Pj_Pool *pool, bool manual_reset = false, - bool initial = false, const char *name = NULL) - { - destroy(); - return pj_event_create(pool->pool_(), name, manual_reset, initial, - &event_); - } - - // - // Get pjlib compatible event object. - // - pj_event_t *pj_event_t_() - { - return event_; - } - - // - // Destroy event object. - // - void destroy() - { - if (event_) { - pj_event_destroy(event_); - event_ = NULL; - } - } - - // - // Wait. - // - pj_status_t wait() - { - return pj_event_wait(event_); - } - - // - // Try wait. - // - pj_status_t trywait() - { - return pj_event_trywait(event_); - } - - // - // Set event state to signalled. - // - pj_status_t set() - { - return pj_event_set(this->pj_event_t_()); - } - - // - // Release one waiting thread. - // - pj_status_t pulse() - { - return pj_event_pulse(this->pj_event_t_()); - } - - // - // Set a non-signalled. - // - pj_status_t reset() - { - return pj_event_reset(this->pj_event_t_()); - } - -private: - pj_event_t *event_; -}; - -// -// OS abstraction. -// -class Pj_OS_API -{ -public: - // - // Get current time. - // - static pj_status_t gettimeofday( Pj_Time_Val *tv ) - { - return pj_gettimeofday(tv); - } - - // - // Parse to time of day. - // - static pj_status_t time_decode( const Pj_Time_Val *tv, - pj_parsed_time *pt ) - { - return pj_time_decode(tv, pt); - } - - // - // Parse from time of day. - // - static pj_status_t time_encode( const pj_parsed_time *pt, - Pj_Time_Val *tv) - { - return pj_time_encode(pt, tv); - } - - // - // Convert to GMT. - // - static pj_status_t time_local_to_gmt( Pj_Time_Val *tv ) - { - return pj_time_local_to_gmt( tv ); - } - - // - // Convert time to local. - // - static pj_status_t time_gmt_to_local( Pj_Time_Val *tv) - { - return pj_time_gmt_to_local( tv ); - } -}; - -// -// Timeval inlines. -// -inline pj_status_t Pj_Time_Val::gettimeofday() -{ - return Pj_OS_API::gettimeofday(this); -} - -inline pj_parsed_time Pj_Time_Val::decode() -{ - pj_parsed_time pt; - Pj_OS_API::time_decode(this, &pt); - return pt; -} - -inline pj_status_t Pj_Time_Val::encode(const pj_parsed_time *pt) -{ - return Pj_OS_API::time_encode(pt, this); -} - -inline pj_status_t Pj_Time_Val::to_gmt() -{ - return Pj_OS_API::time_local_to_gmt(this); -} - -inline pj_status_t Pj_Time_Val::to_local() -{ - return Pj_OS_API::time_gmt_to_local(this); -} - -#endif /* __PJPP_OS_HPP__ */ - +/* $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 __PJPP_OS_HPP__
+#define __PJPP_OS_HPP__
+
+#include <pj/os.h>
+#include <pj++/types.hpp>
+#include <pj++/pool.hpp>
+
+class Pj_Thread;
+
+//
+// Thread API.
+//
+class Pj_Thread_API
+{
+public:
+ //
+ // Create a thread.
+ //
+ static pj_status_t create( Pj_Pool *pool, pj_thread_t **thread,
+ pj_thread_proc *proc, void *arg,
+ unsigned flags = 0,
+ const char *name = NULL,
+ pj_size_t stack_size = 0 )
+ {
+ return pj_thread_create(pool->pool_(), name, proc, arg, stack_size,
+ flags, thread);
+ }
+
+ //
+ // Register a thread.
+ //
+ static pj_status_t register_this_thread( pj_thread_desc desc,
+ pj_thread_t **thread,
+ const char *name = NULL )
+ {
+ return pj_thread_register( name, desc, thread );
+ }
+
+ //
+ // Get current thread.
+ // Will return pj_thread_t (sorry folks, not Pj_Thread).
+ //
+ static pj_thread_t *this_thread()
+ {
+ return pj_thread_this();
+ }
+
+ //
+ // Get thread name.
+ //
+ static const char *get_name(pj_thread_t *thread)
+ {
+ return pj_thread_get_name(thread);
+ }
+
+ //
+ // Resume thread.
+ //
+ static pj_status_t resume(pj_thread_t *thread)
+ {
+ return pj_thread_resume(thread);
+ }
+
+ //
+ // Sleep.
+ //
+ static pj_status_t sleep(unsigned msec)
+ {
+ return pj_thread_sleep(msec);
+ }
+
+ //
+ // Join the specified thread.
+ //
+ static pj_status_t join(pj_thread_t *thread)
+ {
+ return pj_thread_join(thread);
+ }
+
+ //
+ // Destroy thread
+ //
+ static pj_status_t destroy(pj_thread_t *thread)
+ {
+ return pj_thread_destroy(thread);
+ }
+};
+
+
+
+//
+// Thread object.
+//
+// How to use:
+// Derive a class from this class, then override main().
+//
+class Pj_Thread : public Pj_Object
+{
+public:
+ enum Flags
+ {
+ FLAG_SUSPENDED = PJ_THREAD_SUSPENDED
+ };
+
+ //
+ // Default constructor.
+ //
+ Pj_Thread()
+ : thread_(NULL)
+ {
+ }
+
+ //
+ // Destroy thread.
+ //
+ ~Pj_Thread()
+ {
+ destroy();
+ }
+
+ //
+ // This is the main thread function.
+ //
+ virtual int main() = 0;
+
+ //
+ // Start a thread.
+ //
+ pj_status_t create( Pj_Pool *pool,
+ unsigned flags = 0,
+ const char *thread_name = NULL,
+ pj_size_t stack_size = PJ_THREAD_DEFAULT_STACK_SIZE)
+ {
+ destroy();
+ return Pj_Thread_API::create( pool, &thread_, &thread_proc, this,
+ flags, thread_name);
+ }
+
+ //
+ // Get pjlib compatible thread object.
+ //
+ pj_thread_t *pj_thread_t_()
+ {
+ return thread_;
+ }
+
+ //
+ // Get thread name.
+ //
+ const char *get_name()
+ {
+ return Pj_Thread_API::get_name(thread_);
+ }
+
+ //
+ // Resume a suspended thread.
+ //
+ pj_status_t resume()
+ {
+ return Pj_Thread_API::resume(thread_);
+ }
+
+ //
+ // Join this thread.
+ //
+ pj_status_t join()
+ {
+ return Pj_Thread_API::join(thread_);
+ }
+
+ //
+ // Destroy thread.
+ //
+ pj_status_t destroy()
+ {
+ if (thread_) {
+ Pj_Thread_API::destroy(thread_);
+ thread_ = NULL;
+ }
+ }
+
+protected:
+ pj_thread_t *thread_;
+
+ static int PJ_THREAD_FUNC thread_proc(void *obj)
+ {
+ Pj_Thread *thread_class = (Pj_Thread*)obj;
+ return thread_class->main();
+ }
+};
+
+
+//
+// External Thread
+// (threads that were started by external means, i.e. not
+// with Pj_Thread::create).
+//
+// This class will normally be defined as local variable in
+// external thread's stack, normally inside thread's main proc.
+// But be aware that the handle will be destroyed on destructor!
+//
+class Pj_External_Thread : public Pj_Thread
+{
+public:
+ Pj_External_Thread()
+ {
+ }
+
+ //
+ // Register external thread so that pjlib functions can work
+ // in that thread.
+ //
+ pj_status_t register_this_thread( const char *name=NULL )
+ {
+ return Pj_Thread_API::register_this_thread(desc_, &thread_,name);
+ }
+
+private:
+ pj_thread_desc desc_;
+};
+
+
+//
+// Thread specific data/thread local storage/TLS.
+//
+class Pj_Thread_Local_API
+{
+public:
+ //
+ // Allocate thread local storage (TLS) index.
+ //
+ static pj_status_t alloc(long *index)
+ {
+ return pj_thread_local_alloc(index);
+ }
+
+ //
+ // Free TLS index.
+ //
+ static void free(long index)
+ {
+ pj_thread_local_free(index);
+ }
+
+ //
+ // Set thread specific data.
+ //
+ static pj_status_t set(long index, void *value)
+ {
+ return pj_thread_local_set(index, value);
+ }
+
+ //
+ // Get thread specific data.
+ //
+ static void *get(long index)
+ {
+ return pj_thread_local_get(index);
+ }
+
+};
+
+//
+// Atomic variable
+//
+// How to use:
+// Pj_Atomic_Var var(pool, 0);
+// var.set(..);
+//
+class Pj_Atomic_Var : public Pj_Object
+{
+public:
+ //
+ // Default constructor, initialize variable with NULL.
+ //
+ Pj_Atomic_Var()
+ : var_(NULL)
+ {
+ }
+
+ //
+ // Construct atomic variable.
+ //
+ Pj_Atomic_Var(Pj_Pool *pool, pj_atomic_value_t value)
+ : var_(NULL)
+ {
+ create(pool, value);
+ }
+
+ //
+ // Destructor.
+ //
+ ~Pj_Atomic_Var()
+ {
+ destroy();
+ }
+
+ //
+ // Create atomic variable.
+ //
+ pj_status_t create( Pj_Pool *pool, pj_atomic_value_t value)
+ {
+ destroy();
+ return pj_atomic_create(pool->pool_(), value, &var_);
+ }
+
+ //
+ // Destroy.
+ //
+ void destroy()
+ {
+ if (var_) {
+ pj_atomic_destroy(var_);
+ var_ = NULL;
+ }
+ }
+
+ //
+ // Get pjlib compatible atomic variable.
+ //
+ pj_atomic_t *pj_atomic_t_()
+ {
+ return var_;
+ }
+
+ //
+ // Set the value.
+ //
+ void set(pj_atomic_value_t val)
+ {
+ pj_atomic_set(var_, val);
+ }
+
+ //
+ // Get the value.
+ //
+ pj_atomic_value_t get()
+ {
+ return pj_atomic_get(var_);
+ }
+
+ //
+ // Increment.
+ //
+ void inc()
+ {
+ pj_atomic_inc(var_);
+ }
+
+ //
+ // Increment and get the result.
+ //
+ pj_atomic_value_t inc_and_get()
+ {
+ return pj_atomic_inc_and_get(var_);
+ }
+
+ //
+ // Decrement.
+ //
+ void dec()
+ {
+ pj_atomic_dec(var_);
+ }
+
+ //
+ // Decrement and get the result.
+ //
+ pj_atomic_value_t dec_and_get()
+ {
+ return pj_atomic_dec_and_get(var_);
+ }
+
+ //
+ // Add the variable.
+ //
+ void add(pj_atomic_value_t value)
+ {
+ pj_atomic_add(var_, value);
+ }
+
+ //
+ // Add the variable and get the value.
+ //
+ pj_atomic_value_t add_and_get(pj_atomic_value_t value)
+ {
+ return pj_atomic_add_and_get(var_, value );
+ }
+
+private:
+ pj_atomic_t *var_;
+};
+
+
+//
+// Mutex
+//
+class Pj_Mutex : public Pj_Object
+{
+public:
+ //
+ // Mutex type.
+ //
+ enum Type
+ {
+ DEFAULT = PJ_MUTEX_DEFAULT,
+ SIMPLE = PJ_MUTEX_SIMPLE,
+ RECURSE = PJ_MUTEX_RECURSE,
+ };
+
+ //
+ // Default constructor will create default mutex.
+ //
+ explicit Pj_Mutex(Pj_Pool *pool, Type type = DEFAULT,
+ const char *name = NULL)
+ : mutex_(NULL)
+ {
+ create(pool, type, name);
+ }
+
+ //
+ // Destructor.
+ //
+ ~Pj_Mutex()
+ {
+ destroy();
+ }
+
+ //
+ // Create mutex.
+ //
+ pj_status_t create( Pj_Pool *pool, Type type, const char *name = NULL)
+ {
+ destroy();
+ return pj_mutex_create( pool->pool_(), name, type,
+ &mutex_ );
+ }
+
+ //
+ // Create simple mutex.
+ //
+ pj_status_t create_simple( Pj_Pool *pool,const char *name = NULL)
+ {
+ return create(pool, SIMPLE, name);
+ }
+
+ //
+ // Create recursive mutex.
+ //
+ pj_status_t create_recursive( Pj_Pool *pool, const char *name = NULL )
+ {
+ return create(pool, RECURSE, name);
+ }
+
+ //
+ // Get pjlib compatible mutex object.
+ //
+ pj_mutex_t *pj_mutex_t_()
+ {
+ return mutex_;
+ }
+
+ //
+ // Destroy mutex.
+ //
+ void destroy()
+ {
+ if (mutex_) {
+ pj_mutex_destroy(mutex_);
+ mutex_ = NULL;
+ }
+ }
+
+ //
+ // Lock mutex.
+ //
+ pj_status_t acquire()
+ {
+ return pj_mutex_lock(mutex_);
+ }
+
+ //
+ // Unlock mutex.
+ //
+ pj_status_t release()
+ {
+ return pj_mutex_unlock(mutex_);
+ }
+
+ //
+ // Try locking the mutex.
+ //
+ pj_status_t tryacquire()
+ {
+ return pj_mutex_trylock(mutex_);
+ }
+
+private:
+ pj_mutex_t *mutex_;
+};
+
+
+//
+// Semaphore
+//
+class Pj_Semaphore : public Pj_Object
+{
+public:
+ //
+ // Construct semaphore
+ //
+ Pj_Semaphore(Pj_Pool *pool, unsigned max,
+ unsigned initial = 0, const char *name = NULL)
+ : sem_(NULL)
+ {
+ }
+
+ //
+ // Destructor.
+ //
+ ~Pj_Semaphore()
+ {
+ destroy();
+ }
+
+ //
+ // Create semaphore
+ //
+ pj_status_t create( Pj_Pool *pool, unsigned max,
+ unsigned initial = 0, const char *name = NULL )
+ {
+ destroy();
+ return pj_sem_create( pool->pool_(), name, initial, max, &sem_);
+ }
+
+ //
+ // Destroy semaphore.
+ //
+ void destroy()
+ {
+ if (sem_) {
+ pj_sem_destroy(sem_);
+ sem_ = NULL;
+ }
+ }
+
+ //
+ // Get pjlib compatible semaphore object.
+ //
+ pj_sem_t *pj_sem_t_()
+ {
+ return (pj_sem_t*)this;
+ }
+
+ //
+ // Wait semaphore.
+ //
+ pj_status_t wait()
+ {
+ return pj_sem_wait(this->pj_sem_t_());
+ }
+
+ //
+ // Wait semaphore.
+ //
+ pj_status_t acquire()
+ {
+ return wait();
+ }
+
+ //
+ // Try wait semaphore.
+ //
+ pj_status_t trywait()
+ {
+ return pj_sem_trywait(this->pj_sem_t_());
+ }
+
+ //
+ // Try wait semaphore.
+ //
+ pj_status_t tryacquire()
+ {
+ return trywait();
+ }
+
+ //
+ // Post semaphore.
+ //
+ pj_status_t post()
+ {
+ return pj_sem_post(this->pj_sem_t_());
+ }
+
+ //
+ // Post semaphore.
+ //
+ pj_status_t release()
+ {
+ return post();
+ }
+
+private:
+ pj_sem_t *sem_;
+};
+
+
+//
+// Event object.
+//
+class Pj_Event
+{
+public:
+ //
+ // Construct event object.
+ //
+ Pj_Event( Pj_Pool *pool, bool manual_reset = false,
+ bool initial = false, const char *name = NULL )
+ : event_(NULL)
+ {
+ create(pool, manual_reset, initial, name);
+ }
+
+ //
+ // Destructor.
+ //
+ ~Pj_Event()
+ {
+ destroy();
+ }
+
+ //
+ // Create event object.
+ //
+ pj_status_t create( Pj_Pool *pool, bool manual_reset = false,
+ bool initial = false, const char *name = NULL)
+ {
+ destroy();
+ return pj_event_create(pool->pool_(), name, manual_reset, initial,
+ &event_);
+ }
+
+ //
+ // Get pjlib compatible event object.
+ //
+ pj_event_t *pj_event_t_()
+ {
+ return event_;
+ }
+
+ //
+ // Destroy event object.
+ //
+ void destroy()
+ {
+ if (event_) {
+ pj_event_destroy(event_);
+ event_ = NULL;
+ }
+ }
+
+ //
+ // Wait.
+ //
+ pj_status_t wait()
+ {
+ return pj_event_wait(event_);
+ }
+
+ //
+ // Try wait.
+ //
+ pj_status_t trywait()
+ {
+ return pj_event_trywait(event_);
+ }
+
+ //
+ // Set event state to signalled.
+ //
+ pj_status_t set()
+ {
+ return pj_event_set(this->pj_event_t_());
+ }
+
+ //
+ // Release one waiting thread.
+ //
+ pj_status_t pulse()
+ {
+ return pj_event_pulse(this->pj_event_t_());
+ }
+
+ //
+ // Set a non-signalled.
+ //
+ pj_status_t reset()
+ {
+ return pj_event_reset(this->pj_event_t_());
+ }
+
+private:
+ pj_event_t *event_;
+};
+
+//
+// OS abstraction.
+//
+class Pj_OS_API
+{
+public:
+ //
+ // Get current time.
+ //
+ static pj_status_t gettimeofday( Pj_Time_Val *tv )
+ {
+ return pj_gettimeofday(tv);
+ }
+
+ //
+ // Parse to time of day.
+ //
+ static pj_status_t time_decode( const Pj_Time_Val *tv,
+ pj_parsed_time *pt )
+ {
+ return pj_time_decode(tv, pt);
+ }
+
+ //
+ // Parse from time of day.
+ //
+ static pj_status_t time_encode( const pj_parsed_time *pt,
+ Pj_Time_Val *tv)
+ {
+ return pj_time_encode(pt, tv);
+ }
+
+ //
+ // Convert to GMT.
+ //
+ static pj_status_t time_local_to_gmt( Pj_Time_Val *tv )
+ {
+ return pj_time_local_to_gmt( tv );
+ }
+
+ //
+ // Convert time to local.
+ //
+ static pj_status_t time_gmt_to_local( Pj_Time_Val *tv)
+ {
+ return pj_time_gmt_to_local( tv );
+ }
+};
+
+//
+// Timeval inlines.
+//
+inline pj_status_t Pj_Time_Val::gettimeofday()
+{
+ return Pj_OS_API::gettimeofday(this);
+}
+
+inline pj_parsed_time Pj_Time_Val::decode()
+{
+ pj_parsed_time pt;
+ Pj_OS_API::time_decode(this, &pt);
+ return pt;
+}
+
+inline pj_status_t Pj_Time_Val::encode(const pj_parsed_time *pt)
+{
+ return Pj_OS_API::time_encode(pt, this);
+}
+
+inline pj_status_t Pj_Time_Val::to_gmt()
+{
+ return Pj_OS_API::time_local_to_gmt(this);
+}
+
+inline pj_status_t Pj_Time_Val::to_local()
+{
+ return Pj_OS_API::time_gmt_to_local(this);
+}
+
+#endif /* __PJPP_OS_HPP__ */
+
diff --git a/pjlib/include/pj++/pool.hpp b/pjlib/include/pj++/pool.hpp index 1fa75759..22365117 100644 --- a/pjlib/include/pj++/pool.hpp +++ b/pjlib/include/pj++/pool.hpp @@ -1,254 +1,275 @@ -/* $Id$ - */ -#ifndef __PJPP_POOL_HPP__ -#define __PJPP_POOL_HPP__ - -#include <pj/pool.h> - -class Pj_Pool; -class Pj_Caching_Pool; - -// -// Base class for all Pjlib objects -// -class Pj_Object -{ -public: - void *operator new(unsigned int class_size, Pj_Pool *pool); - void *operator new(unsigned int class_size, Pj_Pool &pool); - - void operator delete(void*) - { - } - - void operator delete(void*, Pj_Pool*) - { - } - - void operator delete(void*, Pj_Pool&) - { - } - - // - // Inline implementations at the end of this file. - // - -private: - // Can not use normal new operator; must use pool. - // e.g.: - // obj = new(pool) Pj_The_Object(pool, ...); - // - void *operator new(unsigned int) - {} -}; - - -// -// Pool. -// -class Pj_Pool : public Pj_Object -{ -public: - // - // Default constructor, initializes internal pool to NULL. - // Application must call attach() some time later. - // - Pj_Pool() - : p_(NULL) - { - } - - // - // Create pool. - // - Pj_Pool(Pj_Caching_Pool &caching_pool, - pj_size_t initial_size, - pj_size_t increment_size, - const char *name = NULL, - pj_pool_callback *callback = NULL); - - // - // Construct from existing pool. - // - explicit Pj_Pool(pj_pool_t *pool) - : p_(pool) - { - } - - // - // Attach existing pool. - // - void attach(pj_pool_t *pool) - { - p_ = pool; - } - - // - // Destructor. - // - // Release pool back to factory. Remember: if you delete pool, then - // make sure that all objects that have been allocated from this pool - // have been properly destroyed. - // - // This is where C++ is trickier than plain C!! - // - ~Pj_Pool() - { - if (p_) - pj_pool_release(p_); - } - - // - // Get name. - // - const char *getobjname() const - { - return pj_pool_getobjname(p_); - } - - // - // Get pjlib compatible pool object. - // - pj_pool_t *pool_() - { - return p_; - } - - // - // Get pjlib compatible pool object. - // - const pj_pool_t *pool_() const - { - return p_; - } - - // - // Get pjlib compatible pool object. - // - pj_pool_t *pj_pool_t_() - { - return p_; - } - - // - // Reset pool. - // - void reset() - { - pj_pool_reset(p_); - } - - // - // Get current capacity. - // - pj_size_t get_capacity() - { - pj_pool_get_capacity(p_); - } - - // - // Get current total bytes allocated from the pool. - // - pj_size_t get_used_size() - { - pj_pool_get_used_size(p_); - } - - // - // Allocate. - // - void *alloc(pj_size_t size) - { - return pj_pool_alloc(p_, size); - } - - // - // Allocate elements and zero fill the memory. - // - void *calloc(pj_size_t count, pj_size_t elem) - { - return pj_pool_calloc(p_, count, elem); - } - - // - // Allocate and zero fill memory. - // - void *zalloc(pj_size_t size) - { - return pj_pool_zalloc(p_, size); - } - -private: - pj_pool_t *p_; -}; - - -// -// Caching pool. -// -class Pj_Caching_Pool -{ -public: - // - // Construct caching pool. - // - Pj_Caching_Pool( pj_size_t cache_capacity = 0, - const pj_pool_factory_policy *pol=&pj_pool_factory_default_policy) - { - pj_caching_pool_init(&cp_, pol, cache_capacity); - } - - // - // Destroy caching pool. - // - ~Pj_Caching_Pool() - { - pj_caching_pool_destroy(&cp_); - } - - // - // Create pool. - // - pj_pool_t *create_pool( pj_size_t initial_size, - pj_size_t increment_size, - const char *name = NULL, - pj_pool_callback *callback = NULL) - { - return (pj_pool_t*)(*cp_.factory.create_pool)(&cp_.factory, name, - initial_size, - increment_size, - callback); - } - -private: - pj_caching_pool cp_; -}; - -// -// Inlines for Pj_Object -// -inline void *Pj_Object::operator new(unsigned int class_size, Pj_Pool *pool) -{ - return pool->alloc(class_size); -} -inline void *Pj_Object::operator new(unsigned int class_size, Pj_Pool &pool) -{ - return pool.alloc(class_size); -} - -// -// Inlines for Pj_Pool -// -inline Pj_Pool::Pj_Pool( Pj_Caching_Pool &caching_pool, - pj_size_t initial_size, - pj_size_t increment_size, - const char *name, - pj_pool_callback *callback) -{ - p_ = caching_pool.create_pool(initial_size, increment_size, name, - callback); -} - - -#endif /* __PJPP_POOL_HPP__ */ - +/* $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 __PJPP_POOL_HPP__
+#define __PJPP_POOL_HPP__
+
+#include <pj/pool.h>
+
+class Pj_Pool;
+class Pj_Caching_Pool;
+
+//
+// Base class for all Pjlib objects
+//
+class Pj_Object
+{
+public:
+ void *operator new(unsigned int class_size, Pj_Pool *pool);
+ void *operator new(unsigned int class_size, Pj_Pool &pool);
+
+ void operator delete(void*)
+ {
+ }
+
+ void operator delete(void*, Pj_Pool*)
+ {
+ }
+
+ void operator delete(void*, Pj_Pool&)
+ {
+ }
+
+ //
+ // Inline implementations at the end of this file.
+ //
+
+private:
+ // Can not use normal new operator; must use pool.
+ // e.g.:
+ // obj = new(pool) Pj_The_Object(pool, ...);
+ //
+ void *operator new(unsigned int)
+ {}
+};
+
+
+//
+// Pool.
+//
+class Pj_Pool : public Pj_Object
+{
+public:
+ //
+ // Default constructor, initializes internal pool to NULL.
+ // Application must call attach() some time later.
+ //
+ Pj_Pool()
+ : p_(NULL)
+ {
+ }
+
+ //
+ // Create pool.
+ //
+ Pj_Pool(Pj_Caching_Pool &caching_pool,
+ pj_size_t initial_size,
+ pj_size_t increment_size,
+ const char *name = NULL,
+ pj_pool_callback *callback = NULL);
+
+ //
+ // Construct from existing pool.
+ //
+ explicit Pj_Pool(pj_pool_t *pool)
+ : p_(pool)
+ {
+ }
+
+ //
+ // Attach existing pool.
+ //
+ void attach(pj_pool_t *pool)
+ {
+ p_ = pool;
+ }
+
+ //
+ // Destructor.
+ //
+ // Release pool back to factory. Remember: if you delete pool, then
+ // make sure that all objects that have been allocated from this pool
+ // have been properly destroyed.
+ //
+ // This is where C++ is trickier than plain C!!
+ //
+ ~Pj_Pool()
+ {
+ if (p_)
+ pj_pool_release(p_);
+ }
+
+ //
+ // Get name.
+ //
+ const char *getobjname() const
+ {
+ return pj_pool_getobjname(p_);
+ }
+
+ //
+ // Get pjlib compatible pool object.
+ //
+ pj_pool_t *pool_()
+ {
+ return p_;
+ }
+
+ //
+ // Get pjlib compatible pool object.
+ //
+ const pj_pool_t *pool_() const
+ {
+ return p_;
+ }
+
+ //
+ // Get pjlib compatible pool object.
+ //
+ pj_pool_t *pj_pool_t_()
+ {
+ return p_;
+ }
+
+ //
+ // Reset pool.
+ //
+ void reset()
+ {
+ pj_pool_reset(p_);
+ }
+
+ //
+ // Get current capacity.
+ //
+ pj_size_t get_capacity()
+ {
+ pj_pool_get_capacity(p_);
+ }
+
+ //
+ // Get current total bytes allocated from the pool.
+ //
+ pj_size_t get_used_size()
+ {
+ pj_pool_get_used_size(p_);
+ }
+
+ //
+ // Allocate.
+ //
+ void *alloc(pj_size_t size)
+ {
+ return pj_pool_alloc(p_, size);
+ }
+
+ //
+ // Allocate elements and zero fill the memory.
+ //
+ void *calloc(pj_size_t count, pj_size_t elem)
+ {
+ return pj_pool_calloc(p_, count, elem);
+ }
+
+ //
+ // Allocate and zero fill memory.
+ //
+ void *zalloc(pj_size_t size)
+ {
+ return pj_pool_zalloc(p_, size);
+ }
+
+private:
+ pj_pool_t *p_;
+};
+
+
+//
+// Caching pool.
+//
+class Pj_Caching_Pool
+{
+public:
+ //
+ // Construct caching pool.
+ //
+ Pj_Caching_Pool( pj_size_t cache_capacity = 0,
+ const pj_pool_factory_policy *pol=&pj_pool_factory_default_policy)
+ {
+ pj_caching_pool_init(&cp_, pol, cache_capacity);
+ }
+
+ //
+ // Destroy caching pool.
+ //
+ ~Pj_Caching_Pool()
+ {
+ pj_caching_pool_destroy(&cp_);
+ }
+
+ //
+ // Create pool.
+ //
+ pj_pool_t *create_pool( pj_size_t initial_size,
+ pj_size_t increment_size,
+ const char *name = NULL,
+ pj_pool_callback *callback = NULL)
+ {
+ return (pj_pool_t*)(*cp_.factory.create_pool)(&cp_.factory, name,
+ initial_size,
+ increment_size,
+ callback);
+ }
+
+private:
+ pj_caching_pool cp_;
+};
+
+//
+// Inlines for Pj_Object
+//
+inline void *Pj_Object::operator new(unsigned int class_size, Pj_Pool *pool)
+{
+ return pool->alloc(class_size);
+}
+inline void *Pj_Object::operator new(unsigned int class_size, Pj_Pool &pool)
+{
+ return pool.alloc(class_size);
+}
+
+//
+// Inlines for Pj_Pool
+//
+inline Pj_Pool::Pj_Pool( Pj_Caching_Pool &caching_pool,
+ pj_size_t initial_size,
+ pj_size_t increment_size,
+ const char *name,
+ pj_pool_callback *callback)
+{
+ p_ = caching_pool.create_pool(initial_size, increment_size, name,
+ callback);
+}
+
+
+#endif /* __PJPP_POOL_HPP__ */
+
diff --git a/pjlib/include/pj++/proactor.hpp b/pjlib/include/pj++/proactor.hpp index 73be85f4..7c4f9928 100644 --- a/pjlib/include/pj++/proactor.hpp +++ b/pjlib/include/pj++/proactor.hpp @@ -1,502 +1,523 @@ -/* $Id$ - */ -#ifndef __PJPP_PROACTOR_HPP__ -#define __PJPP_PROACTOR_HPP__ - -#include <pj/ioqueue.h> -#include <pj++/pool.hpp> -#include <pj++/sock.hpp> -#include <pj++/timer.hpp> -#include <pj/errno.h> - -class Pj_Proactor; -class Pj_Event_Handler; - - -////////////////////////////////////////////////////////////////////////////// -// Asynchronous operation key. -// -// Applications may inheric this class to put their application -// specific data. -// -class Pj_Async_Op : public pj_ioqueue_op_key_t -{ -public: - // - // Construct with null handler. - // App must call set_handler() before use. - // - Pj_Async_Op() - : handler_(NULL) - { - pj_ioqueue_op_key_init(this, sizeof(*this)); - } - - // - // Constructor. - // - explicit Pj_Async_Op(Pj_Event_Handler *handler) - : handler_(handler) - { - pj_ioqueue_op_key_init(this, sizeof(*this)); - } - - // - // Set handler. - // - void set_handler(Pj_Event_Handler *handler) - { - handler_ = handler; - } - - // - // Check whether operation is still pending for this key. - // - bool is_pending(); - - // - // Cancel the operation. - // - bool cancel(pj_ssize_t bytes_status=-PJ_ECANCELLED); - -protected: - Pj_Event_Handler *handler_; -}; - - -////////////////////////////////////////////////////////////////////////////// -// Event handler. -// -// Applications should inherit this class to receive various event -// notifications. -// -// Applications should implement get_socket_handle(). -// -class Pj_Event_Handler : public Pj_Object -{ - friend class Pj_Proactor; -public: - // - // Default constructor. - // - Pj_Event_Handler() - : key_(NULL) - { - pj_memset(&timer_, 0, sizeof(timer_)); - timer_.user_data = this; - timer_.cb = &timer_callback; - } - - // - // Destroy. - // - virtual ~Pj_Event_Handler() - { - unregister(); - } - - // - // Unregister this handler from the ioqueue. - // - void unregister() - { - if (key_) { - pj_ioqueue_unregister(key_); - key_ = NULL; - } - } - - // - // Get socket handle associated with this. - // - virtual pj_sock_t get_socket_handle() - { - return PJ_INVALID_SOCKET; - } - - // - // Start async receive. - // - pj_status_t recv( Pj_Async_Op *op_key, - void *buf, pj_ssize_t *len, - unsigned flags) - { - return pj_ioqueue_recv( key_, op_key, - buf, len, flags); - } - - // - // Start async recvfrom() - // - pj_status_t recvfrom( Pj_Async_Op *op_key, - void *buf, pj_ssize_t *len, unsigned flags, - Pj_Inet_Addr *addr) - { - addr->addrlen_ = sizeof(Pj_Inet_Addr); - return pj_ioqueue_recvfrom( key_, op_key, buf, len, flags, - addr, &addr->addrlen_ ); - } - - // - // Start async send() - // - pj_status_t send( Pj_Async_Op *op_key, - const void *data, pj_ssize_t *len, - unsigned flags) - { - return pj_ioqueue_send( key_, op_key, data, len, flags); - } - - // - // Start async sendto() - // - pj_status_t sendto( Pj_Async_Op *op_key, - const void *data, pj_ssize_t *len, unsigned flags, - const Pj_Inet_Addr &addr) - { - return pj_ioqueue_sendto(key_, op_key, data, len, flags, - &addr, sizeof(addr)); - } - -#if PJ_HAS_TCP - // - // Start async connect() - // - pj_status_t connect(const Pj_Inet_Addr &addr) - { - return pj_ioqueue_connect(key_, &addr, sizeof(addr)); - } - - // - // Start async accept(). - // - pj_status_t accept( Pj_Async_Op *op_key, - Pj_Socket *sock, - Pj_Inet_Addr *local = NULL, - Pj_Inet_Addr *remote = NULL) - { - int *addrlen = local ? &local->addrlen_ : NULL; - return pj_ioqueue_accept( key_, op_key, &sock->sock_, - local, remote, addrlen ); - } - -#endif - -protected: - ////////////////// - // Overridables - ////////////////// - - // - // Timeout callback. - // - virtual void on_timeout(int data) - { - } - - // - // On read complete callback. - // - virtual void on_read_complete( Pj_Async_Op *op_key, - pj_ssize_t bytes_read) - { - } - - // - // On write complete callback. - // - virtual void on_write_complete( Pj_Async_Op *op_key, - pj_ssize_t bytes_sent) - { - } - -#if PJ_HAS_TCP - // - // On connect complete callback. - // - virtual void on_connect_complete(pj_status_t status) - { - } - - // - // On new connection callback. - // - virtual void on_accept_complete( Pj_Async_Op *op_key, - pj_sock_t new_sock, - pj_status_t status) - { - } - -#endif - - -private: - pj_ioqueue_key_t *key_; - pj_timer_entry timer_; - - friend class Pj_Proactor; - friend class Pj_Async_Op; - - // - // Static timer callback. - // - static void timer_callback( pj_timer_heap_t *timer_heap, - struct pj_timer_entry *entry) - { - Pj_Event_Handler *handler = - (Pj_Event_Handler*) entry->user_data; - - handler->on_timeout(entry->id); - } -}; - -inline bool Pj_Async_Op::is_pending() -{ - return pj_ioqueue_is_pending(handler_->key_, this) != 0; -} - -inline bool Pj_Async_Op::cancel(pj_ssize_t bytes_status) -{ - return pj_ioqueue_post_completion(handler_->key_, this, - bytes_status) == PJ_SUCCESS; -} - -////////////////////////////////////////////////////////////////////////////// -// Proactor -// -class Pj_Proactor : public Pj_Object -{ -public: - // - // Default constructor, initializes to NULL. - // - Pj_Proactor() - : ioq_(NULL), th_(NULL) - { - cb_.on_read_complete = &read_complete_cb; - cb_.on_write_complete = &write_complete_cb; - cb_.on_accept_complete = &accept_complete_cb; - cb_.on_connect_complete = &connect_complete_cb; - } - - // - // Construct proactor. - // - Pj_Proactor( Pj_Pool *pool, pj_size_t max_fd, - pj_size_t max_timer_entries ) - : ioq_(NULL), th_(NULL) - { - cb_.on_read_complete = &read_complete_cb; - cb_.on_write_complete = &write_complete_cb; - cb_.on_accept_complete = &accept_complete_cb; - cb_.on_connect_complete = &connect_complete_cb; - - create(pool, max_fd, max_timer_entries); - } - - // - // Destructor. - // - ~Pj_Proactor() - { - destroy(); - } - - // - // Create proactor. - // - pj_status_t create( Pj_Pool *pool, pj_size_t max_fd, - pj_size_t timer_entry_count) - { - pj_status_t status; - - destroy(); - - status = pj_ioqueue_create(pool->pool_(), max_fd, &ioq_); - if (status != PJ_SUCCESS) - return status; - - status = pj_timer_heap_create(pool->pool_(), - timer_entry_count, &th_); - if (status != PJ_SUCCESS) { - pj_ioqueue_destroy(ioq_); - ioq_ = NULL; - return NULL; - } - - return status; - } - - // - // Destroy proactor. - // - void destroy() - { - if (ioq_) { - pj_ioqueue_destroy(ioq_); - ioq_ = NULL; - } - if (th_) { - pj_timer_heap_destroy(th_); - th_ = NULL; - } - } - - // - // Register handler. - // This will call handler->get_socket_handle() - // - pj_status_t register_socket_handler(Pj_Pool *pool, - Pj_Event_Handler *handler) - { - return pj_ioqueue_register_sock( pool->pool_(), ioq_, - handler->get_socket_handle(), - handler, &cb_, &handler->key_ ); - } - - // - // Unregister handler. - // - static void unregister_handler(Pj_Event_Handler *handler) - { - if (handler->key_) { - pj_ioqueue_unregister( handler->key_ ); - handler->key_ = NULL; - } - } - - // - // Scheduler timer. - // - bool schedule_timer( Pj_Event_Handler *handler, - const Pj_Time_Val &delay, - int id=-1) - { - return schedule_timer(th_, handler, delay, id); - } - - // - // Cancel timer. - // - bool cancel_timer(Pj_Event_Handler *handler) - { - return pj_timer_heap_cancel(th_, &handler->timer_) == 1; - } - - // - // Handle events. - // - int handle_events(Pj_Time_Val *max_timeout) - { - Pj_Time_Val timeout(0, 0); - int timer_count; - - timer_count = pj_timer_heap_poll( th_, &timeout ); - - if (timeout.get_sec() < 0) - timeout.sec = PJ_MAXINT32; - - /* If caller specifies maximum time to wait, then compare the value - * with the timeout to wait from timer, and use the minimum value. - */ - if (max_timeout && timeout >= *max_timeout) { - timeout = *max_timeout; - } - - /* Poll events in ioqueue. */ - int ioqueue_count; - - ioqueue_count = pj_ioqueue_poll(ioq_, &timeout); - if (ioqueue_count < 0) - return ioqueue_count; - - return ioqueue_count + timer_count; - } - - // - // Get the internal ioqueue object. - // - pj_ioqueue_t *get_io_queue() - { - return ioq_; - } - - // - // Get the internal timer heap object. - // - pj_timer_heap_t *get_timer_heap() - { - return th_; - } - -private: - pj_ioqueue_t *ioq_; - pj_timer_heap_t *th_; - pj_ioqueue_callback cb_; - - static bool schedule_timer( pj_timer_heap_t *timer, - Pj_Event_Handler *handler, - const Pj_Time_Val &delay, - int id=-1) - { - handler->timer_.id = id; - return pj_timer_heap_schedule(timer, &handler->timer_, &delay) == 0; - } - - - // - // Static read completion callback. - // - static void read_complete_cb( pj_ioqueue_key_t *key, - pj_ioqueue_op_key_t *op_key, - pj_ssize_t bytes_read) - { - Pj_Event_Handler *handler = - (Pj_Event_Handler*) pj_ioqueue_get_user_data(key); - - handler->on_read_complete((Pj_Async_Op*)op_key, bytes_read); - } - - // - // Static write completion callback. - // - static void write_complete_cb(pj_ioqueue_key_t *key, - pj_ioqueue_op_key_t *op_key, - pj_ssize_t bytes_sent) - { - Pj_Event_Handler *handler = - (Pj_Event_Handler*) pj_ioqueue_get_user_data(key); - - handler->on_write_complete((Pj_Async_Op*)op_key, bytes_sent); - } - - // - // Static accept completion callback. - // - static void accept_complete_cb(pj_ioqueue_key_t *key, - pj_ioqueue_op_key_t *op_key, - pj_sock_t new_sock, - pj_status_t status) - { - Pj_Event_Handler *handler = - (Pj_Event_Handler*) pj_ioqueue_get_user_data(key); - - handler->on_accept_complete((Pj_Async_Op*)op_key, new_sock, status); - } - - // - // Static connect completion callback. - // - static void connect_complete_cb(pj_ioqueue_key_t *key, - pj_status_t status) - { - Pj_Event_Handler *handler = - (Pj_Event_Handler*) pj_ioqueue_get_user_data(key); - - handler->on_connect_complete(status); - } - -}; - -#endif /* __PJPP_PROACTOR_HPP__ */ - +/* $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 __PJPP_PROACTOR_HPP__
+#define __PJPP_PROACTOR_HPP__
+
+#include <pj/ioqueue.h>
+#include <pj++/pool.hpp>
+#include <pj++/sock.hpp>
+#include <pj++/timer.hpp>
+#include <pj/errno.h>
+
+class Pj_Proactor;
+class Pj_Event_Handler;
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Asynchronous operation key.
+//
+// Applications may inheric this class to put their application
+// specific data.
+//
+class Pj_Async_Op : public pj_ioqueue_op_key_t
+{
+public:
+ //
+ // Construct with null handler.
+ // App must call set_handler() before use.
+ //
+ Pj_Async_Op()
+ : handler_(NULL)
+ {
+ pj_ioqueue_op_key_init(this, sizeof(*this));
+ }
+
+ //
+ // Constructor.
+ //
+ explicit Pj_Async_Op(Pj_Event_Handler *handler)
+ : handler_(handler)
+ {
+ pj_ioqueue_op_key_init(this, sizeof(*this));
+ }
+
+ //
+ // Set handler.
+ //
+ void set_handler(Pj_Event_Handler *handler)
+ {
+ handler_ = handler;
+ }
+
+ //
+ // Check whether operation is still pending for this key.
+ //
+ bool is_pending();
+
+ //
+ // Cancel the operation.
+ //
+ bool cancel(pj_ssize_t bytes_status=-PJ_ECANCELLED);
+
+protected:
+ Pj_Event_Handler *handler_;
+};
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Event handler.
+//
+// Applications should inherit this class to receive various event
+// notifications.
+//
+// Applications should implement get_socket_handle().
+//
+class Pj_Event_Handler : public Pj_Object
+{
+ friend class Pj_Proactor;
+public:
+ //
+ // Default constructor.
+ //
+ Pj_Event_Handler()
+ : key_(NULL)
+ {
+ pj_memset(&timer_, 0, sizeof(timer_));
+ timer_.user_data = this;
+ timer_.cb = &timer_callback;
+ }
+
+ //
+ // Destroy.
+ //
+ virtual ~Pj_Event_Handler()
+ {
+ unregister();
+ }
+
+ //
+ // Unregister this handler from the ioqueue.
+ //
+ void unregister()
+ {
+ if (key_) {
+ pj_ioqueue_unregister(key_);
+ key_ = NULL;
+ }
+ }
+
+ //
+ // Get socket handle associated with this.
+ //
+ virtual pj_sock_t get_socket_handle()
+ {
+ return PJ_INVALID_SOCKET;
+ }
+
+ //
+ // Start async receive.
+ //
+ pj_status_t recv( Pj_Async_Op *op_key,
+ void *buf, pj_ssize_t *len,
+ unsigned flags)
+ {
+ return pj_ioqueue_recv( key_, op_key,
+ buf, len, flags);
+ }
+
+ //
+ // Start async recvfrom()
+ //
+ pj_status_t recvfrom( Pj_Async_Op *op_key,
+ void *buf, pj_ssize_t *len, unsigned flags,
+ Pj_Inet_Addr *addr)
+ {
+ addr->addrlen_ = sizeof(Pj_Inet_Addr);
+ return pj_ioqueue_recvfrom( key_, op_key, buf, len, flags,
+ addr, &addr->addrlen_ );
+ }
+
+ //
+ // Start async send()
+ //
+ pj_status_t send( Pj_Async_Op *op_key,
+ const void *data, pj_ssize_t *len,
+ unsigned flags)
+ {
+ return pj_ioqueue_send( key_, op_key, data, len, flags);
+ }
+
+ //
+ // Start async sendto()
+ //
+ pj_status_t sendto( Pj_Async_Op *op_key,
+ const void *data, pj_ssize_t *len, unsigned flags,
+ const Pj_Inet_Addr &addr)
+ {
+ return pj_ioqueue_sendto(key_, op_key, data, len, flags,
+ &addr, sizeof(addr));
+ }
+
+#if PJ_HAS_TCP
+ //
+ // Start async connect()
+ //
+ pj_status_t connect(const Pj_Inet_Addr &addr)
+ {
+ return pj_ioqueue_connect(key_, &addr, sizeof(addr));
+ }
+
+ //
+ // Start async accept().
+ //
+ pj_status_t accept( Pj_Async_Op *op_key,
+ Pj_Socket *sock,
+ Pj_Inet_Addr *local = NULL,
+ Pj_Inet_Addr *remote = NULL)
+ {
+ int *addrlen = local ? &local->addrlen_ : NULL;
+ return pj_ioqueue_accept( key_, op_key, &sock->sock_,
+ local, remote, addrlen );
+ }
+
+#endif
+
+protected:
+ //////////////////
+ // Overridables
+ //////////////////
+
+ //
+ // Timeout callback.
+ //
+ virtual void on_timeout(int data)
+ {
+ }
+
+ //
+ // On read complete callback.
+ //
+ virtual void on_read_complete( Pj_Async_Op *op_key,
+ pj_ssize_t bytes_read)
+ {
+ }
+
+ //
+ // On write complete callback.
+ //
+ virtual void on_write_complete( Pj_Async_Op *op_key,
+ pj_ssize_t bytes_sent)
+ {
+ }
+
+#if PJ_HAS_TCP
+ //
+ // On connect complete callback.
+ //
+ virtual void on_connect_complete(pj_status_t status)
+ {
+ }
+
+ //
+ // On new connection callback.
+ //
+ virtual void on_accept_complete( Pj_Async_Op *op_key,
+ pj_sock_t new_sock,
+ pj_status_t status)
+ {
+ }
+
+#endif
+
+
+private:
+ pj_ioqueue_key_t *key_;
+ pj_timer_entry timer_;
+
+ friend class Pj_Proactor;
+ friend class Pj_Async_Op;
+
+ //
+ // Static timer callback.
+ //
+ static void timer_callback( pj_timer_heap_t *timer_heap,
+ struct pj_timer_entry *entry)
+ {
+ Pj_Event_Handler *handler =
+ (Pj_Event_Handler*) entry->user_data;
+
+ handler->on_timeout(entry->id);
+ }
+};
+
+inline bool Pj_Async_Op::is_pending()
+{
+ return pj_ioqueue_is_pending(handler_->key_, this) != 0;
+}
+
+inline bool Pj_Async_Op::cancel(pj_ssize_t bytes_status)
+{
+ return pj_ioqueue_post_completion(handler_->key_, this,
+ bytes_status) == PJ_SUCCESS;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Proactor
+//
+class Pj_Proactor : public Pj_Object
+{
+public:
+ //
+ // Default constructor, initializes to NULL.
+ //
+ Pj_Proactor()
+ : ioq_(NULL), th_(NULL)
+ {
+ cb_.on_read_complete = &read_complete_cb;
+ cb_.on_write_complete = &write_complete_cb;
+ cb_.on_accept_complete = &accept_complete_cb;
+ cb_.on_connect_complete = &connect_complete_cb;
+ }
+
+ //
+ // Construct proactor.
+ //
+ Pj_Proactor( Pj_Pool *pool, pj_size_t max_fd,
+ pj_size_t max_timer_entries )
+ : ioq_(NULL), th_(NULL)
+ {
+ cb_.on_read_complete = &read_complete_cb;
+ cb_.on_write_complete = &write_complete_cb;
+ cb_.on_accept_complete = &accept_complete_cb;
+ cb_.on_connect_complete = &connect_complete_cb;
+
+ create(pool, max_fd, max_timer_entries);
+ }
+
+ //
+ // Destructor.
+ //
+ ~Pj_Proactor()
+ {
+ destroy();
+ }
+
+ //
+ // Create proactor.
+ //
+ pj_status_t create( Pj_Pool *pool, pj_size_t max_fd,
+ pj_size_t timer_entry_count)
+ {
+ pj_status_t status;
+
+ destroy();
+
+ status = pj_ioqueue_create(pool->pool_(), max_fd, &ioq_);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ status = pj_timer_heap_create(pool->pool_(),
+ timer_entry_count, &th_);
+ if (status != PJ_SUCCESS) {
+ pj_ioqueue_destroy(ioq_);
+ ioq_ = NULL;
+ return NULL;
+ }
+
+ return status;
+ }
+
+ //
+ // Destroy proactor.
+ //
+ void destroy()
+ {
+ if (ioq_) {
+ pj_ioqueue_destroy(ioq_);
+ ioq_ = NULL;
+ }
+ if (th_) {
+ pj_timer_heap_destroy(th_);
+ th_ = NULL;
+ }
+ }
+
+ //
+ // Register handler.
+ // This will call handler->get_socket_handle()
+ //
+ pj_status_t register_socket_handler(Pj_Pool *pool,
+ Pj_Event_Handler *handler)
+ {
+ return pj_ioqueue_register_sock( pool->pool_(), ioq_,
+ handler->get_socket_handle(),
+ handler, &cb_, &handler->key_ );
+ }
+
+ //
+ // Unregister handler.
+ //
+ static void unregister_handler(Pj_Event_Handler *handler)
+ {
+ if (handler->key_) {
+ pj_ioqueue_unregister( handler->key_ );
+ handler->key_ = NULL;
+ }
+ }
+
+ //
+ // Scheduler timer.
+ //
+ bool schedule_timer( Pj_Event_Handler *handler,
+ const Pj_Time_Val &delay,
+ int id=-1)
+ {
+ return schedule_timer(th_, handler, delay, id);
+ }
+
+ //
+ // Cancel timer.
+ //
+ bool cancel_timer(Pj_Event_Handler *handler)
+ {
+ return pj_timer_heap_cancel(th_, &handler->timer_) == 1;
+ }
+
+ //
+ // Handle events.
+ //
+ int handle_events(Pj_Time_Val *max_timeout)
+ {
+ Pj_Time_Val timeout(0, 0);
+ int timer_count;
+
+ timer_count = pj_timer_heap_poll( th_, &timeout );
+
+ if (timeout.get_sec() < 0)
+ timeout.sec = PJ_MAXINT32;
+
+ /* If caller specifies maximum time to wait, then compare the value
+ * with the timeout to wait from timer, and use the minimum value.
+ */
+ if (max_timeout && timeout >= *max_timeout) {
+ timeout = *max_timeout;
+ }
+
+ /* Poll events in ioqueue. */
+ int ioqueue_count;
+
+ ioqueue_count = pj_ioqueue_poll(ioq_, &timeout);
+ if (ioqueue_count < 0)
+ return ioqueue_count;
+
+ return ioqueue_count + timer_count;
+ }
+
+ //
+ // Get the internal ioqueue object.
+ //
+ pj_ioqueue_t *get_io_queue()
+ {
+ return ioq_;
+ }
+
+ //
+ // Get the internal timer heap object.
+ //
+ pj_timer_heap_t *get_timer_heap()
+ {
+ return th_;
+ }
+
+private:
+ pj_ioqueue_t *ioq_;
+ pj_timer_heap_t *th_;
+ pj_ioqueue_callback cb_;
+
+ static bool schedule_timer( pj_timer_heap_t *timer,
+ Pj_Event_Handler *handler,
+ const Pj_Time_Val &delay,
+ int id=-1)
+ {
+ handler->timer_.id = id;
+ return pj_timer_heap_schedule(timer, &handler->timer_, &delay) == 0;
+ }
+
+
+ //
+ // Static read completion callback.
+ //
+ static void read_complete_cb( pj_ioqueue_key_t *key,
+ pj_ioqueue_op_key_t *op_key,
+ pj_ssize_t bytes_read)
+ {
+ Pj_Event_Handler *handler =
+ (Pj_Event_Handler*) pj_ioqueue_get_user_data(key);
+
+ handler->on_read_complete((Pj_Async_Op*)op_key, bytes_read);
+ }
+
+ //
+ // Static write completion callback.
+ //
+ static void write_complete_cb(pj_ioqueue_key_t *key,
+ pj_ioqueue_op_key_t *op_key,
+ pj_ssize_t bytes_sent)
+ {
+ Pj_Event_Handler *handler =
+ (Pj_Event_Handler*) pj_ioqueue_get_user_data(key);
+
+ handler->on_write_complete((Pj_Async_Op*)op_key, bytes_sent);
+ }
+
+ //
+ // Static accept completion callback.
+ //
+ static void accept_complete_cb(pj_ioqueue_key_t *key,
+ pj_ioqueue_op_key_t *op_key,
+ pj_sock_t new_sock,
+ pj_status_t status)
+ {
+ Pj_Event_Handler *handler =
+ (Pj_Event_Handler*) pj_ioqueue_get_user_data(key);
+
+ handler->on_accept_complete((Pj_Async_Op*)op_key, new_sock, status);
+ }
+
+ //
+ // Static connect completion callback.
+ //
+ static void connect_complete_cb(pj_ioqueue_key_t *key,
+ pj_status_t status)
+ {
+ Pj_Event_Handler *handler =
+ (Pj_Event_Handler*) pj_ioqueue_get_user_data(key);
+
+ handler->on_connect_complete(status);
+ }
+
+};
+
+#endif /* __PJPP_PROACTOR_HPP__ */
+
diff --git a/pjlib/include/pj++/scanner.hpp b/pjlib/include/pj++/scanner.hpp index 8a3d9897..2131d4df 100644 --- a/pjlib/include/pj++/scanner.hpp +++ b/pjlib/include/pj++/scanner.hpp @@ -1,173 +1,194 @@ -/* $Id$ - */ -#ifndef __PJPP_SCANNER_HPP__ -#define __PJPP_SCANNER_HPP__ - -#include <pjlib-util/scanner.h> -#include <pj++/string.hpp> - -class Pj_Char_Spec -{ -public: - Pj_Char_Spec() { pj_cs_init(cs__); } - - void set(int c) { pj_cs_set(cs__, c); } - void add_range(int begin, int end) { pj_cs_add_range(cs__, begin, end); } - void add_alpha() { pj_cs_add_alpha(cs__); } - void add_num() { pj_cs_add_num(cs__); } - void add_str(const char *str) { pj_cs_add_str(cs__, str); } - void del_range(int begin, int end) { pj_cs_del_range(cs__, begin, end); } - void del_str(const char *str) { pj_cs_del_str(cs__, str); } - void invert() { pj_cs_invert(cs__); } - int match(int c) { return pj_cs_match(cs__, c); } - - pj_char_spec_element_t *cs_() - { - return cs__; - } - - const pj_char_spec_element_t *cs_() const - { - return cs__; - } - -private: - pj_char_spec cs__; -}; - -class Pj_Scanner -{ -public: - Pj_Scanner() {} - - enum - { - SYNTAX_ERROR = 101 - }; - static void syntax_error_handler_throw_pj(pj_scanner *); - - typedef pj_scan_state State; - - void init(char *buf, int len, unsigned options=PJ_SCAN_AUTOSKIP_WS, - pj_syn_err_func_ptr callback = &syntax_error_handler_throw_pj) - { - pj_scan_init(&scanner_, buf, len, options, callback); - } - - void fini() - { - pj_scan_fini(&scanner_); - } - - int eof() const - { - return pj_scan_is_eof(&scanner_); - } - - int peek_char() const - { - return *scanner_.curptr; - } - - int peek(const Pj_Char_Spec *cs, Pj_String *out) - { - return pj_scan_peek(&scanner_, cs->cs_(), out); - } - - int peek_n(pj_size_t len, Pj_String *out) - { - return pj_scan_peek_n(&scanner_, len, out); - } - - int peek_until(const Pj_Char_Spec *cs, Pj_String *out) - { - return pj_scan_peek_until(&scanner_, cs->cs_(), out); - } - - void get(const Pj_Char_Spec *cs, Pj_String *out) - { - pj_scan_get(&scanner_, cs->cs_(), out); - } - - void get_n(unsigned N, Pj_String *out) - { - pj_scan_get_n(&scanner_, N, out); - } - - int get_char() - { - return pj_scan_get_char(&scanner_); - } - - void get_quote(int begin_quote, int end_quote, Pj_String *out) - { - pj_scan_get_quote(&scanner_, begin_quote, end_quote, out); - } - - void get_newline() - { - pj_scan_get_newline(&scanner_); - } - - void get_until(const Pj_Char_Spec *cs, Pj_String *out) - { - pj_scan_get_until(&scanner_, cs->cs_(), out); - } - - void get_until_ch(int until_ch, Pj_String *out) - { - pj_scan_get_until_ch(&scanner_, until_ch, out); - } - - void get_until_chr(const char *spec, Pj_String *out) - { - pj_scan_get_until_chr(&scanner_, spec, out); - } - - void advance_n(unsigned N, bool skip_ws=true) - { - pj_scan_advance_n(&scanner_, N, skip_ws); - } - - int strcmp(const char *s, int len) - { - return pj_scan_strcmp(&scanner_, s, len); - } - - int stricmp(const char *s, int len) - { - return pj_scan_stricmp(&scanner_, s, len); - } - - void skip_ws() - { - pj_scan_skip_whitespace(&scanner_); - } - - void save_state(State *state) - { - pj_scan_save_state(&scanner_, state); - } - - void restore_state(State *state) - { - pj_scan_restore_state(&scanner_, state); - } - - int get_pos_line() const - { - return scanner_.line; - } - - int get_pos_col() const - { - return scanner_.col; - } - - -private: - pj_scanner scanner_; -}; - -#endif /* __PJPP_SCANNER_HPP__ */ - +/* $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 __PJPP_SCANNER_HPP__
+#define __PJPP_SCANNER_HPP__
+
+#include <pjlib-util/scanner.h>
+#include <pj++/string.hpp>
+
+class Pj_Char_Spec
+{
+public:
+ Pj_Char_Spec() { pj_cs_init(cs__); }
+
+ void set(int c) { pj_cs_set(cs__, c); }
+ void add_range(int begin, int end) { pj_cs_add_range(cs__, begin, end); }
+ void add_alpha() { pj_cs_add_alpha(cs__); }
+ void add_num() { pj_cs_add_num(cs__); }
+ void add_str(const char *str) { pj_cs_add_str(cs__, str); }
+ void del_range(int begin, int end) { pj_cs_del_range(cs__, begin, end); }
+ void del_str(const char *str) { pj_cs_del_str(cs__, str); }
+ void invert() { pj_cs_invert(cs__); }
+ int match(int c) { return pj_cs_match(cs__, c); }
+
+ pj_char_spec_element_t *cs_()
+ {
+ return cs__;
+ }
+
+ const pj_char_spec_element_t *cs_() const
+ {
+ return cs__;
+ }
+
+private:
+ pj_char_spec cs__;
+};
+
+class Pj_Scanner
+{
+public:
+ Pj_Scanner() {}
+
+ enum
+ {
+ SYNTAX_ERROR = 101
+ };
+ static void syntax_error_handler_throw_pj(pj_scanner *);
+
+ typedef pj_scan_state State;
+
+ void init(char *buf, int len, unsigned options=PJ_SCAN_AUTOSKIP_WS,
+ pj_syn_err_func_ptr callback = &syntax_error_handler_throw_pj)
+ {
+ pj_scan_init(&scanner_, buf, len, options, callback);
+ }
+
+ void fini()
+ {
+ pj_scan_fini(&scanner_);
+ }
+
+ int eof() const
+ {
+ return pj_scan_is_eof(&scanner_);
+ }
+
+ int peek_char() const
+ {
+ return *scanner_.curptr;
+ }
+
+ int peek(const Pj_Char_Spec *cs, Pj_String *out)
+ {
+ return pj_scan_peek(&scanner_, cs->cs_(), out);
+ }
+
+ int peek_n(pj_size_t len, Pj_String *out)
+ {
+ return pj_scan_peek_n(&scanner_, len, out);
+ }
+
+ int peek_until(const Pj_Char_Spec *cs, Pj_String *out)
+ {
+ return pj_scan_peek_until(&scanner_, cs->cs_(), out);
+ }
+
+ void get(const Pj_Char_Spec *cs, Pj_String *out)
+ {
+ pj_scan_get(&scanner_, cs->cs_(), out);
+ }
+
+ void get_n(unsigned N, Pj_String *out)
+ {
+ pj_scan_get_n(&scanner_, N, out);
+ }
+
+ int get_char()
+ {
+ return pj_scan_get_char(&scanner_);
+ }
+
+ void get_quote(int begin_quote, int end_quote, Pj_String *out)
+ {
+ pj_scan_get_quote(&scanner_, begin_quote, end_quote, out);
+ }
+
+ void get_newline()
+ {
+ pj_scan_get_newline(&scanner_);
+ }
+
+ void get_until(const Pj_Char_Spec *cs, Pj_String *out)
+ {
+ pj_scan_get_until(&scanner_, cs->cs_(), out);
+ }
+
+ void get_until_ch(int until_ch, Pj_String *out)
+ {
+ pj_scan_get_until_ch(&scanner_, until_ch, out);
+ }
+
+ void get_until_chr(const char *spec, Pj_String *out)
+ {
+ pj_scan_get_until_chr(&scanner_, spec, out);
+ }
+
+ void advance_n(unsigned N, bool skip_ws=true)
+ {
+ pj_scan_advance_n(&scanner_, N, skip_ws);
+ }
+
+ int strcmp(const char *s, int len)
+ {
+ return pj_scan_strcmp(&scanner_, s, len);
+ }
+
+ int stricmp(const char *s, int len)
+ {
+ return pj_scan_stricmp(&scanner_, s, len);
+ }
+
+ void skip_ws()
+ {
+ pj_scan_skip_whitespace(&scanner_);
+ }
+
+ void save_state(State *state)
+ {
+ pj_scan_save_state(&scanner_, state);
+ }
+
+ void restore_state(State *state)
+ {
+ pj_scan_restore_state(&scanner_, state);
+ }
+
+ int get_pos_line() const
+ {
+ return scanner_.line;
+ }
+
+ int get_pos_col() const
+ {
+ return scanner_.col;
+ }
+
+
+private:
+ pj_scanner scanner_;
+};
+
+#endif /* __PJPP_SCANNER_HPP__ */
+
diff --git a/pjlib/include/pj++/sock.hpp b/pjlib/include/pj++/sock.hpp index f1a1e45f..3a401b04 100644 --- a/pjlib/include/pj++/sock.hpp +++ b/pjlib/include/pj++/sock.hpp @@ -1,427 +1,448 @@ -/* $Id$ - */ -#ifndef __PJPP_SOCK_HPP__ -#define __PJPP_SOCK_HPP__ - -#include <pj/sock.h> -#include <pj/string.h> - -class Pj_Event_Handler; - -// -// Base class for address. -// -class Pj_Addr -{ -}; - -// -// Internet address. -// -class Pj_Inet_Addr : public pj_sockaddr_in, public Pj_Addr -{ -public: - // - // Get port number. - // - pj_uint16_t get_port_number() const - { - return pj_sockaddr_in_get_port(this); - } - - // - // Set port number. - // - void set_port_number(pj_uint16_t port) - { - sin_family = PJ_AF_INET; - pj_sockaddr_in_set_port(this, port); - } - - // - // Get IP address. - // - pj_uint32_t get_ip_address() const - { - return pj_sockaddr_in_get_addr(this).s_addr; - } - - // - // Get address string. - // - const char *get_address() const - { - return pj_inet_ntoa(sin_addr); - } - - // - // Set IP address. - // - void set_ip_address(pj_uint32_t addr) - { - sin_family = PJ_AF_INET; - pj_sockaddr_in_set_addr(this, addr); - } - - // - // Set address. - // - pj_status_t set_address(const pj_str_t *addr) - { - return pj_sockaddr_in_set_str_addr(this, addr); - } - - // - // Set address. - // - pj_status_t set_address(const char *addr) - { - pj_str_t s; - return pj_sockaddr_in_set_str_addr(this, pj_cstr(&s, addr)); - } - - // - // Compare for equality. - // - bool operator==(const Pj_Inet_Addr &rhs) const - { - return sin_family == rhs.sin_family && - sin_addr.s_addr == rhs.sin_addr.s_addr && - sin_port == rhs.sin_port; - } - -private: - // - // Dummy length used in pj_ioqueue_recvfrom() etc - // - friend class Pj_Event_Handler; - friend class Pj_Socket; - friend class Pj_Sock_Stream; - friend class Pj_Sock_Dgram; - - int addrlen_; -}; - - -// -// Socket base class. -// -// Note: -// socket will not automatically be closed on destructor. -// -class Pj_Socket -{ -public: - // - // Default constructor. - // - Pj_Socket() - : sock_(PJ_INVALID_SOCKET) - { - } - - // - // Initialize from a socket handle. - // - explicit Pj_Socket(pj_sock_t sock) - : sock_(sock) - { - } - - // - // Copy constructor. - // - Pj_Socket(const Pj_Socket &rhs) - : sock_(rhs.sock_) - { - } - - // - // Destructor will not close the socket. - // You must call close() explicitly. - // - ~Pj_Socket() - { - } - - // - // Set socket handle. - // - void set_handle(pj_sock_t sock) - { - sock_ = sock; - } - - // - // Get socket handle. - // - pj_sock_t get_handle() const - { - return sock_; - } - - // - // Get socket handle. - // - pj_sock_t& get_handle() - { - return sock_; - } - - // - // See if the socket is valid. - // - bool is_valid() const - { - return sock_ != PJ_INVALID_SOCKET; - } - - // - // Create the socket. - // - pj_status_t create(int af, int type, int proto) - { - return pj_sock_socket(af, type, proto, &sock_); - } - - // - // Bind socket. - // - pj_status_t bind(const Pj_Inet_Addr &addr) - { - return pj_sock_bind(sock_, &addr, sizeof(Pj_Inet_Addr)); - } - - // - // Close socket. - // - pj_status_t close() - { - pj_sock_close(sock_); - } - - // - // Get peer socket name. - // - pj_status_t getpeername(Pj_Inet_Addr *addr) - { - return pj_sock_getpeername(sock_, addr, &addr->addrlen_); - } - - // - // getsockname - // - pj_status_t getsockname(Pj_Inet_Addr *addr) - { - return pj_sock_getsockname(sock_, addr, &addr->addrlen_); - } - - // - // getsockopt. - // - pj_status_t getsockopt(int level, int optname, - void *optval, int *optlen) - { - return pj_sock_getsockopt(sock_, level, optname, optval, optlen); - } - - // - // setsockopt - // - pj_status_t setsockopt(int level, int optname, - const void *optval, int optlen) - { - return pj_sock_setsockopt(sock_, level, optname, optval, optlen); - } - - // - // receive data. - // - pj_ssize_t recv(void *buf, pj_size_t len, int flag = 0) - { - pj_ssize_t bytes = len; - if (pj_sock_recv(sock_, buf, &bytes, flag) != PJ_SUCCESS) - return -1; - return bytes; - } - - // - // send data. - // - pj_ssize_t send(const void *buf, pj_ssize_t len, int flag = 0) - { - pj_ssize_t bytes = len; - if (pj_sock_send(sock_, buf, &bytes, flag) != PJ_SUCCESS) - return -1; - return bytes; - } - - // - // connect. - // - pj_status_t connect(const Pj_Inet_Addr &addr) - { - return pj_sock_connect(sock_, &addr, sizeof(Pj_Inet_Addr)); - } - - // - // assignment. - // - Pj_Socket &operator=(const Pj_Socket &rhs) - { - sock_ = rhs.sock_; - return *this; - } - -protected: - friend class Pj_Event_Handler; - pj_sock_t sock_; -}; - - -#if PJ_HAS_TCP -// -// Stream socket. -// -class Pj_Sock_Stream : public Pj_Socket -{ -public: - // - // Default constructor. - // - Pj_Sock_Stream() - { - } - - // - // Initialize from a socket handle. - // - explicit Pj_Sock_Stream(pj_sock_t sock) - : Pj_Socket(sock) - { - } - - // - // Copy constructor. - // - Pj_Sock_Stream(const Pj_Sock_Stream &rhs) : Pj_Socket(rhs) - { - } - - // - // Assignment. - // - Pj_Sock_Stream &operator=(const Pj_Sock_Stream &rhs) - { - sock_ = rhs.sock_; - return *this; - } - - // - // listen() - // - pj_status_t listen(int backlog = 5) - { - return pj_sock_listen(sock_, backlog); - } - - // - // blocking accept() - // - Pj_Sock_Stream accept(Pj_Inet_Addr *remote_addr = NULL) - { - pj_sock_t newsock; - int *addrlen = remote_addr ? &remote_addr->addrlen_ : NULL; - pj_status_t status; - - status = pj_sock_accept(sock_, &newsock, remote_addr, addrlen); - if (status != PJ_SUCCESS) - return Pj_Sock_Stream(-1); - - return Pj_Sock_Stream(newsock); - } - - // - // shutdown() - // - pj_status_t shutdown(int how = PJ_SHUT_RDWR) - { - return pj_sock_shutdown(sock_, how); - } - -}; -#endif - -// -// Datagram socket. -// -class Pj_Sock_Dgram : public Pj_Socket -{ -public: - // - // Default constructor. - // - Pj_Sock_Dgram() - { - } - - // - // Initialize from a socket handle. - // - explicit Pj_Sock_Dgram(pj_sock_t sock) - : Pj_Socket(sock) - { - } - - // - // Copy constructor. - // - Pj_Sock_Dgram(const Pj_Sock_Dgram &rhs) - : Pj_Socket(rhs) - { - } - - // - // Assignment. - // - Pj_Sock_Dgram &operator=(const Pj_Sock_Dgram &rhs) - { - Pj_Socket::operator =(rhs); - return *this; - } - - // - // recvfrom() - // - pj_ssize_t recvfrom( void *buf, pj_size_t len, int flag = 0, - Pj_Inet_Addr *fromaddr = NULL) - { - pj_ssize_t bytes = len; - int *addrlen = fromaddr ? &fromaddr->addrlen_ : NULL; - if (pj_sock_recvfrom( sock_, buf, &bytes, flag, - fromaddr, addrlen) != PJ_SUCCESS) - { - return -1; - } - return bytes; - } - - // - // sendto() - // - pj_ssize_t sendto( const void *buf, pj_size_t len, int flag, - const Pj_Inet_Addr &addr) - { - pj_ssize_t bytes = len; - if (pj_sock_sendto( sock_, buf, &bytes, flag, - &addr, sizeof(pj_sockaddr_in)) != PJ_SUCCESS) - { - return -1; - } - return bytes; - } -}; - - -#endif /* __PJPP_SOCK_HPP__ */ - +/* $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 __PJPP_SOCK_HPP__
+#define __PJPP_SOCK_HPP__
+
+#include <pj/sock.h>
+#include <pj/string.h>
+
+class Pj_Event_Handler;
+
+//
+// Base class for address.
+//
+class Pj_Addr
+{
+};
+
+//
+// Internet address.
+//
+class Pj_Inet_Addr : public pj_sockaddr_in, public Pj_Addr
+{
+public:
+ //
+ // Get port number.
+ //
+ pj_uint16_t get_port_number() const
+ {
+ return pj_sockaddr_in_get_port(this);
+ }
+
+ //
+ // Set port number.
+ //
+ void set_port_number(pj_uint16_t port)
+ {
+ sin_family = PJ_AF_INET;
+ pj_sockaddr_in_set_port(this, port);
+ }
+
+ //
+ // Get IP address.
+ //
+ pj_uint32_t get_ip_address() const
+ {
+ return pj_sockaddr_in_get_addr(this).s_addr;
+ }
+
+ //
+ // Get address string.
+ //
+ const char *get_address() const
+ {
+ return pj_inet_ntoa(sin_addr);
+ }
+
+ //
+ // Set IP address.
+ //
+ void set_ip_address(pj_uint32_t addr)
+ {
+ sin_family = PJ_AF_INET;
+ pj_sockaddr_in_set_addr(this, addr);
+ }
+
+ //
+ // Set address.
+ //
+ pj_status_t set_address(const pj_str_t *addr)
+ {
+ return pj_sockaddr_in_set_str_addr(this, addr);
+ }
+
+ //
+ // Set address.
+ //
+ pj_status_t set_address(const char *addr)
+ {
+ pj_str_t s;
+ return pj_sockaddr_in_set_str_addr(this, pj_cstr(&s, addr));
+ }
+
+ //
+ // Compare for equality.
+ //
+ bool operator==(const Pj_Inet_Addr &rhs) const
+ {
+ return sin_family == rhs.sin_family &&
+ sin_addr.s_addr == rhs.sin_addr.s_addr &&
+ sin_port == rhs.sin_port;
+ }
+
+private:
+ //
+ // Dummy length used in pj_ioqueue_recvfrom() etc
+ //
+ friend class Pj_Event_Handler;
+ friend class Pj_Socket;
+ friend class Pj_Sock_Stream;
+ friend class Pj_Sock_Dgram;
+
+ int addrlen_;
+};
+
+
+//
+// Socket base class.
+//
+// Note:
+// socket will not automatically be closed on destructor.
+//
+class Pj_Socket
+{
+public:
+ //
+ // Default constructor.
+ //
+ Pj_Socket()
+ : sock_(PJ_INVALID_SOCKET)
+ {
+ }
+
+ //
+ // Initialize from a socket handle.
+ //
+ explicit Pj_Socket(pj_sock_t sock)
+ : sock_(sock)
+ {
+ }
+
+ //
+ // Copy constructor.
+ //
+ Pj_Socket(const Pj_Socket &rhs)
+ : sock_(rhs.sock_)
+ {
+ }
+
+ //
+ // Destructor will not close the socket.
+ // You must call close() explicitly.
+ //
+ ~Pj_Socket()
+ {
+ }
+
+ //
+ // Set socket handle.
+ //
+ void set_handle(pj_sock_t sock)
+ {
+ sock_ = sock;
+ }
+
+ //
+ // Get socket handle.
+ //
+ pj_sock_t get_handle() const
+ {
+ return sock_;
+ }
+
+ //
+ // Get socket handle.
+ //
+ pj_sock_t& get_handle()
+ {
+ return sock_;
+ }
+
+ //
+ // See if the socket is valid.
+ //
+ bool is_valid() const
+ {
+ return sock_ != PJ_INVALID_SOCKET;
+ }
+
+ //
+ // Create the socket.
+ //
+ pj_status_t create(int af, int type, int proto)
+ {
+ return pj_sock_socket(af, type, proto, &sock_);
+ }
+
+ //
+ // Bind socket.
+ //
+ pj_status_t bind(const Pj_Inet_Addr &addr)
+ {
+ return pj_sock_bind(sock_, &addr, sizeof(Pj_Inet_Addr));
+ }
+
+ //
+ // Close socket.
+ //
+ pj_status_t close()
+ {
+ pj_sock_close(sock_);
+ }
+
+ //
+ // Get peer socket name.
+ //
+ pj_status_t getpeername(Pj_Inet_Addr *addr)
+ {
+ return pj_sock_getpeername(sock_, addr, &addr->addrlen_);
+ }
+
+ //
+ // getsockname
+ //
+ pj_status_t getsockname(Pj_Inet_Addr *addr)
+ {
+ return pj_sock_getsockname(sock_, addr, &addr->addrlen_);
+ }
+
+ //
+ // getsockopt.
+ //
+ pj_status_t getsockopt(int level, int optname,
+ void *optval, int *optlen)
+ {
+ return pj_sock_getsockopt(sock_, level, optname, optval, optlen);
+ }
+
+ //
+ // setsockopt
+ //
+ pj_status_t setsockopt(int level, int optname,
+ const void *optval, int optlen)
+ {
+ return pj_sock_setsockopt(sock_, level, optname, optval, optlen);
+ }
+
+ //
+ // receive data.
+ //
+ pj_ssize_t recv(void *buf, pj_size_t len, int flag = 0)
+ {
+ pj_ssize_t bytes = len;
+ if (pj_sock_recv(sock_, buf, &bytes, flag) != PJ_SUCCESS)
+ return -1;
+ return bytes;
+ }
+
+ //
+ // send data.
+ //
+ pj_ssize_t send(const void *buf, pj_ssize_t len, int flag = 0)
+ {
+ pj_ssize_t bytes = len;
+ if (pj_sock_send(sock_, buf, &bytes, flag) != PJ_SUCCESS)
+ return -1;
+ return bytes;
+ }
+
+ //
+ // connect.
+ //
+ pj_status_t connect(const Pj_Inet_Addr &addr)
+ {
+ return pj_sock_connect(sock_, &addr, sizeof(Pj_Inet_Addr));
+ }
+
+ //
+ // assignment.
+ //
+ Pj_Socket &operator=(const Pj_Socket &rhs)
+ {
+ sock_ = rhs.sock_;
+ return *this;
+ }
+
+protected:
+ friend class Pj_Event_Handler;
+ pj_sock_t sock_;
+};
+
+
+#if PJ_HAS_TCP
+//
+// Stream socket.
+//
+class Pj_Sock_Stream : public Pj_Socket
+{
+public:
+ //
+ // Default constructor.
+ //
+ Pj_Sock_Stream()
+ {
+ }
+
+ //
+ // Initialize from a socket handle.
+ //
+ explicit Pj_Sock_Stream(pj_sock_t sock)
+ : Pj_Socket(sock)
+ {
+ }
+
+ //
+ // Copy constructor.
+ //
+ Pj_Sock_Stream(const Pj_Sock_Stream &rhs) : Pj_Socket(rhs)
+ {
+ }
+
+ //
+ // Assignment.
+ //
+ Pj_Sock_Stream &operator=(const Pj_Sock_Stream &rhs)
+ {
+ sock_ = rhs.sock_;
+ return *this;
+ }
+
+ //
+ // listen()
+ //
+ pj_status_t listen(int backlog = 5)
+ {
+ return pj_sock_listen(sock_, backlog);
+ }
+
+ //
+ // blocking accept()
+ //
+ Pj_Sock_Stream accept(Pj_Inet_Addr *remote_addr = NULL)
+ {
+ pj_sock_t newsock;
+ int *addrlen = remote_addr ? &remote_addr->addrlen_ : NULL;
+ pj_status_t status;
+
+ status = pj_sock_accept(sock_, &newsock, remote_addr, addrlen);
+ if (status != PJ_SUCCESS)
+ return Pj_Sock_Stream(-1);
+
+ return Pj_Sock_Stream(newsock);
+ }
+
+ //
+ // shutdown()
+ //
+ pj_status_t shutdown(int how = PJ_SHUT_RDWR)
+ {
+ return pj_sock_shutdown(sock_, how);
+ }
+
+};
+#endif
+
+//
+// Datagram socket.
+//
+class Pj_Sock_Dgram : public Pj_Socket
+{
+public:
+ //
+ // Default constructor.
+ //
+ Pj_Sock_Dgram()
+ {
+ }
+
+ //
+ // Initialize from a socket handle.
+ //
+ explicit Pj_Sock_Dgram(pj_sock_t sock)
+ : Pj_Socket(sock)
+ {
+ }
+
+ //
+ // Copy constructor.
+ //
+ Pj_Sock_Dgram(const Pj_Sock_Dgram &rhs)
+ : Pj_Socket(rhs)
+ {
+ }
+
+ //
+ // Assignment.
+ //
+ Pj_Sock_Dgram &operator=(const Pj_Sock_Dgram &rhs)
+ {
+ Pj_Socket::operator =(rhs);
+ return *this;
+ }
+
+ //
+ // recvfrom()
+ //
+ pj_ssize_t recvfrom( void *buf, pj_size_t len, int flag = 0,
+ Pj_Inet_Addr *fromaddr = NULL)
+ {
+ pj_ssize_t bytes = len;
+ int *addrlen = fromaddr ? &fromaddr->addrlen_ : NULL;
+ if (pj_sock_recvfrom( sock_, buf, &bytes, flag,
+ fromaddr, addrlen) != PJ_SUCCESS)
+ {
+ return -1;
+ }
+ return bytes;
+ }
+
+ //
+ // sendto()
+ //
+ pj_ssize_t sendto( const void *buf, pj_size_t len, int flag,
+ const Pj_Inet_Addr &addr)
+ {
+ pj_ssize_t bytes = len;
+ if (pj_sock_sendto( sock_, buf, &bytes, flag,
+ &addr, sizeof(pj_sockaddr_in)) != PJ_SUCCESS)
+ {
+ return -1;
+ }
+ return bytes;
+ }
+};
+
+
+#endif /* __PJPP_SOCK_HPP__ */
+
diff --git a/pjlib/include/pj++/string.hpp b/pjlib/include/pj++/string.hpp index 6be1e50a..dbb2d57f 100644 --- a/pjlib/include/pj++/string.hpp +++ b/pjlib/include/pj++/string.hpp @@ -1,409 +1,430 @@ -/* $Id$ - */ -#ifndef __PJPP_STRING_HPP__ -#define __PJPP_STRING_HPP__ - -#include <pj/string.h> -#include <pj++/pool.hpp> -#include <pj/assert.h> - -// -// String wrapper class for pj_str_t. -// -class Pj_String : public pj_str_t -{ -public: - // - // Default constructor. - // - Pj_String() - { - pj_assert(sizeof(Pj_String) == sizeof(pj_str_t)); - ptr=NULL; - slen=0; - } - - // - // Construct the buffer from a char*. - // - explicit Pj_String(char *str) - { - set(str); - } - - // - // Construct from a const char*. - // - Pj_String(Pj_Pool *pool, const char *src) - { - set(pool, src); - } - - // - // Construct from pj_str_t*. - // - explicit Pj_String(pj_str_t *s) - { - set(s); - } - - // - // Construct by copying from const pj_str_t*. - // - Pj_String(Pj_Pool *pool, const pj_str_t *s) - { - set(pool, s); - } - - // - // Construct from another Pj_String - // - explicit Pj_String(Pj_String &rhs) - { - set(rhs); - } - - // - // Construct by copying from Pj_String - // - Pj_String(Pj_Pool *pool, const Pj_String &rhs) - { - set(pool, rhs); - } - - // - // Construct from a char* and a length. - // - Pj_String(char *str, pj_size_t len) - { - set(str, len); - } - - // - // Construct from pair of pointer. - // - Pj_String(char *begin, char *end) - { - pj_strset3(this, begin, end); - } - - // - // Get the length of the string. - // - pj_size_t length() const - { - return pj_strlen(this); - } - - // - // Get the length of the string. - // - pj_size_t size() const - { - return length(); - } - - // - // Get the string buffer. - // - const char *buf() const - { - return ptr; - } - - // - // Initialize buffer from char*. - // - void set(char *str) - { - pj_strset2(this, str); - } - - // - // Initialize by copying from a const char*. - // - void set(Pj_Pool *pool, const char *s) - { - pj_strdup2(pool->pool_(), this, s); - } - - // - // Initialize from pj_str_t*. - // - void set(pj_str_t *s) - { - pj_strassign(this, s); - } - - // - // Initialize by copying from const pj_str_t*. - // - void set(Pj_Pool *pool, const pj_str_t *s) - { - pj_strdup(pool->pool_(), this, s); - } - - // - // Initialize from char* and length. - // - void set(char *str, pj_size_t len) - { - pj_strset(this, str, len); - } - - // - // Initialize from pair of pointers. - // - void set(char *begin, char *end) - { - pj_strset3(this, begin, end); - } - - // - // Initialize from other Pj_String. - // - void set(Pj_String &rhs) - { - pj_strassign(this, &rhs); - } - - // - // Initialize by copying from a Pj_String*. - // - void set(Pj_Pool *pool, const Pj_String *s) - { - pj_strdup(pool->pool_(), this, s); - } - - // - // Initialize by copying from other Pj_String. - // - void set(Pj_Pool *pool, const Pj_String &s) - { - pj_strdup(pool->pool_(), this, &s); - } - - // - // Copy the contents of other string. - // - void strcpy(const pj_str_t *s) - { - pj_strcpy(this, s); - } - - // - // Copy the contents of other string. - // - void strcpy(const Pj_String &rhs) - { - pj_strcpy(this, &rhs); - } - - // - // Copy the contents of other string. - // - void strcpy(const char *s) - { - pj_strcpy2(this, s); - } - - // - // Compare string. - // - int strcmp(const char *s) const - { - return pj_strcmp2(this, s); - } - - // - // Compare string. - // - int strcmp(const pj_str_t *s) const - { - return pj_strcmp(this, s); - } - - // - // Compare string. - // - int strcmp(const Pj_String &rhs) const - { - return pj_strcmp(this, &rhs); - } - - // - // Compare string. - // - int strncmp(const char *s, pj_size_t len) const - { - return pj_strncmp2(this, s, len); - } - - // - // Compare string. - // - int strncmp(const pj_str_t *s, pj_size_t len) const - { - return pj_strncmp(this, s, len); - } - - // - // Compare string. - // - int strncmp(const Pj_String &rhs, pj_size_t len) const - { - return pj_strncmp(this, &rhs, len); - } - - // - // Compare string. - // - int stricmp(const char *s) const - { - return pj_stricmp2(this, s); - } - - // - // Compare string. - // - int stricmp(const pj_str_t *s) const - { - return pj_stricmp(this, s); - } - - // - // Compare string. - // - int stricmp(const Pj_String &rhs) const - { - return stricmp(&rhs); - } - - // - // Compare string. - // - int strnicmp(const char *s, pj_size_t len) const - { - return pj_strnicmp2(this, s, len); - } - - // - // Compare string. - // - int strnicmp(const pj_str_t *s, pj_size_t len) const - { - return pj_strnicmp(this, s, len); - } - - // - // Compare string. - // - int strnicmp(const Pj_String &rhs, pj_size_t len) const - { - return strnicmp(&rhs, len); - } - - // - // Compare contents for equality. - // - bool operator==(const char *s) const - { - return strcmp(s) == 0; - } - - // - // Compare contents for equality. - // - bool operator==(const pj_str_t *s) const - { - return strcmp(s) == 0; - } - - // - // Compare contents for equality. - // - bool operator==(const Pj_String &rhs) const - { - return pj_strcmp(this, &rhs) == 0; - } - - // - // Find a character in the string. - // - char *strchr(int chr) - { - return pj_strchr(this, chr); - } - - // - // Find a character in the string. - // - char *find(int chr) - { - return strchr(chr); - } - - // - // Concatenate string. - // - void strcat(const Pj_String &rhs) - { - pj_strcat(this, &rhs); - } - - // - // Left trim. - // - void ltrim() - { - pj_strltrim(this); - } - - // - // Right trim. - // - void rtrim() - { - pj_strrtrim(this); - } - - // - // Left and right trim. - // - void trim() - { - pj_strtrim(this); - } - - // - // Convert to unsigned long. - // - unsigned long to_ulong() const - { - return pj_strtoul(this); - } - - // - // Convert from unsigned long. - // - void from_ulong(unsigned long value) - { - slen = pj_utoa(value, ptr); - } - - // - // Convert from unsigned long with padding. - // - void from_ulong_with_pad(unsigned long value, int min_dig=0, int pad=' ') - { - slen = pj_utoa_pad(value, ptr, min_dig, pad); - } - - -private: - //Pj_String(const Pj_String &rhs) {} - void operator=(const Pj_String &rhs) { pj_assert(false); } -}; - -#endif /* __PJPP_STRING_HPP__ */ - +/* $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 __PJPP_STRING_HPP__
+#define __PJPP_STRING_HPP__
+
+#include <pj/string.h>
+#include <pj++/pool.hpp>
+#include <pj/assert.h>
+
+//
+// String wrapper class for pj_str_t.
+//
+class Pj_String : public pj_str_t
+{
+public:
+ //
+ // Default constructor.
+ //
+ Pj_String()
+ {
+ pj_assert(sizeof(Pj_String) == sizeof(pj_str_t));
+ ptr=NULL;
+ slen=0;
+ }
+
+ //
+ // Construct the buffer from a char*.
+ //
+ explicit Pj_String(char *str)
+ {
+ set(str);
+ }
+
+ //
+ // Construct from a const char*.
+ //
+ Pj_String(Pj_Pool *pool, const char *src)
+ {
+ set(pool, src);
+ }
+
+ //
+ // Construct from pj_str_t*.
+ //
+ explicit Pj_String(pj_str_t *s)
+ {
+ set(s);
+ }
+
+ //
+ // Construct by copying from const pj_str_t*.
+ //
+ Pj_String(Pj_Pool *pool, const pj_str_t *s)
+ {
+ set(pool, s);
+ }
+
+ //
+ // Construct from another Pj_String
+ //
+ explicit Pj_String(Pj_String &rhs)
+ {
+ set(rhs);
+ }
+
+ //
+ // Construct by copying from Pj_String
+ //
+ Pj_String(Pj_Pool *pool, const Pj_String &rhs)
+ {
+ set(pool, rhs);
+ }
+
+ //
+ // Construct from a char* and a length.
+ //
+ Pj_String(char *str, pj_size_t len)
+ {
+ set(str, len);
+ }
+
+ //
+ // Construct from pair of pointer.
+ //
+ Pj_String(char *begin, char *end)
+ {
+ pj_strset3(this, begin, end);
+ }
+
+ //
+ // Get the length of the string.
+ //
+ pj_size_t length() const
+ {
+ return pj_strlen(this);
+ }
+
+ //
+ // Get the length of the string.
+ //
+ pj_size_t size() const
+ {
+ return length();
+ }
+
+ //
+ // Get the string buffer.
+ //
+ const char *buf() const
+ {
+ return ptr;
+ }
+
+ //
+ // Initialize buffer from char*.
+ //
+ void set(char *str)
+ {
+ pj_strset2(this, str);
+ }
+
+ //
+ // Initialize by copying from a const char*.
+ //
+ void set(Pj_Pool *pool, const char *s)
+ {
+ pj_strdup2(pool->pool_(), this, s);
+ }
+
+ //
+ // Initialize from pj_str_t*.
+ //
+ void set(pj_str_t *s)
+ {
+ pj_strassign(this, s);
+ }
+
+ //
+ // Initialize by copying from const pj_str_t*.
+ //
+ void set(Pj_Pool *pool, const pj_str_t *s)
+ {
+ pj_strdup(pool->pool_(), this, s);
+ }
+
+ //
+ // Initialize from char* and length.
+ //
+ void set(char *str, pj_size_t len)
+ {
+ pj_strset(this, str, len);
+ }
+
+ //
+ // Initialize from pair of pointers.
+ //
+ void set(char *begin, char *end)
+ {
+ pj_strset3(this, begin, end);
+ }
+
+ //
+ // Initialize from other Pj_String.
+ //
+ void set(Pj_String &rhs)
+ {
+ pj_strassign(this, &rhs);
+ }
+
+ //
+ // Initialize by copying from a Pj_String*.
+ //
+ void set(Pj_Pool *pool, const Pj_String *s)
+ {
+ pj_strdup(pool->pool_(), this, s);
+ }
+
+ //
+ // Initialize by copying from other Pj_String.
+ //
+ void set(Pj_Pool *pool, const Pj_String &s)
+ {
+ pj_strdup(pool->pool_(), this, &s);
+ }
+
+ //
+ // Copy the contents of other string.
+ //
+ void strcpy(const pj_str_t *s)
+ {
+ pj_strcpy(this, s);
+ }
+
+ //
+ // Copy the contents of other string.
+ //
+ void strcpy(const Pj_String &rhs)
+ {
+ pj_strcpy(this, &rhs);
+ }
+
+ //
+ // Copy the contents of other string.
+ //
+ void strcpy(const char *s)
+ {
+ pj_strcpy2(this, s);
+ }
+
+ //
+ // Compare string.
+ //
+ int strcmp(const char *s) const
+ {
+ return pj_strcmp2(this, s);
+ }
+
+ //
+ // Compare string.
+ //
+ int strcmp(const pj_str_t *s) const
+ {
+ return pj_strcmp(this, s);
+ }
+
+ //
+ // Compare string.
+ //
+ int strcmp(const Pj_String &rhs) const
+ {
+ return pj_strcmp(this, &rhs);
+ }
+
+ //
+ // Compare string.
+ //
+ int strncmp(const char *s, pj_size_t len) const
+ {
+ return pj_strncmp2(this, s, len);
+ }
+
+ //
+ // Compare string.
+ //
+ int strncmp(const pj_str_t *s, pj_size_t len) const
+ {
+ return pj_strncmp(this, s, len);
+ }
+
+ //
+ // Compare string.
+ //
+ int strncmp(const Pj_String &rhs, pj_size_t len) const
+ {
+ return pj_strncmp(this, &rhs, len);
+ }
+
+ //
+ // Compare string.
+ //
+ int stricmp(const char *s) const
+ {
+ return pj_stricmp2(this, s);
+ }
+
+ //
+ // Compare string.
+ //
+ int stricmp(const pj_str_t *s) const
+ {
+ return pj_stricmp(this, s);
+ }
+
+ //
+ // Compare string.
+ //
+ int stricmp(const Pj_String &rhs) const
+ {
+ return stricmp(&rhs);
+ }
+
+ //
+ // Compare string.
+ //
+ int strnicmp(const char *s, pj_size_t len) const
+ {
+ return pj_strnicmp2(this, s, len);
+ }
+
+ //
+ // Compare string.
+ //
+ int strnicmp(const pj_str_t *s, pj_size_t len) const
+ {
+ return pj_strnicmp(this, s, len);
+ }
+
+ //
+ // Compare string.
+ //
+ int strnicmp(const Pj_String &rhs, pj_size_t len) const
+ {
+ return strnicmp(&rhs, len);
+ }
+
+ //
+ // Compare contents for equality.
+ //
+ bool operator==(const char *s) const
+ {
+ return strcmp(s) == 0;
+ }
+
+ //
+ // Compare contents for equality.
+ //
+ bool operator==(const pj_str_t *s) const
+ {
+ return strcmp(s) == 0;
+ }
+
+ //
+ // Compare contents for equality.
+ //
+ bool operator==(const Pj_String &rhs) const
+ {
+ return pj_strcmp(this, &rhs) == 0;
+ }
+
+ //
+ // Find a character in the string.
+ //
+ char *strchr(int chr)
+ {
+ return pj_strchr(this, chr);
+ }
+
+ //
+ // Find a character in the string.
+ //
+ char *find(int chr)
+ {
+ return strchr(chr);
+ }
+
+ //
+ // Concatenate string.
+ //
+ void strcat(const Pj_String &rhs)
+ {
+ pj_strcat(this, &rhs);
+ }
+
+ //
+ // Left trim.
+ //
+ void ltrim()
+ {
+ pj_strltrim(this);
+ }
+
+ //
+ // Right trim.
+ //
+ void rtrim()
+ {
+ pj_strrtrim(this);
+ }
+
+ //
+ // Left and right trim.
+ //
+ void trim()
+ {
+ pj_strtrim(this);
+ }
+
+ //
+ // Convert to unsigned long.
+ //
+ unsigned long to_ulong() const
+ {
+ return pj_strtoul(this);
+ }
+
+ //
+ // Convert from unsigned long.
+ //
+ void from_ulong(unsigned long value)
+ {
+ slen = pj_utoa(value, ptr);
+ }
+
+ //
+ // Convert from unsigned long with padding.
+ //
+ void from_ulong_with_pad(unsigned long value, int min_dig=0, int pad=' ')
+ {
+ slen = pj_utoa_pad(value, ptr, min_dig, pad);
+ }
+
+
+private:
+ //Pj_String(const Pj_String &rhs) {}
+ void operator=(const Pj_String &rhs) { pj_assert(false); }
+};
+
+#endif /* __PJPP_STRING_HPP__ */
+
diff --git a/pjlib/include/pj++/timer.hpp b/pjlib/include/pj++/timer.hpp index fbb15f7a..7a5618d0 100644 --- a/pjlib/include/pj++/timer.hpp +++ b/pjlib/include/pj++/timer.hpp @@ -1,181 +1,202 @@ -/* $Id$ - */ -#ifndef __PJPP_TIMER_HPP__ -#define __PJPP_TIMER_HPP__ - -#include <pj/timer.h> -#include <pj++/types.hpp> -#include <pj/assert.h> -#include <pj++/lock.hpp> - -class Pj_Timer_Heap; - -////////////////////////////////////////////////////////////////////////////// -// Timer entry. -// -// How to use: -// Derive class from Pj_Timer_Entry and override on_timeout(). -// Scheduler timer in Pj_Timer_Heap. -// -class Pj_Timer_Entry : public Pj_Object -{ - friend class Pj_Timer_Heap; - -public: - // - // Default constructor. - // - Pj_Timer_Entry() - { - entry_.user_data = this; - entry_.cb = &timer_heap_callback; - } - - // - // Destructor, do nothing. - // - ~Pj_Timer_Entry() - { - } - - // - // Override this to get the timeout notification. - // - virtual void on_timeout(int id) = 0; - -private: - pj_timer_entry entry_; - - static void timer_heap_callback(pj_timer_heap_t *th, pj_timer_entry *e) - { - Pj_Timer_Entry *entry = (Pj_Timer_Entry*) e->user_data; - entry->on_timeout(e->id); - } - -}; - -////////////////////////////////////////////////////////////////////////////// -// Timer heap. -// -class Pj_Timer_Heap : public Pj_Object -{ -public: - // - // Default constructor. - // - Pj_Timer_Heap() - : ht_(NULL) - { - } - - // - // Construct timer heap. - // - Pj_Timer_Heap(Pj_Pool *pool, pj_size_t initial_count) - : ht_(NULL) - { - create(pool, initial_count); - } - - // - // Destructor. - // - ~Pj_Timer_Heap() - { - destroy(); - } - - // - // Create - // - pj_status_t create(Pj_Pool *pool, pj_size_t initial_count) - { - destroy(); - return pj_timer_heap_create(pool->pool_(), initial_count, &ht_); - } - - // - // Destroy - // - void destroy() - { - if (ht_) { - pj_timer_heap_destroy(ht_); - ht_ = NULL; - } - } - - // - // Get pjlib compatible timer heap object. - // - pj_timer_heap_t *get_timer_heap() - { - return ht_; - } - - // - // Set the lock object. - // - void set_lock( Pj_Lock *lock, bool auto_delete ) - { - pj_timer_heap_set_lock( ht_, lock->pj_lock_t_(), auto_delete); - } - - // - // Set maximum number of timed out entries to be processed per poll. - // - unsigned set_max_timed_out_per_poll(unsigned count) - { - return pj_timer_heap_set_max_timed_out_per_poll(ht_, count); - } - - // - // Schedule a timer. - // - bool schedule( Pj_Timer_Entry *ent, const Pj_Time_Val &delay, - int id) - { - ent->entry_.id = id; - return pj_timer_heap_schedule(ht_, &ent->entry_, &delay) == 0; - } - - // - // Cancel a timer. - // - bool cancel(Pj_Timer_Entry *ent) - { - return pj_timer_heap_cancel(ht_, &ent->entry_) == 1; - } - - // - // Get current number of timers - // - pj_size_t count() - { - return pj_timer_heap_count(ht_); - } - - // - // Get the earliest time. - // Return false if no timer is found. - // - bool earliest_time(Pj_Time_Val *t) - { - return pj_timer_heap_earliest_time(ht_, t) == PJ_SUCCESS; - } - - // - // Poll the timer. - // Return number of timed out entries has been called. - // - unsigned poll(Pj_Time_Val *next_delay = NULL) - { - return pj_timer_heap_poll(ht_, next_delay); - } - -private: - pj_timer_heap_t *ht_; -}; - -#endif /* __PJPP_TIMER_HPP__ */ - +/* $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 __PJPP_TIMER_HPP__
+#define __PJPP_TIMER_HPP__
+
+#include <pj/timer.h>
+#include <pj++/types.hpp>
+#include <pj/assert.h>
+#include <pj++/lock.hpp>
+
+class Pj_Timer_Heap;
+
+//////////////////////////////////////////////////////////////////////////////
+// Timer entry.
+//
+// How to use:
+// Derive class from Pj_Timer_Entry and override on_timeout().
+// Scheduler timer in Pj_Timer_Heap.
+//
+class Pj_Timer_Entry : public Pj_Object
+{
+ friend class Pj_Timer_Heap;
+
+public:
+ //
+ // Default constructor.
+ //
+ Pj_Timer_Entry()
+ {
+ entry_.user_data = this;
+ entry_.cb = &timer_heap_callback;
+ }
+
+ //
+ // Destructor, do nothing.
+ //
+ ~Pj_Timer_Entry()
+ {
+ }
+
+ //
+ // Override this to get the timeout notification.
+ //
+ virtual void on_timeout(int id) = 0;
+
+private:
+ pj_timer_entry entry_;
+
+ static void timer_heap_callback(pj_timer_heap_t *th, pj_timer_entry *e)
+ {
+ Pj_Timer_Entry *entry = (Pj_Timer_Entry*) e->user_data;
+ entry->on_timeout(e->id);
+ }
+
+};
+
+//////////////////////////////////////////////////////////////////////////////
+// Timer heap.
+//
+class Pj_Timer_Heap : public Pj_Object
+{
+public:
+ //
+ // Default constructor.
+ //
+ Pj_Timer_Heap()
+ : ht_(NULL)
+ {
+ }
+
+ //
+ // Construct timer heap.
+ //
+ Pj_Timer_Heap(Pj_Pool *pool, pj_size_t initial_count)
+ : ht_(NULL)
+ {
+ create(pool, initial_count);
+ }
+
+ //
+ // Destructor.
+ //
+ ~Pj_Timer_Heap()
+ {
+ destroy();
+ }
+
+ //
+ // Create
+ //
+ pj_status_t create(Pj_Pool *pool, pj_size_t initial_count)
+ {
+ destroy();
+ return pj_timer_heap_create(pool->pool_(), initial_count, &ht_);
+ }
+
+ //
+ // Destroy
+ //
+ void destroy()
+ {
+ if (ht_) {
+ pj_timer_heap_destroy(ht_);
+ ht_ = NULL;
+ }
+ }
+
+ //
+ // Get pjlib compatible timer heap object.
+ //
+ pj_timer_heap_t *get_timer_heap()
+ {
+ return ht_;
+ }
+
+ //
+ // Set the lock object.
+ //
+ void set_lock( Pj_Lock *lock, bool auto_delete )
+ {
+ pj_timer_heap_set_lock( ht_, lock->pj_lock_t_(), auto_delete);
+ }
+
+ //
+ // Set maximum number of timed out entries to be processed per poll.
+ //
+ unsigned set_max_timed_out_per_poll(unsigned count)
+ {
+ return pj_timer_heap_set_max_timed_out_per_poll(ht_, count);
+ }
+
+ //
+ // Schedule a timer.
+ //
+ bool schedule( Pj_Timer_Entry *ent, const Pj_Time_Val &delay,
+ int id)
+ {
+ ent->entry_.id = id;
+ return pj_timer_heap_schedule(ht_, &ent->entry_, &delay) == 0;
+ }
+
+ //
+ // Cancel a timer.
+ //
+ bool cancel(Pj_Timer_Entry *ent)
+ {
+ return pj_timer_heap_cancel(ht_, &ent->entry_) == 1;
+ }
+
+ //
+ // Get current number of timers
+ //
+ pj_size_t count()
+ {
+ return pj_timer_heap_count(ht_);
+ }
+
+ //
+ // Get the earliest time.
+ // Return false if no timer is found.
+ //
+ bool earliest_time(Pj_Time_Val *t)
+ {
+ return pj_timer_heap_earliest_time(ht_, t) == PJ_SUCCESS;
+ }
+
+ //
+ // Poll the timer.
+ // Return number of timed out entries has been called.
+ //
+ unsigned poll(Pj_Time_Val *next_delay = NULL)
+ {
+ return pj_timer_heap_poll(ht_, next_delay);
+ }
+
+private:
+ pj_timer_heap_t *ht_;
+};
+
+#endif /* __PJPP_TIMER_HPP__ */
+
diff --git a/pjlib/include/pj++/tree.hpp b/pjlib/include/pj++/tree.hpp index f4fe8fc1..d58d6a04 100644 --- a/pjlib/include/pj++/tree.hpp +++ b/pjlib/include/pj++/tree.hpp @@ -1,112 +1,133 @@ -/* $Id$ - */ -#ifndef __PJPP_TREE_HPP__ -#define __PJPP_TREE_HPP__ - -#include <pj/rbtree.h> - -// -// Tree. -// -class PJ_Tree -{ -public: - typedef pj_rbtree_comp Comp; - class iterator; - class reverse_iterator; - - class Node : private pj_rbtree_node - { - friend class PJ_Tree; - friend class iterator; - friend class reverse_iterator; - - public: - Node() {} - explicit Node(void *data) { user_data = data; } - void set_user_data(void *data) { user_data = data; } - void *get_user_data() const { return user_data; } - }; - - class iterator - { - public: - iterator() {} - iterator(const iterator &rhs) : tr_(rhs.tr_), nd_(rhs.nd_) {} - iterator(pj_rbtree *tr, pj_rbtree_node *nd) : tr_(tr), nd_(nd) {} - Node *operator*() { return (Node*)nd_; } - bool operator==(const iterator &rhs) const { return tr_==rhs.tr_ && nd_==rhs.nd_; } - iterator &operator=(const iterator &rhs) { tr_=rhs.tr_; nd_=rhs.nd_; return *this; } - void operator++() { nd_=pj_rbtree_next(tr_, nd_); } - void operator--() { nd_=pj_rbtree_prev(tr_, nd_); } - protected: - pj_rbtree *tr_; - pj_rbtree_node *nd_; - }; - - class reverse_iterator : public iterator - { - public: - reverse_iterator() {} - reverse_iterator(const reverse_iterator &it) : iterator(it) {} - reverse_iterator(pj_rbtree *t, pj_rbtree_node *n) : iterator(t, n) {} - reverse_iterator &operator=(const reverse_iterator &rhs) { iterator::operator=(rhs); return *this; } - Node *operator*() { return (Node*)nd_; } - bool operator==(const reverse_iterator &rhs) const { return iterator::operator==(rhs); } - void operator++() { nd_=pj_rbtree_prev(tr_, nd_); } - void operator--() { nd_=pj_rbtree_next(tr_, nd_); } - }; - - explicit PJ_Tree(Comp *comp) { pj_rbtree_init(&t_, comp); } - - iterator begin() - { - return iterator(&t_, pj_rbtree_first(&t_)); - } - - iterator end() - { - return iterator(&t_, NULL); - } - - reverse_iterator rbegin() - { - return reverse_iterator(&t_, pj_rbtree_last(&t_)); - } - - reverse_iterator rend() - { - return reverse_iterator(&t_, NULL); - } - - bool insert(Node *node) - { - return pj_rbtree_insert(&t_, node)==0 ? true : false; - } - - Node *find(const void *key) - { - return (Node*)pj_rbtree_find(&t_, key); - } - - Node *erase(Node *node) - { - return (Node*)pj_rbtree_erase(&t_, node); - } - - unsigned max_height(Node *node=NULL) - { - return pj_rbtree_max_height(&t_, node); - } - - unsigned min_height(Node *node=NULL) - { - return pj_rbtree_min_height(&t_, node); - } - -private: - pj_rbtree t_; -}; - -#endif /* __PJPP_TREE_HPP__ */ - +/* $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 __PJPP_TREE_HPP__
+#define __PJPP_TREE_HPP__
+
+#include <pj/rbtree.h>
+
+//
+// Tree.
+//
+class PJ_Tree
+{
+public:
+ typedef pj_rbtree_comp Comp;
+ class iterator;
+ class reverse_iterator;
+
+ class Node : private pj_rbtree_node
+ {
+ friend class PJ_Tree;
+ friend class iterator;
+ friend class reverse_iterator;
+
+ public:
+ Node() {}
+ explicit Node(void *data) { user_data = data; }
+ void set_user_data(void *data) { user_data = data; }
+ void *get_user_data() const { return user_data; }
+ };
+
+ class iterator
+ {
+ public:
+ iterator() {}
+ iterator(const iterator &rhs) : tr_(rhs.tr_), nd_(rhs.nd_) {}
+ iterator(pj_rbtree *tr, pj_rbtree_node *nd) : tr_(tr), nd_(nd) {}
+ Node *operator*() { return (Node*)nd_; }
+ bool operator==(const iterator &rhs) const { return tr_==rhs.tr_ && nd_==rhs.nd_; }
+ iterator &operator=(const iterator &rhs) { tr_=rhs.tr_; nd_=rhs.nd_; return *this; }
+ void operator++() { nd_=pj_rbtree_next(tr_, nd_); }
+ void operator--() { nd_=pj_rbtree_prev(tr_, nd_); }
+ protected:
+ pj_rbtree *tr_;
+ pj_rbtree_node *nd_;
+ };
+
+ class reverse_iterator : public iterator
+ {
+ public:
+ reverse_iterator() {}
+ reverse_iterator(const reverse_iterator &it) : iterator(it) {}
+ reverse_iterator(pj_rbtree *t, pj_rbtree_node *n) : iterator(t, n) {}
+ reverse_iterator &operator=(const reverse_iterator &rhs) { iterator::operator=(rhs); return *this; }
+ Node *operator*() { return (Node*)nd_; }
+ bool operator==(const reverse_iterator &rhs) const { return iterator::operator==(rhs); }
+ void operator++() { nd_=pj_rbtree_prev(tr_, nd_); }
+ void operator--() { nd_=pj_rbtree_next(tr_, nd_); }
+ };
+
+ explicit PJ_Tree(Comp *comp) { pj_rbtree_init(&t_, comp); }
+
+ iterator begin()
+ {
+ return iterator(&t_, pj_rbtree_first(&t_));
+ }
+
+ iterator end()
+ {
+ return iterator(&t_, NULL);
+ }
+
+ reverse_iterator rbegin()
+ {
+ return reverse_iterator(&t_, pj_rbtree_last(&t_));
+ }
+
+ reverse_iterator rend()
+ {
+ return reverse_iterator(&t_, NULL);
+ }
+
+ bool insert(Node *node)
+ {
+ return pj_rbtree_insert(&t_, node)==0 ? true : false;
+ }
+
+ Node *find(const void *key)
+ {
+ return (Node*)pj_rbtree_find(&t_, key);
+ }
+
+ Node *erase(Node *node)
+ {
+ return (Node*)pj_rbtree_erase(&t_, node);
+ }
+
+ unsigned max_height(Node *node=NULL)
+ {
+ return pj_rbtree_max_height(&t_, node);
+ }
+
+ unsigned min_height(Node *node=NULL)
+ {
+ return pj_rbtree_min_height(&t_, node);
+ }
+
+private:
+ pj_rbtree t_;
+};
+
+#endif /* __PJPP_TREE_HPP__ */
+
diff --git a/pjlib/include/pj++/types.hpp b/pjlib/include/pj++/types.hpp index 3155eb02..18a2f52b 100644 --- a/pjlib/include/pj++/types.hpp +++ b/pjlib/include/pj++/types.hpp @@ -1,144 +1,165 @@ -/* $Id$ - */ -#ifndef __PJPP_TYPES_HPP__ -#define __PJPP_TYPES_HPP__ - -#include <pj/types.h> - -class Pj_Pool; -class Pj_Socket ; -class Pj_Lock; - - -// -// PJLIB initializer. -// -class Pjlib -{ -public: - Pjlib() - { - pj_init(); - } -}; - -// -// Class Pj_Object is declared in pool.hpp -// - -// -// Time value wrapper. -// -class Pj_Time_Val : public pj_time_val -{ -public: - Pj_Time_Val() - { - } - - Pj_Time_Val(long init_sec, long init_msec) - { - sec = init_sec; - msec = init_msec; - } - - Pj_Time_Val(const Pj_Time_Val &rhs) - { - sec=rhs.sec; - msec=rhs.msec; - } - - explicit Pj_Time_Val(const pj_time_val &tv) - { - sec = tv.sec; - msec = tv.msec; - } - - long get_sec() const - { - return sec; - } - - long get_msec() const - { - return msec; - } - - void set_sec (long s) - { - sec = s; - } - - void set_msec(long ms) - { - msec = ms; - normalize(); - } - - long to_msec() const - { - return PJ_TIME_VAL_MSEC((*this)); - } - - bool operator == (const Pj_Time_Val &rhs) const - { - return PJ_TIME_VAL_EQ((*this), rhs); - } - - bool operator > (const Pj_Time_Val &rhs) const - { - return PJ_TIME_VAL_GT((*this), rhs); - } - - bool operator >= (const Pj_Time_Val &rhs) const - { - return PJ_TIME_VAL_GTE((*this), rhs); - } - - bool operator < (const Pj_Time_Val &rhs) const - { - return PJ_TIME_VAL_LT((*this), rhs); - } - - bool operator <= (const Pj_Time_Val &rhs) const - { - return PJ_TIME_VAL_LTE((*this), rhs); - } - - Pj_Time_Val & operator = (const Pj_Time_Val &rhs) - { - sec = rhs.sec; - msec = rhs.msec; - return *this; - } - - Pj_Time_Val & operator += (const Pj_Time_Val &rhs) - { - PJ_TIME_VAL_ADD((*this), rhs); - return *this; - } - - Pj_Time_Val & operator -= (const Pj_Time_Val &rhs) - { - PJ_TIME_VAL_SUB((*this), rhs); - return *this; - } - - /* Must include os.hpp to use these, otherwise unresolved in linking */ - inline pj_status_t gettimeofday(); - inline pj_parsed_time decode(); - inline pj_status_t encode(const pj_parsed_time *pt); - inline pj_status_t to_gmt(); - inline pj_status_t to_local(); - - -private: - void normalize() - { - pj_time_val_normalize(this); - } - -}; - -#endif /* __PJPP_TYPES_HPP__ */ - +/* $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 __PJPP_TYPES_HPP__
+#define __PJPP_TYPES_HPP__
+
+#include <pj/types.h>
+
+class Pj_Pool;
+class Pj_Socket ;
+class Pj_Lock;
+
+
+//
+// PJLIB initializer.
+//
+class Pjlib
+{
+public:
+ Pjlib()
+ {
+ pj_init();
+ }
+};
+
+//
+// Class Pj_Object is declared in pool.hpp
+//
+
+//
+// Time value wrapper.
+//
+class Pj_Time_Val : public pj_time_val
+{
+public:
+ Pj_Time_Val()
+ {
+ }
+
+ Pj_Time_Val(long init_sec, long init_msec)
+ {
+ sec = init_sec;
+ msec = init_msec;
+ }
+
+ Pj_Time_Val(const Pj_Time_Val &rhs)
+ {
+ sec=rhs.sec;
+ msec=rhs.msec;
+ }
+
+ explicit Pj_Time_Val(const pj_time_val &tv)
+ {
+ sec = tv.sec;
+ msec = tv.msec;
+ }
+
+ long get_sec() const
+ {
+ return sec;
+ }
+
+ long get_msec() const
+ {
+ return msec;
+ }
+
+ void set_sec (long s)
+ {
+ sec = s;
+ }
+
+ void set_msec(long ms)
+ {
+ msec = ms;
+ normalize();
+ }
+
+ long to_msec() const
+ {
+ return PJ_TIME_VAL_MSEC((*this));
+ }
+
+ bool operator == (const Pj_Time_Val &rhs) const
+ {
+ return PJ_TIME_VAL_EQ((*this), rhs);
+ }
+
+ bool operator > (const Pj_Time_Val &rhs) const
+ {
+ return PJ_TIME_VAL_GT((*this), rhs);
+ }
+
+ bool operator >= (const Pj_Time_Val &rhs) const
+ {
+ return PJ_TIME_VAL_GTE((*this), rhs);
+ }
+
+ bool operator < (const Pj_Time_Val &rhs) const
+ {
+ return PJ_TIME_VAL_LT((*this), rhs);
+ }
+
+ bool operator <= (const Pj_Time_Val &rhs) const
+ {
+ return PJ_TIME_VAL_LTE((*this), rhs);
+ }
+
+ Pj_Time_Val & operator = (const Pj_Time_Val &rhs)
+ {
+ sec = rhs.sec;
+ msec = rhs.msec;
+ return *this;
+ }
+
+ Pj_Time_Val & operator += (const Pj_Time_Val &rhs)
+ {
+ PJ_TIME_VAL_ADD((*this), rhs);
+ return *this;
+ }
+
+ Pj_Time_Val & operator -= (const Pj_Time_Val &rhs)
+ {
+ PJ_TIME_VAL_SUB((*this), rhs);
+ return *this;
+ }
+
+ /* Must include os.hpp to use these, otherwise unresolved in linking */
+ inline pj_status_t gettimeofday();
+ inline pj_parsed_time decode();
+ inline pj_status_t encode(const pj_parsed_time *pt);
+ inline pj_status_t to_gmt();
+ inline pj_status_t to_local();
+
+
+private:
+ void normalize()
+ {
+ pj_time_val_normalize(this);
+ }
+
+};
+
+#endif /* __PJPP_TYPES_HPP__ */
+
diff --git a/pjlib/include/pj/addr_resolv.h b/pjlib/include/pj/addr_resolv.h index 1da92082..3a5c1eb5 100644 --- a/pjlib/include/pj/addr_resolv.h +++ b/pjlib/include/pj/addr_resolv.h @@ -1,77 +1,98 @@ -/* $Id$ - */ - -#ifndef __PJ_ADDR_RESOLV_H__ -#define __PJ_ADDR_RESOLV_H__ - -/** - * @file addr_resolv.h - * @brief Address resolve (pj_gethostbyname()). - */ - -#include <pj/types.h> - -PJ_BEGIN_DECL - -/** - * @defgroup pj_addr_resolve Network Address Resolution - * @ingroup PJ_IO - * @{ - * - * This module provides function to resolve Internet address of the - * specified host name. To resolve a particular host name, application - * can just call #pj_gethostbyname(). - * - * Example: - * <pre> - * ... - * pj_hostent he; - * pj_status_t rc; - * pj_str_t host = pj_str("host.example.com"); - * - * rc = pj_gethostbyname( &host, &he); - * if (rc != PJ_SUCCESS) { - * char errbuf[80]; - * pj_strerror( rc, errbuf, sizeof(errbuf)); - * PJ_LOG(2,("sample", "Unable to resolve host, error=%s", errbuf)); - * return rc; - * } - * - * // process address... - * addr.sin_addr.s_addr = *(pj_uint32_t*)he.h_addr; - * ... - * </pre> - * - * It's pretty simple really... - */ - -/** This structure describes an Internet host address. */ -typedef struct pj_hostent -{ - char *h_name; /**< The official name of the host. */ - char **h_aliases; /**< Aliases list. */ - int h_addrtype; /**< Host address type. */ - int h_length; /**< Length of address. */ - char **h_addr_list; /**< List of addresses. */ -} pj_hostent; - -/** Shortcut to h_addr_list[0] */ -#define h_addr h_addr_list[0] - -/** - * This function fills the structure of type pj_hostent for a given host name. - * - * @param name Host name, or IPv4 or IPv6 address in standard dot notation. - * @param he The pj_hostent structure to be filled. - * - * @return PJ_SUCCESS, or the appropriate error codes. - */ -PJ_DECL(pj_status_t) pj_gethostbyname(const pj_str_t *name, pj_hostent *he); - - -/** @} */ - -PJ_END_DECL - -#endif /* __PJ_ADDR_RESOLV_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 __PJ_ADDR_RESOLV_H__
+#define __PJ_ADDR_RESOLV_H__
+
+/**
+ * @file addr_resolv.h
+ * @brief Address resolve (pj_gethostbyname()).
+ */
+
+#include <pj/types.h>
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup pj_addr_resolve Network Address Resolution
+ * @ingroup PJ_IO
+ * @{
+ *
+ * This module provides function to resolve Internet address of the
+ * specified host name. To resolve a particular host name, application
+ * can just call #pj_gethostbyname().
+ *
+ * Example:
+ * <pre>
+ * ...
+ * pj_hostent he;
+ * pj_status_t rc;
+ * pj_str_t host = pj_str("host.example.com");
+ *
+ * rc = pj_gethostbyname( &host, &he);
+ * if (rc != PJ_SUCCESS) {
+ * char errbuf[80];
+ * pj_strerror( rc, errbuf, sizeof(errbuf));
+ * PJ_LOG(2,("sample", "Unable to resolve host, error=%s", errbuf));
+ * return rc;
+ * }
+ *
+ * // process address...
+ * addr.sin_addr.s_addr = *(pj_uint32_t*)he.h_addr;
+ * ...
+ * </pre>
+ *
+ * It's pretty simple really...
+ */
+
+/** This structure describes an Internet host address. */
+typedef struct pj_hostent
+{
+ char *h_name; /**< The official name of the host. */
+ char **h_aliases; /**< Aliases list. */
+ int h_addrtype; /**< Host address type. */
+ int h_length; /**< Length of address. */
+ char **h_addr_list; /**< List of addresses. */
+} pj_hostent;
+
+/** Shortcut to h_addr_list[0] */
+#define h_addr h_addr_list[0]
+
+/**
+ * This function fills the structure of type pj_hostent for a given host name.
+ *
+ * @param name Host name, or IPv4 or IPv6 address in standard dot notation.
+ * @param he The pj_hostent structure to be filled.
+ *
+ * @return PJ_SUCCESS, or the appropriate error codes.
+ */
+PJ_DECL(pj_status_t) pj_gethostbyname(const pj_str_t *name, pj_hostent *he);
+
+
+/** @} */
+
+PJ_END_DECL
+
+#endif /* __PJ_ADDR_RESOLV_H__ */
+
diff --git a/pjlib/include/pj/array.h b/pjlib/include/pj/array.h index eaec726e..dc896c2b 100644 --- a/pjlib/include/pj/array.h +++ b/pjlib/include/pj/array.h @@ -1,80 +1,101 @@ -/* $Id$ - * - */ -#ifndef __PJ_ARRAY_H__ -#define __PJ_ARRAY_H__ - -/** - * @file array.h - * @brief PJLIB Array helper. - */ -#include <pj/types.h> - -PJ_BEGIN_DECL - -/** - * @defgroup PJ_ARRAY Array helper. - * @ingroup PJ_DS - * @{ - * - * This module provides helper to manipulate array of elements of any size. - * It provides most used array operations such as insert, erase, and search. - */ - -/** - * Insert value to the array at the given position, and rearrange the - * remaining nodes after the position. - * - * @param array the array. - * @param elem_size the size of the individual element. - * @param count the current number of elements in the array. - * @param pos the position where the new element is put. - * @param value the value to copy to the new element. - */ -PJ_DECL(void) pj_array_insert( void *array, - unsigned elem_size, - unsigned count, - unsigned pos, - const void *value); - -/** - * Erase a value from the array at given position, and rearrange the remaining - * elements post the erased element. - * - * @param array the array. - * @param elem_size the size of the individual element. - * @param count the current number of elements in the array. - * @param pos the index/position to delete. - */ -PJ_DECL(void) pj_array_erase( void *array, - unsigned elem_size, - unsigned count, - unsigned pos); - -/** - * Search the first value in the array according to matching function. - * - * @param array the array. - * @param elem_size the individual size of the element. - * @param count the number of elements. - * @param matching the matching function, which MUST return PJ_SUCCESS if - * the specified element match. - * @param result the pointer to the value found. - * - * @return PJ_SUCCESS if value is found, otherwise the error code. - */ -PJ_DECL(pj_status_t) pj_array_find( const void *array, - unsigned elem_size, - unsigned count, - pj_status_t (*matching)(const void *value), - void **result); - -/** - * @} - */ - -PJ_END_DECL - - -#endif /* __PJ_ARRAY_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 __PJ_ARRAY_H__
+#define __PJ_ARRAY_H__
+
+/**
+ * @file array.h
+ * @brief PJLIB Array helper.
+ */
+#include <pj/types.h>
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup PJ_ARRAY Array helper.
+ * @ingroup PJ_DS
+ * @{
+ *
+ * This module provides helper to manipulate array of elements of any size.
+ * It provides most used array operations such as insert, erase, and search.
+ */
+
+/**
+ * Insert value to the array at the given position, and rearrange the
+ * remaining nodes after the position.
+ *
+ * @param array the array.
+ * @param elem_size the size of the individual element.
+ * @param count the current number of elements in the array.
+ * @param pos the position where the new element is put.
+ * @param value the value to copy to the new element.
+ */
+PJ_DECL(void) pj_array_insert( void *array,
+ unsigned elem_size,
+ unsigned count,
+ unsigned pos,
+ const void *value);
+
+/**
+ * Erase a value from the array at given position, and rearrange the remaining
+ * elements post the erased element.
+ *
+ * @param array the array.
+ * @param elem_size the size of the individual element.
+ * @param count the current number of elements in the array.
+ * @param pos the index/position to delete.
+ */
+PJ_DECL(void) pj_array_erase( void *array,
+ unsigned elem_size,
+ unsigned count,
+ unsigned pos);
+
+/**
+ * Search the first value in the array according to matching function.
+ *
+ * @param array the array.
+ * @param elem_size the individual size of the element.
+ * @param count the number of elements.
+ * @param matching the matching function, which MUST return PJ_SUCCESS if
+ * the specified element match.
+ * @param result the pointer to the value found.
+ *
+ * @return PJ_SUCCESS if value is found, otherwise the error code.
+ */
+PJ_DECL(pj_status_t) pj_array_find( const void *array,
+ unsigned elem_size,
+ unsigned count,
+ pj_status_t (*matching)(const void *value),
+ void **result);
+
+/**
+ * @}
+ */
+
+PJ_END_DECL
+
+
+#endif /* __PJ_ARRAY_H__ */
+
diff --git a/pjlib/include/pj/assert.h b/pjlib/include/pj/assert.h index d10c864a..c6d37707 100644 --- a/pjlib/include/pj/assert.h +++ b/pjlib/include/pj/assert.h @@ -1,58 +1,79 @@ -/* $Id$ - * - */ -#ifndef __PJ_ASSERT_H__ -#define __PJ_ASSERT_H__ - -/** - * @file assert.h - * @brief Assertion macro pj_assert(). - */ - -#include <pj/config.h> -#include <pj/compat/assert.h> - -/** - * @defgroup pj_assert Assertion Macro - * @ingroup PJ_MISC - * @{ - * - * Assertion and other helper macros for sanity checking. - */ - -/** - * @hideinitializer - * Check during debug build that an expression is true. If the expression - * computes to false during run-time, then the program will stop at the - * offending statements. - * For release build, this macro will not do anything. - * - * @param expr The expression to be evaluated. - */ -#define pj_assert(expr) assert(expr) - - -/** - * @hideinitializer - * If #PJ_ENABLE_EXTRA_CHECK is declared and non-zero, then - * #PJ_ASSERT_RETURN macro will evaluate the expression in @a expr during - * run-time. If the expression yields false, assertion will be triggered - * and the current function will return with the specified return value. - * - * If #PJ_ENABLE_EXTRA_CHECK is not declared or is zero, then no run-time - * checking will be performed. The macro simply evaluates to pj_assert(expr). - */ -#if defined(PJ_ENABLE_EXTRA_CHECK) && PJ_ENABLE_EXTRA_CHECK != 0 -# define PJ_ASSERT_RETURN(expr,retval) \ - do { \ - pj_assert(expr); \ - if (!(expr)) return retval; \ - } while (0) -#else -# define PJ_ASSERT_RETURN(expr,retval) pj_assert(expr) -#endif - -/** @} */ - -#endif /* __PJ_ASSERT_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 __PJ_ASSERT_H__
+#define __PJ_ASSERT_H__
+
+/**
+ * @file assert.h
+ * @brief Assertion macro pj_assert().
+ */
+
+#include <pj/config.h>
+#include <pj/compat/assert.h>
+
+/**
+ * @defgroup pj_assert Assertion Macro
+ * @ingroup PJ_MISC
+ * @{
+ *
+ * Assertion and other helper macros for sanity checking.
+ */
+
+/**
+ * @hideinitializer
+ * Check during debug build that an expression is true. If the expression
+ * computes to false during run-time, then the program will stop at the
+ * offending statements.
+ * For release build, this macro will not do anything.
+ *
+ * @param expr The expression to be evaluated.
+ */
+#define pj_assert(expr) assert(expr)
+
+
+/**
+ * @hideinitializer
+ * If #PJ_ENABLE_EXTRA_CHECK is declared and non-zero, then
+ * #PJ_ASSERT_RETURN macro will evaluate the expression in @a expr during
+ * run-time. If the expression yields false, assertion will be triggered
+ * and the current function will return with the specified return value.
+ *
+ * If #PJ_ENABLE_EXTRA_CHECK is not declared or is zero, then no run-time
+ * checking will be performed. The macro simply evaluates to pj_assert(expr).
+ */
+#if defined(PJ_ENABLE_EXTRA_CHECK) && PJ_ENABLE_EXTRA_CHECK != 0
+# define PJ_ASSERT_RETURN(expr,retval) \
+ do { \
+ pj_assert(expr); \
+ if (!(expr)) return retval; \
+ } while (0)
+#else
+# define PJ_ASSERT_RETURN(expr,retval) pj_assert(expr)
+#endif
+
+/** @} */
+
+#endif /* __PJ_ASSERT_H__ */
+
diff --git a/pjlib/include/pj/compat/assert.h b/pjlib/include/pj/compat/assert.h index 586cafb5..2cc1794f 100644 --- a/pjlib/include/pj/compat/assert.h +++ b/pjlib/include/pj/compat/assert.h @@ -1,40 +1,61 @@ -/* $Id$ - * - */ -/* $Log: /pjproject-0.3/pjlib/src/pj/compat/assert.h $ - * - * 3 9/22/05 10:31a Bennylp - * Moving all *.h files to include/. - * - * 2 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 1 9/17/05 10:36a Bennylp - * Created. - * - */ -#ifndef __PJ_COMPAT_ASSERT_H__ -#define __PJ_COMPAT_ASSERT_H__ - -/** - * @file assert.h - * @brief Provides assert() macro. - */ - -#if defined(PJ_HAS_ASSERT_H) && PJ_HAS_ASSERT_H != 0 -# include <assert.h> - -#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0 -# define assert(expr) do { \ - if (!(expr)) \ - printk("!!ASSERTION FAILED: [%s:%d] \"" #expr "\"\n",\ - __FILE__, __LINE__); \ - } while (0) - -#else -# warning "assert() is not implemented" -# define assert(expr) -#endif - -#endif /* __PJ_COMPAT_ASSERT_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
+ */
+/* $Log: /pjproject-0.3/pjlib/src/pj/compat/assert.h $
+ *
+ * 3 9/22/05 10:31a Bennylp
+ * Moving all *.h files to include/.
+ *
+ * 2 9/21/05 1:39p Bennylp
+ * Periodic checkin for backup.
+ *
+ * 1 9/17/05 10:36a Bennylp
+ * Created.
+ *
+ */
+#ifndef __PJ_COMPAT_ASSERT_H__
+#define __PJ_COMPAT_ASSERT_H__
+
+/**
+ * @file assert.h
+ * @brief Provides assert() macro.
+ */
+
+#if defined(PJ_HAS_ASSERT_H) && PJ_HAS_ASSERT_H != 0
+# include <assert.h>
+
+#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0
+# define assert(expr) do { \
+ if (!(expr)) \
+ printk("!!ASSERTION FAILED: [%s:%d] \"" #expr "\"\n",\
+ __FILE__, __LINE__); \
+ } while (0)
+
+#else
+# warning "assert() is not implemented"
+# define assert(expr)
+#endif
+
+#endif /* __PJ_COMPAT_ASSERT_H__ */
+
diff --git a/pjlib/include/pj/compat/cc_gcc.h b/pjlib/include/pj/compat/cc_gcc.h index 913f691e..96e9157c 100644 --- a/pjlib/include/pj/compat/cc_gcc.h +++ b/pjlib/include/pj/compat/cc_gcc.h @@ -1,34 +1,55 @@ -/* $Id$ - * - */ -/* $Log: /pjproject-0.3/pjlib/src/pj/compat/cc_gcc.h $ - * - * 2 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#ifndef __PJ_COMPAT_CC_GCC_H__ -#define __PJ_COMPAT_CC_GCC_H__ - -/** - * @file cc_gcc.h - * @brief Describes GCC compiler specifics. - */ - -#ifndef __GNUC__ -# error "This file is only for gcc!" -#endif - -#define PJ_INLINE_SPECIFIER static inline -#define PJ_THREAD_FUNC -#define PJ_NORETURN -#define PJ_ATTR_NORETURN __attribute__ ((noreturn)) - -#define PJ_HAS_INT64 1 - -typedef long long pj_int64_t; -typedef unsigned long long pj_uint64_t; - - -#endif /* __PJ_COMPAT_CC_GCC_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
+ */
+/* $Log: /pjproject-0.3/pjlib/src/pj/compat/cc_gcc.h $
+ *
+ * 2 9/17/05 10:37a Bennylp
+ * Major reorganization towards version 0.3.
+ *
+ */
+#ifndef __PJ_COMPAT_CC_GCC_H__
+#define __PJ_COMPAT_CC_GCC_H__
+
+/**
+ * @file cc_gcc.h
+ * @brief Describes GCC compiler specifics.
+ */
+
+#ifndef __GNUC__
+# error "This file is only for gcc!"
+#endif
+
+#define PJ_INLINE_SPECIFIER static inline
+#define PJ_THREAD_FUNC
+#define PJ_NORETURN
+#define PJ_ATTR_NORETURN __attribute__ ((noreturn))
+
+#define PJ_HAS_INT64 1
+
+typedef long long pj_int64_t;
+typedef unsigned long long pj_uint64_t;
+
+
+#endif /* __PJ_COMPAT_CC_GCC_H__ */
+
diff --git a/pjlib/include/pj/compat/cc_msvc.h b/pjlib/include/pj/compat/cc_msvc.h index f8407e3c..d67210b6 100644 --- a/pjlib/include/pj/compat/cc_msvc.h +++ b/pjlib/include/pj/compat/cc_msvc.h @@ -1,42 +1,63 @@ -/* $Id$ - * - */ -/* $Log: /pjproject-0.3/pjlib/include/pj/compat/cc_msvc.h $ - * - * 3 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 2 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#ifndef __PJ_COMPAT_CC_MSVC_H__ -#define __PJ_COMPAT_CC_MSVC_H__ - -/** - * @file cc_msvc.h - * @brief Describes Microsoft Visual C compiler specifics. - */ - -#ifndef _MSC_VER -# error "This header file is only for Visual C compiler!" -#endif - -# pragma warning(disable: 4127) // conditional expression is constant -# pragma warning(disable: 4611) // not wise to mix setjmp with C++ -# pragma warning(disable: 4514) // unreferenced inline function has been removed -# ifdef __cplusplus -# define PJ_INLINE_SPECIFIER inline -# else -# define PJ_INLINE_SPECIFIER static __inline -# endif -# define PJ_THREAD_FUNC -# define PJ_NORETURN __declspec(noreturn) -# define PJ_ATTR_NORETURN - -# define PJ_HAS_INT64 1 -typedef __int64 pj_int64_t; -typedef unsigned __int64 pj_uint64_t; - -#endif /* __PJ_COMPAT_CC_MSVC_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
+ */
+/* $Log: /pjproject-0.3/pjlib/include/pj/compat/cc_msvc.h $
+ *
+ * 3 10/14/05 12:26a Bennylp
+ * Finished error code framework, some fixes in ioqueue, etc. Pretty
+ * major.
+ *
+ * 2 9/17/05 10:37a Bennylp
+ * Major reorganization towards version 0.3.
+ *
+ */
+#ifndef __PJ_COMPAT_CC_MSVC_H__
+#define __PJ_COMPAT_CC_MSVC_H__
+
+/**
+ * @file cc_msvc.h
+ * @brief Describes Microsoft Visual C compiler specifics.
+ */
+
+#ifndef _MSC_VER
+# error "This header file is only for Visual C compiler!"
+#endif
+
+# pragma warning(disable: 4127) // conditional expression is constant
+# pragma warning(disable: 4611) // not wise to mix setjmp with C++
+# pragma warning(disable: 4514) // unreferenced inline function has been removed
+# ifdef __cplusplus
+# define PJ_INLINE_SPECIFIER inline
+# else
+# define PJ_INLINE_SPECIFIER static __inline
+# endif
+# define PJ_THREAD_FUNC
+# define PJ_NORETURN __declspec(noreturn)
+# define PJ_ATTR_NORETURN
+
+# define PJ_HAS_INT64 1
+typedef __int64 pj_int64_t;
+typedef unsigned __int64 pj_uint64_t;
+
+#endif /* __PJ_COMPAT_CC_MSVC_H__ */
diff --git a/pjlib/include/pj/compat/ctype.h b/pjlib/include/pj/compat/ctype.h index d01cc195..d8ddac15 100644 --- a/pjlib/include/pj/compat/ctype.h +++ b/pjlib/include/pj/compat/ctype.h @@ -1,44 +1,65 @@ -/* $Id$ - * - */ -/* $Log: /pjproject-0.3/pjlib/include/pj/compat/ctype.h $ - * - * 3 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 2 9/22/05 10:31a Bennylp - * Moving all *.h files to include/. - * - * 1 9/17/05 10:36a Bennylp - * Created. - * - */ -#ifndef __PJ_COMPAT_CTYPE_H__ -#define __PJ_COMPAT_CTYPE_H__ - -/** - * @file ctype.h - * @brief Provides ctype function family. - */ - -#if defined(PJ_HAS_CTYPE_H) && PJ_HAS_CTYPE_H != 0 -# include <ctype.h> -#else -# define isalnum(c) (isalpha(c) || isdigit(c)) -# define isalpha(c) (islower(c) || isupper(c)) -# define isascii(c) (((unsigned char)(c))<=0x7f) -# define isdigit(c) ((c)>='0' && (c)<='9') -# define isspace(c) ((c)==' ' || (c)=='\t' ||\ - (c)=='\n' || (c)=='\r' || (c)=='\v') -# define islower(c) ((c)>='a' && (c)<='z') -# define isupper(c) ((c)>='A' && (c)<='Z') -# define isxdigit(c) (isdigit(c) || (tolower(c)>='a'&&tolower(c)<='f')) -# define tolower(c) (((c) >= 'A' && (c) <= 'Z') ? (c)+('a'-'A') : (c)) -# define toupper(c) (((c) >= 'a' && (c) <= 'z') ? (c)-('a'-'A') : (c)) -#endif - -#define isblank(c) (c==' ' || c=='\t') - - -#endif /* __PJ_COMPAT_CTYPE_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
+ */
+/* $Log: /pjproject-0.3/pjlib/include/pj/compat/ctype.h $
+ *
+ * 3 10/14/05 12:26a Bennylp
+ * Finished error code framework, some fixes in ioqueue, etc. Pretty
+ * major.
+ *
+ * 2 9/22/05 10:31a Bennylp
+ * Moving all *.h files to include/.
+ *
+ * 1 9/17/05 10:36a Bennylp
+ * Created.
+ *
+ */
+#ifndef __PJ_COMPAT_CTYPE_H__
+#define __PJ_COMPAT_CTYPE_H__
+
+/**
+ * @file ctype.h
+ * @brief Provides ctype function family.
+ */
+
+#if defined(PJ_HAS_CTYPE_H) && PJ_HAS_CTYPE_H != 0
+# include <ctype.h>
+#else
+# define isalnum(c) (isalpha(c) || isdigit(c))
+# define isalpha(c) (islower(c) || isupper(c))
+# define isascii(c) (((unsigned char)(c))<=0x7f)
+# define isdigit(c) ((c)>='0' && (c)<='9')
+# define isspace(c) ((c)==' ' || (c)=='\t' ||\
+ (c)=='\n' || (c)=='\r' || (c)=='\v')
+# define islower(c) ((c)>='a' && (c)<='z')
+# define isupper(c) ((c)>='A' && (c)<='Z')
+# define isxdigit(c) (isdigit(c) || (tolower(c)>='a'&&tolower(c)<='f'))
+# define tolower(c) (((c) >= 'A' && (c) <= 'Z') ? (c)+('a'-'A') : (c))
+# define toupper(c) (((c) >= 'a' && (c) <= 'z') ? (c)-('a'-'A') : (c))
+#endif
+
+#define isblank(c) (c==' ' || c=='\t')
+
+
+#endif /* __PJ_COMPAT_CTYPE_H__ */
diff --git a/pjlib/include/pj/compat/errno.h b/pjlib/include/pj/compat/errno.h index 7ee8324a..be7a753d 100644 --- a/pjlib/include/pj/compat/errno.h +++ b/pjlib/include/pj/compat/errno.h @@ -1,29 +1,50 @@ -/* $Id$ - * - */ -#ifndef __PJ_COMPAT_ERRNO_H__ -#define __PJ_COMPAT_ERRNO_H__ - -#if defined(PJ_WIN32) && PJ_WIN32 != 0 - - typedef unsigned long pj_os_err_type; -# define pj_get_native_os_error() GetLastError() -# define pj_get_native_netos_error() WSAGetLastError() - -#elif (defined(PJ_LINUX) && PJ_LINUX != 0) || \ - (defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0) || \ - (defined(PJ_SUNOS) && PJ_SUNOS != 0) - - typedef int pj_os_err_type; -# define pj_get_native_os_error() (errno) -# define pj_get_native_netos_error() (errno) - -#else - -# error "Please define pj_os_err_type for this platform here!" - -#endif - - -#endif /* __PJ_COMPAT_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
+ */
+#ifndef __PJ_COMPAT_ERRNO_H__
+#define __PJ_COMPAT_ERRNO_H__
+
+#if defined(PJ_WIN32) && PJ_WIN32 != 0
+
+ typedef unsigned long pj_os_err_type;
+# define pj_get_native_os_error() GetLastError()
+# define pj_get_native_netos_error() WSAGetLastError()
+
+#elif (defined(PJ_LINUX) && PJ_LINUX != 0) || \
+ (defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0) || \
+ (defined(PJ_SUNOS) && PJ_SUNOS != 0)
+
+ typedef int pj_os_err_type;
+# define pj_get_native_os_error() (errno)
+# define pj_get_native_netos_error() (errno)
+
+#else
+
+# error "Please define pj_os_err_type for this platform here!"
+
+#endif
+
+
+#endif /* __PJ_COMPAT_ERRNO_H__ */
+
diff --git a/pjlib/include/pj/compat/high_precision.h b/pjlib/include/pj/compat/high_precision.h index 431283df..ba48e43e 100644 --- a/pjlib/include/pj/compat/high_precision.h +++ b/pjlib/include/pj/compat/high_precision.h @@ -1,87 +1,106 @@ -/* $Id$ - * - */ -#ifndef __PJ_COMPAT_HIGH_PRECISION_H__ -#define __PJ_COMPAT_HIGH_PRECISION_H__ - - -#if defined(PJ_HAS_FLOATING_POINT) && PJ_HAS_FLOATING_POINT != 0 - /* - * The first choice for high precision math is to use double. - */ -# include <math.h> - typedef double pj_highprec_t; - -# define PJ_HIGHPREC_VALUE_IS_ZERO(a) (a==0) -# define pj_highprec_mod(a,b) (a=fmod(a,b)) - -#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0 - -# include <asm/div64.h> - - typedef pj_int64_t pj_highprec_t; - -# define pj_highprec_div(a1,a2) do_div(a1,a2) -# define pj_highprec_mod(a1,a2) (a1=do_mod(a1, a2)) - - PJ_INLINE(pj_int64_t) do_mod( pj_int64_t a1, pj_int64_t a2) - { - return do_div(a1,a2); - } - - -#elif defined(PJ_HAS_INT64) && PJ_HAS_INT64 != 0 - /* - * Next choice is to use 64-bit arithmatics. - */ - typedef pj_int64_t pj_highprec_t; - -#else -# warning "High precision math is not available" - - /* - * Last, fallback to 32-bit arithmetics. - */ - typedef pj_int32_t pj_highprec_t; - -#endif - -/** - * @def pj_highprec_mul - * pj_highprec_mul(a1, a2) - High Precision Multiplication - * Multiply a1 and a2, and store the result in a1. - */ -#ifndef pj_highprec_mul -# define pj_highprec_mul(a1,a2) (a1 = a1 * a2) -#endif - -/** - * @def pj_highprec_div - * pj_highprec_div(a1, a2) - High Precision Division - * Divide a2 from a1, and store the result in a1. - */ -#ifndef pj_highprec_div -# define pj_highprec_div(a1,a2) (a1 = a1 / a2) -#endif - -/** - * @def pj_highprec_mod - * pj_highprec_mod(a1, a2) - High Precision Modulus - * Get the modulus a2 from a1, and store the result in a1. - */ -#ifndef pj_highprec_mod -# define pj_highprec_mod(a1,a2) (a1 = a1 % a2) -#endif - - -/** - * @def PJ_HIGHPREC_VALUE_IS_ZERO(a) - * Test if the specified high precision value is zero. - */ -#ifndef PJ_HIGHPREC_VALUE_IS_ZERO -# define PJ_HIGHPREC_VALUE_IS_ZERO(a) (a==0) -#endif - - -#endif /* __PJ_COMPAT_HIGH_PRECISION_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 __PJ_COMPAT_HIGH_PRECISION_H__
+#define __PJ_COMPAT_HIGH_PRECISION_H__
+
+
+#if defined(PJ_HAS_FLOATING_POINT) && PJ_HAS_FLOATING_POINT != 0
+ /*
+ * The first choice for high precision math is to use double.
+ */
+# include <math.h>
+ typedef double pj_highprec_t;
+
+# define PJ_HIGHPREC_VALUE_IS_ZERO(a) (a==0)
+# define pj_highprec_mod(a,b) (a=fmod(a,b))
+
+#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0
+
+# include <asm/div64.h>
+
+ typedef pj_int64_t pj_highprec_t;
+
+# define pj_highprec_div(a1,a2) do_div(a1,a2)
+# define pj_highprec_mod(a1,a2) (a1=do_mod(a1, a2))
+
+ PJ_INLINE(pj_int64_t) do_mod( pj_int64_t a1, pj_int64_t a2)
+ {
+ return do_div(a1,a2);
+ }
+
+
+#elif defined(PJ_HAS_INT64) && PJ_HAS_INT64 != 0
+ /*
+ * Next choice is to use 64-bit arithmatics.
+ */
+ typedef pj_int64_t pj_highprec_t;
+
+#else
+# warning "High precision math is not available"
+
+ /*
+ * Last, fallback to 32-bit arithmetics.
+ */
+ typedef pj_int32_t pj_highprec_t;
+
+#endif
+
+/**
+ * @def pj_highprec_mul
+ * pj_highprec_mul(a1, a2) - High Precision Multiplication
+ * Multiply a1 and a2, and store the result in a1.
+ */
+#ifndef pj_highprec_mul
+# define pj_highprec_mul(a1,a2) (a1 = a1 * a2)
+#endif
+
+/**
+ * @def pj_highprec_div
+ * pj_highprec_div(a1, a2) - High Precision Division
+ * Divide a2 from a1, and store the result in a1.
+ */
+#ifndef pj_highprec_div
+# define pj_highprec_div(a1,a2) (a1 = a1 / a2)
+#endif
+
+/**
+ * @def pj_highprec_mod
+ * pj_highprec_mod(a1, a2) - High Precision Modulus
+ * Get the modulus a2 from a1, and store the result in a1.
+ */
+#ifndef pj_highprec_mod
+# define pj_highprec_mod(a1,a2) (a1 = a1 % a2)
+#endif
+
+
+/**
+ * @def PJ_HIGHPREC_VALUE_IS_ZERO(a)
+ * Test if the specified high precision value is zero.
+ */
+#ifndef PJ_HIGHPREC_VALUE_IS_ZERO
+# define PJ_HIGHPREC_VALUE_IS_ZERO(a) (a==0)
+#endif
+
+
+#endif /* __PJ_COMPAT_HIGH_PRECISION_H__ */
+
diff --git a/pjlib/include/pj/compat/m_alpha.h b/pjlib/include/pj/compat/m_alpha.h index 38569dca..3a1376e9 100644 --- a/pjlib/include/pj/compat/m_alpha.h +++ b/pjlib/include/pj/compat/m_alpha.h @@ -1,25 +1,46 @@ -/* $Id$ - * - */ -/* - * $Log: /pjproject-0.3/pjlib/include/pj/compat/m_alpha.h $ - * - * 1 10/29/05 5:23p Bennylp - * Created. - * - */ -#ifndef __PJ_COMPAT_M_ALPHA_H__ -#define __PJ_COMPAT_M_ALPHA_H__ - -/** - * @file m_alpha.h - * @brief Describes Alpha processor family specifics. - */ - -#define PJ_HAS_PENTIUM 0 -#define PJ_IS_LITTLE_ENDIAN 1 -#define PJ_IS_BIG_ENDIAN 0 - - -#endif /* __PJ_COMPAT_M_ALPHA_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
+ */
+/*
+ * $Log: /pjproject-0.3/pjlib/include/pj/compat/m_alpha.h $
+ *
+ * 1 10/29/05 5:23p Bennylp
+ * Created.
+ *
+ */
+#ifndef __PJ_COMPAT_M_ALPHA_H__
+#define __PJ_COMPAT_M_ALPHA_H__
+
+/**
+ * @file m_alpha.h
+ * @brief Describes Alpha processor family specifics.
+ */
+
+#define PJ_HAS_PENTIUM 0
+#define PJ_IS_LITTLE_ENDIAN 1
+#define PJ_IS_BIG_ENDIAN 0
+
+
+#endif /* __PJ_COMPAT_M_ALPHA_H__ */
+
diff --git a/pjlib/include/pj/compat/m_i386.h b/pjlib/include/pj/compat/m_i386.h index 8eaf19ed..0239c341 100644 --- a/pjlib/include/pj/compat/m_i386.h +++ b/pjlib/include/pj/compat/m_i386.h @@ -1,28 +1,49 @@ -/* $Id$ - * - */ -/* $Log: /pjproject-0.3/pjlib/src/pj/compat/m_i386.h $ - * - * 3 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 2 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#ifndef __PJ_COMPAT_M_i386_H__ -#define __PJ_COMPAT_M_i386_H__ - -/** - * @file m_i386.h - * @brief Describes Intel i386 family processor specifics. - */ - -#define PJ_M_I386 1 - -#define PJ_HAS_PENTIUM 1 -#define PJ_IS_LITTLE_ENDIAN 1 -#define PJ_IS_BIG_ENDIAN 0 - - -#endif /* __PJ_COMPAT_M_i386_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
+ */
+/* $Log: /pjproject-0.3/pjlib/src/pj/compat/m_i386.h $
+ *
+ * 3 9/21/05 1:39p Bennylp
+ * Periodic checkin for backup.
+ *
+ * 2 9/17/05 10:37a Bennylp
+ * Major reorganization towards version 0.3.
+ *
+ */
+#ifndef __PJ_COMPAT_M_i386_H__
+#define __PJ_COMPAT_M_i386_H__
+
+/**
+ * @file m_i386.h
+ * @brief Describes Intel i386 family processor specifics.
+ */
+
+#define PJ_M_I386 1
+
+#define PJ_HAS_PENTIUM 1
+#define PJ_IS_LITTLE_ENDIAN 1
+#define PJ_IS_BIG_ENDIAN 0
+
+
+#endif /* __PJ_COMPAT_M_i386_H__ */
diff --git a/pjlib/include/pj/compat/m_m68k.h b/pjlib/include/pj/compat/m_m68k.h index eb8db6ec..caed75e7 100644 --- a/pjlib/include/pj/compat/m_m68k.h +++ b/pjlib/include/pj/compat/m_m68k.h @@ -1,23 +1,44 @@ -/* $Id$ - * - */ -/* $Log: /pjproject-0.3/pjlib/src/pj/compat/m_m68k.h $ - * - * 2 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#ifndef __PJ_COMPAT_M_M68K_H__ -#define __PJ_COMPAT_M_M68K_H__ - -/** - * @file m_m68k.h - * @brief Describes Motorola m68k family processor specifics. - */ - -#define PJ_HAS_PENTIUM 0 -#define PJ_IS_LITTLE_ENDIAN 1 -#define PJ_IS_BIG_ENDIAN 0 - - -#endif /* __PJ_COMPAT_M_M68K_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
+ */
+/* $Log: /pjproject-0.3/pjlib/src/pj/compat/m_m68k.h $
+ *
+ * 2 9/17/05 10:37a Bennylp
+ * Major reorganization towards version 0.3.
+ *
+ */
+#ifndef __PJ_COMPAT_M_M68K_H__
+#define __PJ_COMPAT_M_M68K_H__
+
+/**
+ * @file m_m68k.h
+ * @brief Describes Motorola m68k family processor specifics.
+ */
+
+#define PJ_HAS_PENTIUM 0
+#define PJ_IS_LITTLE_ENDIAN 1
+#define PJ_IS_BIG_ENDIAN 0
+
+
+#endif /* __PJ_COMPAT_M_M68K_H__ */
diff --git a/pjlib/include/pj/compat/m_sparc.h b/pjlib/include/pj/compat/m_sparc.h index 5fd62400..3cb5d0cf 100644 --- a/pjlib/include/pj/compat/m_sparc.h +++ b/pjlib/include/pj/compat/m_sparc.h @@ -1,23 +1,44 @@ -/* $Id$ - * - */ -/* - *$Log: $ - * - */ -#ifndef __PJ_COMPAT_M_SPARC_H__ -#define __PJ_COMPAT_M_SPARC_H__ - -/** - * @file m_sparc.h - * @brief Describes SPARC family processor specifics. - */ - -#define PJ_SPARC 1 - -#define PJ_HAS_PENTIUM 0 -#define PJ_IS_LITTLE_ENDIAN 0 -#define PJ_IS_BIG_ENDIAN 1 - - -#endif /* __PJ_COMPAT_M_SPARC_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
+ */
+/*
+ *$Log: $
+ *
+ */
+#ifndef __PJ_COMPAT_M_SPARC_H__
+#define __PJ_COMPAT_M_SPARC_H__
+
+/**
+ * @file m_sparc.h
+ * @brief Describes SPARC family processor specifics.
+ */
+
+#define PJ_SPARC 1
+
+#define PJ_HAS_PENTIUM 0
+#define PJ_IS_LITTLE_ENDIAN 0
+#define PJ_IS_BIG_ENDIAN 1
+
+
+#endif /* __PJ_COMPAT_M_SPARC_H__ */
diff --git a/pjlib/include/pj/compat/malloc.h b/pjlib/include/pj/compat/malloc.h index 78ed9c90..4b5da782 100644 --- a/pjlib/include/pj/compat/malloc.h +++ b/pjlib/include/pj/compat/malloc.h @@ -1,27 +1,48 @@ -/* $Id$ - * - */ -/* $Log: /pjproject-0.3/pjlib/src/pj/compat/malloc.h $ - * - * 2 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - * 1 9/16/05 10:02p Bennylp - * Created. - * - */ -#ifndef __PJ_COMPAT_MALLOC_H__ -#define __PJ_COMPAT_MALLOC_H__ - -/** - * @file malloc.h - * @brief Provides malloc() and free() functions. - */ - -#if defined(PJ_HAS_MALLOC_H) && PJ_HAS_MALLOC_H != 0 -# include <malloc.h> -#elif defined(PJ_HAS_STDLIB_H) && PJ_HAS_STDLIB_H != 0 -# include <stdlib.h> -#endif - -#endif /* __PJ_COMPAT_MALLOC_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
+ */
+/* $Log: /pjproject-0.3/pjlib/src/pj/compat/malloc.h $
+ *
+ * 2 9/17/05 10:37a Bennylp
+ * Major reorganization towards version 0.3.
+ *
+ * 1 9/16/05 10:02p Bennylp
+ * Created.
+ *
+ */
+#ifndef __PJ_COMPAT_MALLOC_H__
+#define __PJ_COMPAT_MALLOC_H__
+
+/**
+ * @file malloc.h
+ * @brief Provides malloc() and free() functions.
+ */
+
+#if defined(PJ_HAS_MALLOC_H) && PJ_HAS_MALLOC_H != 0
+# include <malloc.h>
+#elif defined(PJ_HAS_STDLIB_H) && PJ_HAS_STDLIB_H != 0
+# include <stdlib.h>
+#endif
+
+#endif /* __PJ_COMPAT_MALLOC_H__ */
diff --git a/pjlib/include/pj/compat/os_linux.h b/pjlib/include/pj/compat/os_linux.h index efb661a4..8c4d74b5 100644 --- a/pjlib/include/pj/compat/os_linux.h +++ b/pjlib/include/pj/compat/os_linux.h @@ -1,86 +1,107 @@ -/* $Id$ - * - */ -/* $Log: /pjproject-0.3/pjlib/include/pj/compat/os_linux.h $ - * - * 6 10/29/05 11:51a Bennylp - * Version 0.3-pre2. - * - * 5 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 4 9/22/05 10:31a Bennylp - * Moving all *.h files to include/. - * - * 3 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 2 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#ifndef __PJ_COMPAT_OS_LINUX_H__ -#define __PJ_COMPAT_OS_LINUX_H__ - -/** - * @file os_linux.h - * @brief Describes Linux operating system specifics. - */ - -#define PJ_HAS_ARPA_INET_H 1 -#define PJ_HAS_ASSERT_H 1 -#define PJ_HAS_CTYPE_H 1 -#define PJ_HAS_ERRNO_H 1 -#define PJ_HAS_LINUX_SOCKET_H 0 -#define PJ_HAS_MALLOC_H 1 -#define PJ_HAS_NETDB_H 1 -#define PJ_HAS_NETINET_IN_H 1 -#define PJ_HAS_SETJMP_H 1 -#define PJ_HAS_STDARG_H 1 -#define PJ_HAS_STDDEF_H 1 -#define PJ_HAS_STDIO_H 1 -#define PJ_HAS_STDLIB_H 1 -#define PJ_HAS_STRING_H 1 -#define PJ_HAS_SYS_IOCTL_H 1 -#define PJ_HAS_SYS_SELECT_H 1 -#define PJ_HAS_SYS_SOCKET_H 1 -#define PJ_HAS_SYS_TIMEB_H 1 -#define PJ_HAS_SYS_TYPES_H 1 -#define PJ_HAS_TIME_H 1 -#define PJ_HAS_UNISTD_H 1 - -#define PJ_HAS_MSWSOCK_H 0 -#define PJ_HAS_WINSOCK_H 0 -#define PJ_HAS_WINSOCK2_H 0 - -#define PJ_SOCK_HAS_INET_ATON 1 - -/* When this macro is set, getsockopt(SOL_SOCKET, SO_ERROR) will return - * the status of non-blocking connect() operation. - */ -#define PJ_HAS_SO_ERROR 1 - -/* This value specifies the value set in errno by the OS when a non-blocking - * socket recv() can not return immediate daata. - */ -#define PJ_BLOCKING_ERROR_VAL EAGAIN - -/* This value specifies the value set in errno by the OS when a non-blocking - * socket connect() can not get connected immediately. - */ -#define PJ_BLOCKING_CONNECT_ERROR_VAL EINPROGRESS - -/* Default threading is enabled, unless it's overridden. */ -#ifndef PJ_HAS_THREADS -# define PJ_HAS_THREADS (1) -#endif - -#define PJ_HAS_HIGH_RES_TIMER 1 -#define PJ_HAS_MALLOC 1 -#define PJ_OS_HAS_CHECK_STACK 0 - -#define PJ_ATOMIC_VALUE_TYPE long - -#endif /* __PJ_COMPAT_OS_LINUX_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
+ */
+/* $Log: /pjproject-0.3/pjlib/include/pj/compat/os_linux.h $
+ *
+ * 6 10/29/05 11:51a Bennylp
+ * Version 0.3-pre2.
+ *
+ * 5 10/14/05 12:26a Bennylp
+ * Finished error code framework, some fixes in ioqueue, etc. Pretty
+ * major.
+ *
+ * 4 9/22/05 10:31a Bennylp
+ * Moving all *.h files to include/.
+ *
+ * 3 9/21/05 1:39p Bennylp
+ * Periodic checkin for backup.
+ *
+ * 2 9/17/05 10:37a Bennylp
+ * Major reorganization towards version 0.3.
+ *
+ */
+#ifndef __PJ_COMPAT_OS_LINUX_H__
+#define __PJ_COMPAT_OS_LINUX_H__
+
+/**
+ * @file os_linux.h
+ * @brief Describes Linux operating system specifics.
+ */
+
+#define PJ_HAS_ARPA_INET_H 1
+#define PJ_HAS_ASSERT_H 1
+#define PJ_HAS_CTYPE_H 1
+#define PJ_HAS_ERRNO_H 1
+#define PJ_HAS_LINUX_SOCKET_H 0
+#define PJ_HAS_MALLOC_H 1
+#define PJ_HAS_NETDB_H 1
+#define PJ_HAS_NETINET_IN_H 1
+#define PJ_HAS_SETJMP_H 1
+#define PJ_HAS_STDARG_H 1
+#define PJ_HAS_STDDEF_H 1
+#define PJ_HAS_STDIO_H 1
+#define PJ_HAS_STDLIB_H 1
+#define PJ_HAS_STRING_H 1
+#define PJ_HAS_SYS_IOCTL_H 1
+#define PJ_HAS_SYS_SELECT_H 1
+#define PJ_HAS_SYS_SOCKET_H 1
+#define PJ_HAS_SYS_TIMEB_H 1
+#define PJ_HAS_SYS_TYPES_H 1
+#define PJ_HAS_TIME_H 1
+#define PJ_HAS_UNISTD_H 1
+
+#define PJ_HAS_MSWSOCK_H 0
+#define PJ_HAS_WINSOCK_H 0
+#define PJ_HAS_WINSOCK2_H 0
+
+#define PJ_SOCK_HAS_INET_ATON 1
+
+/* When this macro is set, getsockopt(SOL_SOCKET, SO_ERROR) will return
+ * the status of non-blocking connect() operation.
+ */
+#define PJ_HAS_SO_ERROR 1
+
+/* This value specifies the value set in errno by the OS when a non-blocking
+ * socket recv() can not return immediate daata.
+ */
+#define PJ_BLOCKING_ERROR_VAL EAGAIN
+
+/* This value specifies the value set in errno by the OS when a non-blocking
+ * socket connect() can not get connected immediately.
+ */
+#define PJ_BLOCKING_CONNECT_ERROR_VAL EINPROGRESS
+
+/* Default threading is enabled, unless it's overridden. */
+#ifndef PJ_HAS_THREADS
+# define PJ_HAS_THREADS (1)
+#endif
+
+#define PJ_HAS_HIGH_RES_TIMER 1
+#define PJ_HAS_MALLOC 1
+#define PJ_OS_HAS_CHECK_STACK 0
+
+#define PJ_ATOMIC_VALUE_TYPE long
+
+#endif /* __PJ_COMPAT_OS_LINUX_H__ */
+
diff --git a/pjlib/include/pj/compat/os_linux_kernel.h b/pjlib/include/pj/compat/os_linux_kernel.h index ccae3418..5f784560 100644 --- a/pjlib/include/pj/compat/os_linux_kernel.h +++ b/pjlib/include/pj/compat/os_linux_kernel.h @@ -1,103 +1,124 @@ -/* $Id$ - * - */ -/* $Log: /pjproject-0.3/pjlib/include/pj/compat/os_linux_kernel.h $ - * - * 4 10/29/05 11:51a Bennylp - * Version 0.3-pre2. - * - * 3 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 2 9/22/05 10:31a Bennylp - * Moving all *.h files to include/. - * - * 1 9/21/05 1:38p Bennylp - * Created. - * - */ -#ifndef __PJ_COMPAT_OS_LINUX_KERNEL_H__ -#define __PJ_COMPAT_OS_LINUX_KERNEL_H__ - -/** - * @file os_linux.h - * @brief Describes Linux operating system specifics. - */ - -#define PJ_HAS_ARPA_INET_H 0 -#define PJ_HAS_ASSERT_H 0 -#define PJ_HAS_CTYPE_H 0 -#define PJ_HAS_ERRNO_H 0 -#define PJ_HAS_LINUX_SOCKET_H 1 -#define PJ_HAS_MALLOC_H 0 -#define PJ_HAS_NETDB_H 0 -#define PJ_HAS_NETINET_IN_H 0 -#define PJ_HAS_SETJMP_H 0 -#define PJ_HAS_STDARG_H 1 -#define PJ_HAS_STDDEF_H 0 -#define PJ_HAS_STDIO_H 0 -#define PJ_HAS_STDLIB_H 0 -#define PJ_HAS_STRING_H 0 -#define PJ_HAS_SYS_IOCTL_H 0 -#define PJ_HAS_SYS_SELECT_H 0 -#define PJ_HAS_SYS_SOCKET_H 0 -#define PJ_HAS_SYS_TIMEB_H 0 -#define PJ_HAS_SYS_TYPES_H 0 -#define PJ_HAS_TIME_H 0 -#define PJ_HAS_UNISTD_H 0 - -#define PJ_HAS_MSWSOCK_H 0 -#define PJ_HAS_WINSOCK_H 0 -#define PJ_HAS_WINSOCK2_H 0 - -#define PJ_SOCK_HAS_INET_ATON 0 - -/* When this macro is set, getsockopt(SOL_SOCKET, SO_ERROR) will return - * the status of non-blocking connect() operation. - */ -#define PJ_HAS_SO_ERROR 1 - -/* This value specifies the value set in errno by the OS when a non-blocking - * socket recv() can not return immediate daata. - */ -#define PJ_BLOCKING_ERROR_VAL EAGAIN - -/* This value specifies the value set in errno by the OS when a non-blocking - * socket connect() can not get connected immediately. - */ -#define PJ_BLOCKING_CONNECT_ERROR_VAL EINPROGRESS - -#ifndef PJ_HAS_THREADS -# define PJ_HAS_THREADS (1) -#endif - - -/* - * Declare __FD_SETSIZE now before including <linux*>. - */ -#define __FD_SETSIZE PJ_IOQUEUE_MAX_HANDLES - -#define NULL ((void*)0) - -#include <linux/module.h> /* Needed by all modules */ -#include <linux/kernel.h> /* Needed for KERN_INFO */ - -#define __PJ_EXPORT_SYMBOL(a) EXPORT_SYMBOL(a); - -/* - * Override features. - */ -#define PJ_HAS_FLOATING_POINT 0 -#define PJ_HAS_MALLOC 0 -#define PJ_HAS_SEMAPHORE 0 -#define PJ_HAS_EVENT_OBJ 0 -#define PJ_HAS_HIGH_RES_TIMER 1 -#define PJ_OS_HAS_CHECK_STACK 0 -#define PJ_TERM_HAS_COLOR 0 - -#define PJ_ATOMIC_VALUE_TYPE int -#define PJ_THREAD_DESC_SIZE 128 - -#endif /* __PJ_COMPAT_OS_LINUX_KERNEL_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
+ */
+/* $Log: /pjproject-0.3/pjlib/include/pj/compat/os_linux_kernel.h $
+ *
+ * 4 10/29/05 11:51a Bennylp
+ * Version 0.3-pre2.
+ *
+ * 3 10/14/05 12:26a Bennylp
+ * Finished error code framework, some fixes in ioqueue, etc. Pretty
+ * major.
+ *
+ * 2 9/22/05 10:31a Bennylp
+ * Moving all *.h files to include/.
+ *
+ * 1 9/21/05 1:38p Bennylp
+ * Created.
+ *
+ */
+#ifndef __PJ_COMPAT_OS_LINUX_KERNEL_H__
+#define __PJ_COMPAT_OS_LINUX_KERNEL_H__
+
+/**
+ * @file os_linux.h
+ * @brief Describes Linux operating system specifics.
+ */
+
+#define PJ_HAS_ARPA_INET_H 0
+#define PJ_HAS_ASSERT_H 0
+#define PJ_HAS_CTYPE_H 0
+#define PJ_HAS_ERRNO_H 0
+#define PJ_HAS_LINUX_SOCKET_H 1
+#define PJ_HAS_MALLOC_H 0
+#define PJ_HAS_NETDB_H 0
+#define PJ_HAS_NETINET_IN_H 0
+#define PJ_HAS_SETJMP_H 0
+#define PJ_HAS_STDARG_H 1
+#define PJ_HAS_STDDEF_H 0
+#define PJ_HAS_STDIO_H 0
+#define PJ_HAS_STDLIB_H 0
+#define PJ_HAS_STRING_H 0
+#define PJ_HAS_SYS_IOCTL_H 0
+#define PJ_HAS_SYS_SELECT_H 0
+#define PJ_HAS_SYS_SOCKET_H 0
+#define PJ_HAS_SYS_TIMEB_H 0
+#define PJ_HAS_SYS_TYPES_H 0
+#define PJ_HAS_TIME_H 0
+#define PJ_HAS_UNISTD_H 0
+
+#define PJ_HAS_MSWSOCK_H 0
+#define PJ_HAS_WINSOCK_H 0
+#define PJ_HAS_WINSOCK2_H 0
+
+#define PJ_SOCK_HAS_INET_ATON 0
+
+/* When this macro is set, getsockopt(SOL_SOCKET, SO_ERROR) will return
+ * the status of non-blocking connect() operation.
+ */
+#define PJ_HAS_SO_ERROR 1
+
+/* This value specifies the value set in errno by the OS when a non-blocking
+ * socket recv() can not return immediate daata.
+ */
+#define PJ_BLOCKING_ERROR_VAL EAGAIN
+
+/* This value specifies the value set in errno by the OS when a non-blocking
+ * socket connect() can not get connected immediately.
+ */
+#define PJ_BLOCKING_CONNECT_ERROR_VAL EINPROGRESS
+
+#ifndef PJ_HAS_THREADS
+# define PJ_HAS_THREADS (1)
+#endif
+
+
+/*
+ * Declare __FD_SETSIZE now before including <linux*>.
+ */
+#define __FD_SETSIZE PJ_IOQUEUE_MAX_HANDLES
+
+#define NULL ((void*)0)
+
+#include <linux/module.h> /* Needed by all modules */
+#include <linux/kernel.h> /* Needed for KERN_INFO */
+
+#define __PJ_EXPORT_SYMBOL(a) EXPORT_SYMBOL(a);
+
+/*
+ * Override features.
+ */
+#define PJ_HAS_FLOATING_POINT 0
+#define PJ_HAS_MALLOC 0
+#define PJ_HAS_SEMAPHORE 0
+#define PJ_HAS_EVENT_OBJ 0
+#define PJ_HAS_HIGH_RES_TIMER 1
+#define PJ_OS_HAS_CHECK_STACK 0
+#define PJ_TERM_HAS_COLOR 0
+
+#define PJ_ATOMIC_VALUE_TYPE int
+#define PJ_THREAD_DESC_SIZE 128
+
+#endif /* __PJ_COMPAT_OS_LINUX_KERNEL_H__ */
+
diff --git a/pjlib/include/pj/compat/os_palmos.h b/pjlib/include/pj/compat/os_palmos.h index e2ac4b52..7fb56470 100644 --- a/pjlib/include/pj/compat/os_palmos.h +++ b/pjlib/include/pj/compat/os_palmos.h @@ -1,49 +1,70 @@ -/* $Id$ - * - */ -/* $Log: /pjproject-0.3/pjlib/src/pj/compat/os_palmos.h $ - * - * 3 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 2 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#ifndef __PJ_COMPAT_OS_PALMOS_H__ -#define __PJ_COMPAT_OS_PALMOS_H__ - -/** - * @file os_palmos.h - * @brief Describes PalmOS operating system specifics. - */ - -#define PJ_HAS_ARPA_INET_H 0 -#define PJ_HAS_ASSERT_H 1 -#define PJ_HAS_CTYPE_H 1 -#define PJ_HAS_ERRNO_H 0 -#define PJ_HAS_MALLOC_H 1 -#define PJ_HAS_NETDB_H 0 -#define PJ_HAS_NETINET_IN_H 0 -#define PJ_HAS_SETJMP_H 1 -#define PJ_HAS_STDARG_H 1 -#define PJ_HAS_STDDEF_H 1 -#define PJ_HAS_STDIO_H 1 -#define PJ_HAS_STDLIB_H 1 -#define PJ_HAS_STRING_H 1 -#define PJ_HAS_SYS_IOCTL_H 0 -#define PJ_HAS_SYS_SELECT_H 0 -#define PJ_HAS_SYS_SOCKET_H 0 -#define PJ_HAS_SYS_TIMEB_H 0 -#define PJ_HAS_SYS_TYPES_H 1 -#define PJ_HAS_TIME_H 1 -#define PJ_HAS_UNISTD_H 0 - -#define PJ_HAS_MSWSOCK_H 0 -#define PJ_HAS_WINSOCK_H 0 -#define PJ_HAS_WINSOCK2_H 0 - -#define PJ_SOCK_HAS_INET_ATON 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
+ */
+/* $Log: /pjproject-0.3/pjlib/src/pj/compat/os_palmos.h $
+ *
+ * 3 9/21/05 1:39p Bennylp
+ * Periodic checkin for backup.
+ *
+ * 2 9/17/05 10:37a Bennylp
+ * Major reorganization towards version 0.3.
+ *
+ */
+#ifndef __PJ_COMPAT_OS_PALMOS_H__
+#define __PJ_COMPAT_OS_PALMOS_H__
+
+/**
+ * @file os_palmos.h
+ * @brief Describes PalmOS operating system specifics.
+ */
+
+#define PJ_HAS_ARPA_INET_H 0
+#define PJ_HAS_ASSERT_H 1
+#define PJ_HAS_CTYPE_H 1
+#define PJ_HAS_ERRNO_H 0
+#define PJ_HAS_MALLOC_H 1
+#define PJ_HAS_NETDB_H 0
+#define PJ_HAS_NETINET_IN_H 0
+#define PJ_HAS_SETJMP_H 1
+#define PJ_HAS_STDARG_H 1
+#define PJ_HAS_STDDEF_H 1
+#define PJ_HAS_STDIO_H 1
+#define PJ_HAS_STDLIB_H 1
+#define PJ_HAS_STRING_H 1
+#define PJ_HAS_SYS_IOCTL_H 0
+#define PJ_HAS_SYS_SELECT_H 0
+#define PJ_HAS_SYS_SOCKET_H 0
+#define PJ_HAS_SYS_TIMEB_H 0
+#define PJ_HAS_SYS_TYPES_H 1
+#define PJ_HAS_TIME_H 1
+#define PJ_HAS_UNISTD_H 0
+
+#define PJ_HAS_MSWSOCK_H 0
+#define PJ_HAS_WINSOCK_H 0
+#define PJ_HAS_WINSOCK2_H 0
+
+#define PJ_SOCK_HAS_INET_ATON 0
/* When this macro is set, getsockopt(SOL_SOCKET, SO_ERROR) will return
* the status of non-blocking connect() operation.
@@ -59,13 +80,13 @@ * socket connect() can not get connected immediately.
*/
#define PJ_BLOCKING_CONNECT_ERROR_VAL xxx
- -/* Default threading is enabled, unless it's overridden. */ -#ifndef PJ_HAS_THREADS -# define PJ_HAS_THREADS (1) -#endif - -#define PJ_HAS_HIGH_RES_TIMER 1 -#define PJ_OS_HAS_CHECK_STACK 0 - -#endif /* __PJ_COMPAT_OS_PALMOS_H__ */ +
+/* Default threading is enabled, unless it's overridden. */
+#ifndef PJ_HAS_THREADS
+# define PJ_HAS_THREADS (1)
+#endif
+
+#define PJ_HAS_HIGH_RES_TIMER 1
+#define PJ_OS_HAS_CHECK_STACK 0
+
+#endif /* __PJ_COMPAT_OS_PALMOS_H__ */
diff --git a/pjlib/include/pj/compat/os_sunos.h b/pjlib/include/pj/compat/os_sunos.h index 87c408ab..d2406e50 100644 --- a/pjlib/include/pj/compat/os_sunos.h +++ b/pjlib/include/pj/compat/os_sunos.h @@ -1,73 +1,94 @@ -/* $Id$ - * - */ -/* $Log: $ - * - */ -#ifndef __PJ_COMPAT_OS_SUNOS_H__ -#define __PJ_COMPAT_OS_SUNOS_H__ - -/** - * @file os_sunos.h - * @brief Describes SunOS/Solaris operating system specifics. - */ - -#define PJ_HAS_ARPA_INET_H 1 -#define PJ_HAS_ASSERT_H 1 -#define PJ_HAS_CTYPE_H 1 -#define PJ_HAS_ERRNO_H 1 -#define PJ_HAS_LINUX_SOCKET_H 0 -#define PJ_HAS_MALLOC_H 1 -#define PJ_HAS_NETDB_H 1 -#define PJ_HAS_NETINET_IN_H 1 -#define PJ_HAS_SETJMP_H 1 -#define PJ_HAS_STDARG_H 1 -#define PJ_HAS_STDDEF_H 1 -#define PJ_HAS_STDIO_H 1 -#define PJ_HAS_STDLIB_H 1 -#define PJ_HAS_STRING_H 1 -#define PJ_HAS_SYS_IOCTL_H 1 -#define PJ_HAS_SYS_SELECT_H 1 -#define PJ_HAS_SYS_SOCKET_H 1 -#define PJ_HAS_SYS_TIMEB_H 1 -#define PJ_HAS_SYS_TYPES_H 1 -#define PJ_HAS_TIME_H 1 -#define PJ_HAS_UNISTD_H 1 - -#define PJ_HAS_MSWSOCK_H 0 -#define PJ_HAS_WINSOCK_H 0 -#define PJ_HAS_WINSOCK2_H 0 - -#define PJ_SOCK_HAS_INET_ATON 0 - -/* When this macro is set, getsockopt(SOL_SOCKET, SO_ERROR) will return - * the status of non-blocking connect() operation. - */ -#define PJ_HAS_SO_ERROR 0 - -/* This value specifies the value set in errno by the OS when a non-blocking - * socket recv() can not return immediate daata. - */ -#define PJ_BLOCKING_ERROR_VAL EWOULDBLOCK - -/* This value specifies the value set in errno by the OS when a non-blocking - * socket connect() can not get connected immediately. - */ -#define PJ_BLOCKING_CONNECT_ERROR_VAL EINPROGRESS - -/* Default threading is enabled, unless it's overridden. */ -#ifndef PJ_HAS_THREADS -# define PJ_HAS_THREADS (1) -#endif - -#define PJ_HAS_HIGH_RES_TIMER 1 -#define PJ_HAS_MALLOC 1 -#define PJ_OS_HAS_CHECK_STACK 0 - -#define PJ_ATOMIC_VALUE_TYPE long - -/* Get BSD related identifers in Sun's include files */ -#define BSD_COMP - -#endif /* __PJ_COMPAT_OS_SUNOS_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
+ */
+/* $Log: $
+ *
+ */
+#ifndef __PJ_COMPAT_OS_SUNOS_H__
+#define __PJ_COMPAT_OS_SUNOS_H__
+
+/**
+ * @file os_sunos.h
+ * @brief Describes SunOS/Solaris operating system specifics.
+ */
+
+#define PJ_HAS_ARPA_INET_H 1
+#define PJ_HAS_ASSERT_H 1
+#define PJ_HAS_CTYPE_H 1
+#define PJ_HAS_ERRNO_H 1
+#define PJ_HAS_LINUX_SOCKET_H 0
+#define PJ_HAS_MALLOC_H 1
+#define PJ_HAS_NETDB_H 1
+#define PJ_HAS_NETINET_IN_H 1
+#define PJ_HAS_SETJMP_H 1
+#define PJ_HAS_STDARG_H 1
+#define PJ_HAS_STDDEF_H 1
+#define PJ_HAS_STDIO_H 1
+#define PJ_HAS_STDLIB_H 1
+#define PJ_HAS_STRING_H 1
+#define PJ_HAS_SYS_IOCTL_H 1
+#define PJ_HAS_SYS_SELECT_H 1
+#define PJ_HAS_SYS_SOCKET_H 1
+#define PJ_HAS_SYS_TIMEB_H 1
+#define PJ_HAS_SYS_TYPES_H 1
+#define PJ_HAS_TIME_H 1
+#define PJ_HAS_UNISTD_H 1
+
+#define PJ_HAS_MSWSOCK_H 0
+#define PJ_HAS_WINSOCK_H 0
+#define PJ_HAS_WINSOCK2_H 0
+
+#define PJ_SOCK_HAS_INET_ATON 0
+
+/* When this macro is set, getsockopt(SOL_SOCKET, SO_ERROR) will return
+ * the status of non-blocking connect() operation.
+ */
+#define PJ_HAS_SO_ERROR 0
+
+/* This value specifies the value set in errno by the OS when a non-blocking
+ * socket recv() can not return immediate daata.
+ */
+#define PJ_BLOCKING_ERROR_VAL EWOULDBLOCK
+
+/* This value specifies the value set in errno by the OS when a non-blocking
+ * socket connect() can not get connected immediately.
+ */
+#define PJ_BLOCKING_CONNECT_ERROR_VAL EINPROGRESS
+
+/* Default threading is enabled, unless it's overridden. */
+#ifndef PJ_HAS_THREADS
+# define PJ_HAS_THREADS (1)
+#endif
+
+#define PJ_HAS_HIGH_RES_TIMER 1
+#define PJ_HAS_MALLOC 1
+#define PJ_OS_HAS_CHECK_STACK 0
+
+#define PJ_ATOMIC_VALUE_TYPE long
+
+/* Get BSD related identifers in Sun's include files */
+#define BSD_COMP
+
+#endif /* __PJ_COMPAT_OS_SUNOS_H__ */
+
diff --git a/pjlib/include/pj/compat/os_win32.h b/pjlib/include/pj/compat/os_win32.h index e8391b94..b1280601 100644 --- a/pjlib/include/pj/compat/os_win32.h +++ b/pjlib/include/pj/compat/os_win32.h @@ -1,89 +1,110 @@ -/* $Id$ - * - */ -/* $Log: /pjproject-0.3/pjlib/include/pj/compat/os_win32.h $ - * - * 6 10/29/05 11:51a Bennylp - * Version 0.3-pre2. - * - * 5 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 4 9/22/05 10:31a Bennylp - * Moving all *.h files to include/. - * - * 3 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 2 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#ifndef __PJ_COMPAT_OS_WIN32_H__ -#define __PJ_COMPAT_OS_WIN32_H__ - -/** - * @file os_win32.h - * @brief Describes Win32 operating system family specifics. - */ - -#define WIN32_LEAN_AND_MEAN -#define PJ_WIN32_WINNT 0x0400 -#define _WIN32_WINNT PJ_WIN32_WINNT - -#define PJ_HAS_ARPA_INET_H 0 -#define PJ_HAS_ASSERT_H 1 -#define PJ_HAS_CTYPE_H 1 -#define PJ_HAS_ERRNO_H 0 /* Must be zero, otherwise errno_test() fails. */ -#define PJ_HAS_LINUX_SOCKET_H 0 -#define PJ_HAS_MALLOC_H 1 -#define PJ_HAS_NETDB_H 0 -#define PJ_HAS_NETINET_IN_H 0 -#define PJ_HAS_SETJMP_H 1 -#define PJ_HAS_STDARG_H 1 -#define PJ_HAS_STDDEF_H 1 -#define PJ_HAS_STDIO_H 1 -#define PJ_HAS_STDLIB_H 1 -#define PJ_HAS_STRING_H 1 -#define PJ_HAS_SYS_IOCTL_H 0 -#define PJ_HAS_SYS_SELECT_H 0 -#define PJ_HAS_SYS_SOCKET_H 0 -#define PJ_HAS_SYS_TIMEB_H 1 -#define PJ_HAS_SYS_TYPES_H 1 -#define PJ_HAS_TIME_H 1 -#define PJ_HAS_UNISTD_H 0 - -#define PJ_HAS_MSWSOCK_H 1 -#define PJ_HAS_WINSOCK_H 0 -#define PJ_HAS_WINSOCK2_H 1 - -#define PJ_SOCK_HAS_INET_ATON 0 - -/* When this macro is set, getsockopt(SOL_SOCKET, SO_ERROR) will return - * the status of non-blocking connect() operation. - */ -#define PJ_HAS_SO_ERROR 0 - -/* This value specifies the value set in errno by the OS when a non-blocking - * socket recv() or send() can not return immediately. - */ -#define PJ_BLOCKING_ERROR_VAL WSAEWOULDBLOCK - -/* This value specifies the value set in errno by the OS when a non-blocking - * socket connect() can not get connected immediately. - */ -#define PJ_BLOCKING_CONNECT_ERROR_VAL WSAEWOULDBLOCK - -/* Default threading is enabled, unless it's overridden. */ -#ifndef PJ_HAS_THREADS -# define PJ_HAS_THREADS (1) -#endif - -#define PJ_HAS_HIGH_RES_TIMER 1 -#define PJ_HAS_MALLOC 1 -#define PJ_OS_HAS_CHECK_STACK 1 - -#define PJ_ATOMIC_VALUE_TYPE long - -#endif /* __PJ_COMPAT_OS_WIN32_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
+ */
+/* $Log: /pjproject-0.3/pjlib/include/pj/compat/os_win32.h $
+ *
+ * 6 10/29/05 11:51a Bennylp
+ * Version 0.3-pre2.
+ *
+ * 5 10/14/05 12:26a Bennylp
+ * Finished error code framework, some fixes in ioqueue, etc. Pretty
+ * major.
+ *
+ * 4 9/22/05 10:31a Bennylp
+ * Moving all *.h files to include/.
+ *
+ * 3 9/21/05 1:39p Bennylp
+ * Periodic checkin for backup.
+ *
+ * 2 9/17/05 10:37a Bennylp
+ * Major reorganization towards version 0.3.
+ *
+ */
+#ifndef __PJ_COMPAT_OS_WIN32_H__
+#define __PJ_COMPAT_OS_WIN32_H__
+
+/**
+ * @file os_win32.h
+ * @brief Describes Win32 operating system family specifics.
+ */
+
+#define WIN32_LEAN_AND_MEAN
+#define PJ_WIN32_WINNT 0x0400
+#define _WIN32_WINNT PJ_WIN32_WINNT
+
+#define PJ_HAS_ARPA_INET_H 0
+#define PJ_HAS_ASSERT_H 1
+#define PJ_HAS_CTYPE_H 1
+#define PJ_HAS_ERRNO_H 0 /* Must be zero, otherwise errno_test() fails. */
+#define PJ_HAS_LINUX_SOCKET_H 0
+#define PJ_HAS_MALLOC_H 1
+#define PJ_HAS_NETDB_H 0
+#define PJ_HAS_NETINET_IN_H 0
+#define PJ_HAS_SETJMP_H 1
+#define PJ_HAS_STDARG_H 1
+#define PJ_HAS_STDDEF_H 1
+#define PJ_HAS_STDIO_H 1
+#define PJ_HAS_STDLIB_H 1
+#define PJ_HAS_STRING_H 1
+#define PJ_HAS_SYS_IOCTL_H 0
+#define PJ_HAS_SYS_SELECT_H 0
+#define PJ_HAS_SYS_SOCKET_H 0
+#define PJ_HAS_SYS_TIMEB_H 1
+#define PJ_HAS_SYS_TYPES_H 1
+#define PJ_HAS_TIME_H 1
+#define PJ_HAS_UNISTD_H 0
+
+#define PJ_HAS_MSWSOCK_H 1
+#define PJ_HAS_WINSOCK_H 0
+#define PJ_HAS_WINSOCK2_H 1
+
+#define PJ_SOCK_HAS_INET_ATON 0
+
+/* When this macro is set, getsockopt(SOL_SOCKET, SO_ERROR) will return
+ * the status of non-blocking connect() operation.
+ */
+#define PJ_HAS_SO_ERROR 0
+
+/* This value specifies the value set in errno by the OS when a non-blocking
+ * socket recv() or send() can not return immediately.
+ */
+#define PJ_BLOCKING_ERROR_VAL WSAEWOULDBLOCK
+
+/* This value specifies the value set in errno by the OS when a non-blocking
+ * socket connect() can not get connected immediately.
+ */
+#define PJ_BLOCKING_CONNECT_ERROR_VAL WSAEWOULDBLOCK
+
+/* Default threading is enabled, unless it's overridden. */
+#ifndef PJ_HAS_THREADS
+# define PJ_HAS_THREADS (1)
+#endif
+
+#define PJ_HAS_HIGH_RES_TIMER 1
+#define PJ_HAS_MALLOC 1
+#define PJ_OS_HAS_CHECK_STACK 1
+
+#define PJ_ATOMIC_VALUE_TYPE long
+
+#endif /* __PJ_COMPAT_OS_WIN32_H__ */
diff --git a/pjlib/include/pj/compat/rand.h b/pjlib/include/pj/compat/rand.h index b65bf103..af4d915d 100644 --- a/pjlib/include/pj/compat/rand.h +++ b/pjlib/include/pj/compat/rand.h @@ -1,67 +1,88 @@ -/* $Id$ - * - */ -/* $Log: /pjproject-0.3/pjlib/include/pj/compat/rand.h $ - * - * 3 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 2 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 1 9/17/05 10:36a Bennylp - * Created. - * - */ -#ifndef __PJ_COMPAT_RAND_H__ -#define __PJ_COMPAT_RAND_H__ - -/** - * @file rand.h - * @brief Provides platform_rand() and platform_srand() functions. - */ - -#if defined(PJ_HAS_STDLIB_H) && PJ_HAS_STDLIB_H != 0 - /* - * Use stdlib based rand() and srand(). - */ -# include <stdlib.h> -# define platform_srand srand -# if defined(RAND_MAX) && RAND_MAX <= 0xFFFF - /* - * When rand() is only 16 bit strong, double the strength - * by calling it twice! - */ - PJ_INLINE(int) platform_rand(void) - { - return ((rand() & 0xFFFF) << 16) | (rand() & 0xFFFF); - } -# else -# define platform_rand rand -# endif - -#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0 - /* - * Linux kernel mode random number generator. - */ -# include <linux/random.h> -# define platform_srand(seed) - - PJ_INLINE(int) platform_rand(void) - { - int value; - get_random_bytes((void*)&value, sizeof(value)); - return value; - } - -#else -# warning "platform_rand() is not implemented" -# define platform_rand() 1 -# define platform_srand(seed) - -#endif - - -#endif /* __PJ_COMPAT_RAND_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
+ */
+/* $Log: /pjproject-0.3/pjlib/include/pj/compat/rand.h $
+ *
+ * 3 10/14/05 12:26a Bennylp
+ * Finished error code framework, some fixes in ioqueue, etc. Pretty
+ * major.
+ *
+ * 2 9/21/05 1:39p Bennylp
+ * Periodic checkin for backup.
+ *
+ * 1 9/17/05 10:36a Bennylp
+ * Created.
+ *
+ */
+#ifndef __PJ_COMPAT_RAND_H__
+#define __PJ_COMPAT_RAND_H__
+
+/**
+ * @file rand.h
+ * @brief Provides platform_rand() and platform_srand() functions.
+ */
+
+#if defined(PJ_HAS_STDLIB_H) && PJ_HAS_STDLIB_H != 0
+ /*
+ * Use stdlib based rand() and srand().
+ */
+# include <stdlib.h>
+# define platform_srand srand
+# if defined(RAND_MAX) && RAND_MAX <= 0xFFFF
+ /*
+ * When rand() is only 16 bit strong, double the strength
+ * by calling it twice!
+ */
+ PJ_INLINE(int) platform_rand(void)
+ {
+ return ((rand() & 0xFFFF) << 16) | (rand() & 0xFFFF);
+ }
+# else
+# define platform_rand rand
+# endif
+
+#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0
+ /*
+ * Linux kernel mode random number generator.
+ */
+# include <linux/random.h>
+# define platform_srand(seed)
+
+ PJ_INLINE(int) platform_rand(void)
+ {
+ int value;
+ get_random_bytes((void*)&value, sizeof(value));
+ return value;
+ }
+
+#else
+# warning "platform_rand() is not implemented"
+# define platform_rand() 1
+# define platform_srand(seed)
+
+#endif
+
+
+#endif /* __PJ_COMPAT_RAND_H__ */
+
diff --git a/pjlib/include/pj/compat/setjmp.h b/pjlib/include/pj/compat/setjmp.h index fb0c7d69..f018cd97 100644 --- a/pjlib/include/pj/compat/setjmp.h +++ b/pjlib/include/pj/compat/setjmp.h @@ -1,91 +1,112 @@ -/* $Id$ - * - */ -/* $Log: /pjproject-0.3/pjlib/include/pj/compat/setjmp.h $ - * - * 4 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 3 9/22/05 10:31a Bennylp - * Moving all *.h files to include/. - * - * 2 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 1 9/17/05 10:36a Bennylp - * Created. - * - */ -#ifndef __PJ_COMPAT_SETJMP_H__ -#define __PJ_COMPAT_SETJMP_H__ - -/** - * @file setjmp.h - * @brief Provides setjmp.h functionality. - */ - -#if defined(PJ_HAS_SETJMP_H) && PJ_HAS_SETJMP_H != 0 -# include <setjmp.h> - typedef jmp_buf pj_jmp_buf; -# define pj_setjmp(buf) setjmp(buf) -# define pj_longjmp(buf,d) longjmp(buf,d) - -#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0 && \ - defined(PJ_M_I386) && PJ_M_I386 != 0 - - /* - * These are taken from uClibc. - * Copyright (C) 2000-2003 Erik Andersen <andersen@uclibc.org> - */ -# if defined __USE_MISC || defined _ASM -# define JB_BX 0 -# define JB_SI 1 -# define JB_DI 2 -# define JB_BP 3 -# define JB_SP 4 -# define JB_PC 5 -# define JB_SIZE 24 -# endif - -# ifndef _ASM - typedef int __jmp_buf[6]; - - /* A `sigset_t' has a bit for each signal. */ -# define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int))) - typedef struct __sigset_t_tag - { - unsigned long int __val[_SIGSET_NWORDS]; - } __sigset_t; - - /* Calling environment, plus possibly a saved signal mask. */ - typedef struct __jmp_buf_tag /* C++ doesn't like tagless structs. */ - { - /* NOTE: The machine-dependent definitions of `__sigsetjmp' - assume that a `jmp_buf' begins with a `__jmp_buf' and that - `__mask_was_saved' follows it. Do not move these members - or add others before it. */ - __jmp_buf __jmpbuf; /* Calling environment. */ - int __mask_was_saved; /* Saved the signal mask? */ - // we never saved the mask. - __sigset_t __saved_mask; /* Saved signal mask. */ - } jmp_buf[1]; - - typedef jmp_buf sigjmp_buf; - typedef jmp_buf pj_jmp_buf; - - PJ_DECL(int) pj_setjmp(pj_jmp_buf env); - PJ_DECL(void) pj_longjmp(pj_jmp_buf env, int val) __attribute__((noreturn)); - -# endif /* _ASM */ - -#else -# warning "setjmp()/longjmp() is not implemented" - typedef int pj_jmp_buf[1]; -# define pj_setjmp(buf) 0 -# define pj_longjmp(buf,d) 0 -#endif - - -#endif /* __PJ_COMPAT_SETJMP_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
+ */
+/* $Log: /pjproject-0.3/pjlib/include/pj/compat/setjmp.h $
+ *
+ * 4 10/14/05 12:26a Bennylp
+ * Finished error code framework, some fixes in ioqueue, etc. Pretty
+ * major.
+ *
+ * 3 9/22/05 10:31a Bennylp
+ * Moving all *.h files to include/.
+ *
+ * 2 9/21/05 1:39p Bennylp
+ * Periodic checkin for backup.
+ *
+ * 1 9/17/05 10:36a Bennylp
+ * Created.
+ *
+ */
+#ifndef __PJ_COMPAT_SETJMP_H__
+#define __PJ_COMPAT_SETJMP_H__
+
+/**
+ * @file setjmp.h
+ * @brief Provides setjmp.h functionality.
+ */
+
+#if defined(PJ_HAS_SETJMP_H) && PJ_HAS_SETJMP_H != 0
+# include <setjmp.h>
+ typedef jmp_buf pj_jmp_buf;
+# define pj_setjmp(buf) setjmp(buf)
+# define pj_longjmp(buf,d) longjmp(buf,d)
+
+#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0 && \
+ defined(PJ_M_I386) && PJ_M_I386 != 0
+
+ /*
+ * These are taken from uClibc.
+ * Copyright (C) 2000-2003 Erik Andersen <andersen@uclibc.org>
+ */
+# if defined __USE_MISC || defined _ASM
+# define JB_BX 0
+# define JB_SI 1
+# define JB_DI 2
+# define JB_BP 3
+# define JB_SP 4
+# define JB_PC 5
+# define JB_SIZE 24
+# endif
+
+# ifndef _ASM
+ typedef int __jmp_buf[6];
+
+ /* A `sigset_t' has a bit for each signal. */
+# define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int)))
+ typedef struct __sigset_t_tag
+ {
+ unsigned long int __val[_SIGSET_NWORDS];
+ } __sigset_t;
+
+ /* Calling environment, plus possibly a saved signal mask. */
+ typedef struct __jmp_buf_tag /* C++ doesn't like tagless structs. */
+ {
+ /* NOTE: The machine-dependent definitions of `__sigsetjmp'
+ assume that a `jmp_buf' begins with a `__jmp_buf' and that
+ `__mask_was_saved' follows it. Do not move these members
+ or add others before it. */
+ __jmp_buf __jmpbuf; /* Calling environment. */
+ int __mask_was_saved; /* Saved the signal mask? */
+ // we never saved the mask.
+ __sigset_t __saved_mask; /* Saved signal mask. */
+ } jmp_buf[1];
+
+ typedef jmp_buf sigjmp_buf;
+ typedef jmp_buf pj_jmp_buf;
+
+ PJ_DECL(int) pj_setjmp(pj_jmp_buf env);
+ PJ_DECL(void) pj_longjmp(pj_jmp_buf env, int val) __attribute__((noreturn));
+
+# endif /* _ASM */
+
+#else
+# warning "setjmp()/longjmp() is not implemented"
+ typedef int pj_jmp_buf[1];
+# define pj_setjmp(buf) 0
+# define pj_longjmp(buf,d) 0
+#endif
+
+
+#endif /* __PJ_COMPAT_SETJMP_H__ */
+
diff --git a/pjlib/include/pj/compat/size_t.h b/pjlib/include/pj/compat/size_t.h index bdb7e02a..70ae0680 100644 --- a/pjlib/include/pj/compat/size_t.h +++ b/pjlib/include/pj/compat/size_t.h @@ -1,25 +1,46 @@ -/* $Id$ - * - */ -/* $Log: /pjproject-0.3/pjlib/src/pj/compat/size_t.h $ - * - * 2 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 1 9/17/05 10:36a Bennylp - * Created. - * - */ -#ifndef __PJ_COMPAT_SIZE_T_H__ -#define __PJ_COMPAT_SIZE_T_H__ - -/** - * @file size_t.h - * @brief Provides size_t type. - */ -#if PJ_HAS_STDDEF_H -# include <stddef.h> -#endif - -#endif /* __PJ_COMPAT_SIZE_T_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
+ */
+/* $Log: /pjproject-0.3/pjlib/src/pj/compat/size_t.h $
+ *
+ * 2 9/21/05 1:39p Bennylp
+ * Periodic checkin for backup.
+ *
+ * 1 9/17/05 10:36a Bennylp
+ * Created.
+ *
+ */
+#ifndef __PJ_COMPAT_SIZE_T_H__
+#define __PJ_COMPAT_SIZE_T_H__
+
+/**
+ * @file size_t.h
+ * @brief Provides size_t type.
+ */
+#if PJ_HAS_STDDEF_H
+# include <stddef.h>
+#endif
+
+#endif /* __PJ_COMPAT_SIZE_T_H__ */
+
diff --git a/pjlib/include/pj/compat/socket.h b/pjlib/include/pj/compat/socket.h index f2de0cb5..2a989d18 100644 --- a/pjlib/include/pj/compat/socket.h +++ b/pjlib/include/pj/compat/socket.h @@ -1,131 +1,152 @@ -/* $Id$ - * -*/ -/* $Log: /pjproject-0.3/pjlib/include/pj/compat/socket.h $ - * - * 5 10/29/05 11:51a Bennylp - * Version 0.3-pre2. - * - * 4 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 3 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 2 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#ifndef __PJ_COMPAT_SOCKET_H__ -#define __PJ_COMPAT_SOCKET_H__ - -/** - * @file socket.h - * @brief Provides all socket related functions,data types, error codes, etc. - */ - -#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 - -#if defined(PJ_HAS_SYS_TYPES_H) && PJ_HAS_SYS_TYPES_H != 0 -# include <sys/types.h> -#endif - -#if defined(PJ_HAS_SYS_SOCKET_H) && PJ_HAS_SYS_SOCKET_H != 0 -# include <sys/socket.h> -#endif - -#if defined(PJ_HAS_LINUX_SOCKET_H) && PJ_HAS_LINUX_SOCKET_H != 0 -# include <linux/socket.h> -#endif - -#if defined(PJ_HAS_SYS_SELECT_H) && PJ_HAS_SYS_SELECT_H != 0 -# include <sys/select.h> -#endif - -#if defined(PJ_HAS_NETINET_IN_H) && PJ_HAS_NETINET_IN_H != 0 -# include <netinet/in.h> -#endif - -#if defined(PJ_HAS_ARPA_INET_H) && PJ_HAS_ARPA_INET_H != 0 -# include <arpa/inet.h> -#endif - -#if defined(PJ_HAS_SYS_IOCTL_H) && PJ_HAS_SYS_IOCTL_H != 0 -# include <sys/ioctl.h> /* FBIONBIO */ -#endif - -#if defined(PJ_HAS_ERRNO_H) && PJ_HAS_ERRNO_H != 0 -# include <errno.h> -#endif - -#if defined(PJ_HAS_NETDB_H) && PJ_HAS_NETDB_H != 0 -# include <netdb.h> -#endif - -#if defined(PJ_HAS_UNISTD_H) && PJ_HAS_UNISTD_H != 0 -# include <unistd.h> -#endif - - -/* - * Define common errors. - */ -#ifdef PJ_WIN32 -# define OSERR_EWOULDBLOCK WSAEWOULDBLOCK -# define OSERR_EINPROGRESS WSAEINPROGRESS -#else -# define OSERR_EWOULDBLOCK EWOULDBLOCK -# define OSERR_EINPROGRESS EINPROGRESS -#endif - - -/* - * And undefine this.. - */ -#undef s_addr - -/* - * Linux kernel specifics - */ -#ifdef PJ_LINUX_KERNEL -# include <linux/net.h> -# include <asm/ioctls.h> /* FIONBIO */ -# include <linux/syscalls.h> /* sys_select() */ -# include <asm/uaccess.h> /* set/get_fs() */ - - typedef int socklen_t; -# define getsockopt sys_getsockopt - - /* - * Wrapper for select() in Linux kernel. - */ - PJ_INLINE(int) select(int n, fd_set *inp, fd_set *outp, fd_set *exp, - struct timeval *tvp) - { - int count; - mm_segment_t oldfs = get_fs(); - set_fs(KERNEL_DS); - count = sys_select(n, inp, outp, exp, tvp); - set_fs(oldfs); - return count; - } -#endif /* PJ_LINUX_KERNEL */ - - -/* - * Windows specific - */ -#ifdef PJ_WIN32 - typedef int socklen_t;; -#endif - - -#endif /* __PJ_COMPAT_SOCKET_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
+ */
+/* $Log: /pjproject-0.3/pjlib/include/pj/compat/socket.h $
+ *
+ * 5 10/29/05 11:51a Bennylp
+ * Version 0.3-pre2.
+ *
+ * 4 10/14/05 12:26a Bennylp
+ * Finished error code framework, some fixes in ioqueue, etc. Pretty
+ * major.
+ *
+ * 3 9/21/05 1:39p Bennylp
+ * Periodic checkin for backup.
+ *
+ * 2 9/17/05 10:37a Bennylp
+ * Major reorganization towards version 0.3.
+ *
+ */
+#ifndef __PJ_COMPAT_SOCKET_H__
+#define __PJ_COMPAT_SOCKET_H__
+
+/**
+ * @file socket.h
+ * @brief Provides all socket related functions,data types, error codes, etc.
+ */
+
+#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
+
+#if defined(PJ_HAS_SYS_TYPES_H) && PJ_HAS_SYS_TYPES_H != 0
+# include <sys/types.h>
+#endif
+
+#if defined(PJ_HAS_SYS_SOCKET_H) && PJ_HAS_SYS_SOCKET_H != 0
+# include <sys/socket.h>
+#endif
+
+#if defined(PJ_HAS_LINUX_SOCKET_H) && PJ_HAS_LINUX_SOCKET_H != 0
+# include <linux/socket.h>
+#endif
+
+#if defined(PJ_HAS_SYS_SELECT_H) && PJ_HAS_SYS_SELECT_H != 0
+# include <sys/select.h>
+#endif
+
+#if defined(PJ_HAS_NETINET_IN_H) && PJ_HAS_NETINET_IN_H != 0
+# include <netinet/in.h>
+#endif
+
+#if defined(PJ_HAS_ARPA_INET_H) && PJ_HAS_ARPA_INET_H != 0
+# include <arpa/inet.h>
+#endif
+
+#if defined(PJ_HAS_SYS_IOCTL_H) && PJ_HAS_SYS_IOCTL_H != 0
+# include <sys/ioctl.h> /* FBIONBIO */
+#endif
+
+#if defined(PJ_HAS_ERRNO_H) && PJ_HAS_ERRNO_H != 0
+# include <errno.h>
+#endif
+
+#if defined(PJ_HAS_NETDB_H) && PJ_HAS_NETDB_H != 0
+# include <netdb.h>
+#endif
+
+#if defined(PJ_HAS_UNISTD_H) && PJ_HAS_UNISTD_H != 0
+# include <unistd.h>
+#endif
+
+
+/*
+ * Define common errors.
+ */
+#ifdef PJ_WIN32
+# define OSERR_EWOULDBLOCK WSAEWOULDBLOCK
+# define OSERR_EINPROGRESS WSAEINPROGRESS
+#else
+# define OSERR_EWOULDBLOCK EWOULDBLOCK
+# define OSERR_EINPROGRESS EINPROGRESS
+#endif
+
+
+/*
+ * And undefine this..
+ */
+#undef s_addr
+
+/*
+ * Linux kernel specifics
+ */
+#ifdef PJ_LINUX_KERNEL
+# include <linux/net.h>
+# include <asm/ioctls.h> /* FIONBIO */
+# include <linux/syscalls.h> /* sys_select() */
+# include <asm/uaccess.h> /* set/get_fs() */
+
+ typedef int socklen_t;
+# define getsockopt sys_getsockopt
+
+ /*
+ * Wrapper for select() in Linux kernel.
+ */
+ PJ_INLINE(int) select(int n, fd_set *inp, fd_set *outp, fd_set *exp,
+ struct timeval *tvp)
+ {
+ int count;
+ mm_segment_t oldfs = get_fs();
+ set_fs(KERNEL_DS);
+ count = sys_select(n, inp, outp, exp, tvp);
+ set_fs(oldfs);
+ return count;
+ }
+#endif /* PJ_LINUX_KERNEL */
+
+
+/*
+ * Windows specific
+ */
+#ifdef PJ_WIN32
+ typedef int socklen_t;;
+#endif
+
+
+#endif /* __PJ_COMPAT_SOCKET_H__ */
+
diff --git a/pjlib/include/pj/compat/sprintf.h b/pjlib/include/pj/compat/sprintf.h index a398770a..9028d85d 100644 --- a/pjlib/include/pj/compat/sprintf.h +++ b/pjlib/include/pj/compat/sprintf.h @@ -1,33 +1,54 @@ -/* $Id$ - * - */ -/* $Log: /pjproject-0.3/pjlib/include/pj/compat/sprintf.h $ - * - * 2 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 1 9/17/05 10:36a Bennylp - * Created. - * - */ -#ifndef __PJ_COMPAT_SPRINTF_H__ -#define __PJ_COMPAT_SPRINTF_H__ - -/** - * @file sprintf.h - * @brief Provides sprintf() and snprintf() functions. - */ - -#if defined(PJ_HAS_STDIO_H) && PJ_HAS_STDIO_H != 0 -# include <stdio.h> -#endif - -#if defined(_MSC_VER) -# define snprintf _snprintf -#endif - -#define pj_sprintf sprintf -#define pj_snprintf snprintf - -#endif /* __PJ_COMPAT_SPRINTF_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
+ */
+/* $Log: /pjproject-0.3/pjlib/include/pj/compat/sprintf.h $
+ *
+ * 2 10/14/05 12:26a Bennylp
+ * Finished error code framework, some fixes in ioqueue, etc. Pretty
+ * major.
+ *
+ * 1 9/17/05 10:36a Bennylp
+ * Created.
+ *
+ */
+#ifndef __PJ_COMPAT_SPRINTF_H__
+#define __PJ_COMPAT_SPRINTF_H__
+
+/**
+ * @file sprintf.h
+ * @brief Provides sprintf() and snprintf() functions.
+ */
+
+#if defined(PJ_HAS_STDIO_H) && PJ_HAS_STDIO_H != 0
+# include <stdio.h>
+#endif
+
+#if defined(_MSC_VER)
+# define snprintf _snprintf
+#endif
+
+#define pj_sprintf sprintf
+#define pj_snprintf snprintf
+
+#endif /* __PJ_COMPAT_SPRINTF_H__ */
diff --git a/pjlib/include/pj/compat/stdarg.h b/pjlib/include/pj/compat/stdarg.h index 87b3f2cc..a4a3addd 100644 --- a/pjlib/include/pj/compat/stdarg.h +++ b/pjlib/include/pj/compat/stdarg.h @@ -1,22 +1,43 @@ -/* $Id$ - * - */ -/* $Log: /pjproject-0.3/pjlib/src/pj/compat/stdarg.h $ - * - * 1 9/17/05 10:36a Bennylp - * Created. - * - */ -#ifndef __PJ_COMPAT_STDARG_H__ -#define __PJ_COMPAT_STDARG_H__ - -/** - * @file stdarg.h - * @brief Provides stdarg functionality. - */ - -#if defined(PJ_HAS_STDARG_H) && PJ_HAS_STDARG_H != 0 -# include <stdarg.h> -#endif - -#endif /* __PJ_COMPAT_STDARG_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
+ */
+/* $Log: /pjproject-0.3/pjlib/src/pj/compat/stdarg.h $
+ *
+ * 1 9/17/05 10:36a Bennylp
+ * Created.
+ *
+ */
+#ifndef __PJ_COMPAT_STDARG_H__
+#define __PJ_COMPAT_STDARG_H__
+
+/**
+ * @file stdarg.h
+ * @brief Provides stdarg functionality.
+ */
+
+#if defined(PJ_HAS_STDARG_H) && PJ_HAS_STDARG_H != 0
+# include <stdarg.h>
+#endif
+
+#endif /* __PJ_COMPAT_STDARG_H__ */
diff --git a/pjlib/include/pj/compat/stdfileio.h b/pjlib/include/pj/compat/stdfileio.h index 620b170b..e9915f7b 100644 --- a/pjlib/include/pj/compat/stdfileio.h +++ b/pjlib/include/pj/compat/stdfileio.h @@ -1,22 +1,43 @@ -/* $Id$ - * - */ -/* $Log: /pjproject-0.3/pjlib/src/pj/compat/stdfileio.h $ - * - * 1 9/17/05 10:36a Bennylp - * Created. - * - */ -#ifndef __PJ_COMPAT_STDFILEIO_H__ -#define __PJ_COMPAT_STDFILEIO_H__ - -/** - * @file stdfileio.h - * @brief Compatibility for ANSI file I/O like fputs, fflush, etc. - */ - -#if defined(PJ_HAS_STDIO_H) && PJ_HAS_STDIO_H != 0 -# include <stdio.h> -#endif - -#endif /* __PJ_COMPAT_STDFILEIO_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
+ */
+/* $Log: /pjproject-0.3/pjlib/src/pj/compat/stdfileio.h $
+ *
+ * 1 9/17/05 10:36a Bennylp
+ * Created.
+ *
+ */
+#ifndef __PJ_COMPAT_STDFILEIO_H__
+#define __PJ_COMPAT_STDFILEIO_H__
+
+/**
+ * @file stdfileio.h
+ * @brief Compatibility for ANSI file I/O like fputs, fflush, etc.
+ */
+
+#if defined(PJ_HAS_STDIO_H) && PJ_HAS_STDIO_H != 0
+# include <stdio.h>
+#endif
+
+#endif /* __PJ_COMPAT_STDFILEIO_H__ */
diff --git a/pjlib/include/pj/compat/string.h b/pjlib/include/pj/compat/string.h index b8917387..59d82c7c 100644 --- a/pjlib/include/pj/compat/string.h +++ b/pjlib/include/pj/compat/string.h @@ -1,44 +1,65 @@ -/* $Id$ - * - */ -/* $Log: /pjproject-0.3/pjlib/src/pj/compat/string.h $ - * - * 3 9/22/05 10:31a Bennylp - * Moving all *.h files to include/. - * - * 2 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 1 9/17/05 10:36a Bennylp - * Created. - * - */ -#ifndef __PJ_COMPAT_STRING_H__ -#define __PJ_COMPAT_STRING_H__ - -/** - * @file string.h - * @brief Provides string manipulation functions found in ANSI string.h. - */ - -#if defined(PJ_HAS_STRING_H) && PJ_HAS_STRING_H != 0 -# include <string.h> -#else - - PJ_DECL(int) strcasecmp(const char *s1, const char *s2); - PJ_DECL(int) strncasecmp(const char *s1, const char *s2, int len); - -#endif - -#if defined(_MSC_VER) -# define strcasecmp stricmp -# define strncasecmp strnicmp -# define snprintf _snprintf -#else -# define stricmp strcasecmp -# define strnicmp strncasecmp -#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
+ */
+/* $Log: /pjproject-0.3/pjlib/src/pj/compat/string.h $
+ *
+ * 3 9/22/05 10:31a Bennylp
+ * Moving all *.h files to include/.
+ *
+ * 2 9/21/05 1:39p Bennylp
+ * Periodic checkin for backup.
+ *
+ * 1 9/17/05 10:36a Bennylp
+ * Created.
+ *
+ */
+#ifndef __PJ_COMPAT_STRING_H__
+#define __PJ_COMPAT_STRING_H__
+
+/**
+ * @file string.h
+ * @brief Provides string manipulation functions found in ANSI string.h.
+ */
+
+#if defined(PJ_HAS_STRING_H) && PJ_HAS_STRING_H != 0
+# include <string.h>
+#else
+
+ PJ_DECL(int) strcasecmp(const char *s1, const char *s2);
+ PJ_DECL(int) strncasecmp(const char *s1, const char *s2, int len);
+
+#endif
+
+#if defined(_MSC_VER)
+# define strcasecmp stricmp
+# define strncasecmp strnicmp
+# define snprintf _snprintf
+#else
+# define stricmp strcasecmp
+# define strnicmp strncasecmp
+#endif
+
#define pj_native_strcmp strcmp
#define pj_native_strlen strlen
@@ -48,5 +69,5 @@ #define pj_native_strcasecmp strcasecmp
#define pj_native_strncasecmp strncasecmp
- -#endif /* __PJ_COMPAT_STRING_H__ */ +
+#endif /* __PJ_COMPAT_STRING_H__ */
diff --git a/pjlib/include/pj/compat/time.h b/pjlib/include/pj/compat/time.h index 79d0f276..93036047 100644 --- a/pjlib/include/pj/compat/time.h +++ b/pjlib/include/pj/compat/time.h @@ -1,27 +1,48 @@ -/* $Id$ - * - */ -/* $Log: /pjproject-0.3/pjlib/src/pj/compat/time.h $ - * - * 1 9/17/05 10:36a Bennylp - * Created. - * - */ -#ifndef __PJ_COMPAT_TIME_H__ -#define __PJ_COMPAT_TIME_H__ - -/** - * @file time.h - * @brief Provides ftime() and localtime() etc functions. - */ - -#if defined(PJ_HAS_TIME_H) && PJ_HAS_TIME_H != 0 -# include <time.h> -#endif - -#if defined(PJ_HAS_SYS_TIMEB_H) && PJ_HAS_SYS_TIMEB_H != 0 -# include <sys/timeb.h> -#endif - - -#endif /* __PJ_COMPAT_TIME_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
+ */
+/* $Log: /pjproject-0.3/pjlib/src/pj/compat/time.h $
+ *
+ * 1 9/17/05 10:36a Bennylp
+ * Created.
+ *
+ */
+#ifndef __PJ_COMPAT_TIME_H__
+#define __PJ_COMPAT_TIME_H__
+
+/**
+ * @file time.h
+ * @brief Provides ftime() and localtime() etc functions.
+ */
+
+#if defined(PJ_HAS_TIME_H) && PJ_HAS_TIME_H != 0
+# include <time.h>
+#endif
+
+#if defined(PJ_HAS_SYS_TIMEB_H) && PJ_HAS_SYS_TIMEB_H != 0
+# include <sys/timeb.h>
+#endif
+
+
+#endif /* __PJ_COMPAT_TIME_H__ */
diff --git a/pjlib/include/pj/compat/vsprintf.h b/pjlib/include/pj/compat/vsprintf.h index 79be197f..644f365f 100644 --- a/pjlib/include/pj/compat/vsprintf.h +++ b/pjlib/include/pj/compat/vsprintf.h @@ -1,28 +1,49 @@ -/* $Id$ - * - */ -/* $Log: /pjproject-0.3/pjlib/src/pj/compat/vsprintf.h $ - * - * 1 9/17/05 10:36a Bennylp - * Created. - * - */ -#ifndef __PJ_COMPAT_VSPRINTF_H__ -#define __PJ_COMPAT_VSPRINTF_H__ - -/** - * @file vsprintf.h - * @brief Provides vsprintf and vsnprintf function. - */ - -#if defined(PJ_HAS_STDIO_H) && PJ_HAS_STDIO_H != 0 -# include <stdio.h> -#endif - -#if defined(_MSC_VER) -# define vsnprintf _vsnprintf -#endif - -#define pj_vsnprintf vsnprintf - -#endif /* __PJ_COMPAT_VSPRINTF_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
+ */
+/* $Log: /pjproject-0.3/pjlib/src/pj/compat/vsprintf.h $
+ *
+ * 1 9/17/05 10:36a Bennylp
+ * Created.
+ *
+ */
+#ifndef __PJ_COMPAT_VSPRINTF_H__
+#define __PJ_COMPAT_VSPRINTF_H__
+
+/**
+ * @file vsprintf.h
+ * @brief Provides vsprintf and vsnprintf function.
+ */
+
+#if defined(PJ_HAS_STDIO_H) && PJ_HAS_STDIO_H != 0
+# include <stdio.h>
+#endif
+
+#if defined(_MSC_VER)
+# define vsnprintf _vsnprintf
+#endif
+
+#define pj_vsnprintf vsnprintf
+
+#endif /* __PJ_COMPAT_VSPRINTF_H__ */
diff --git a/pjlib/include/pj/config.h b/pjlib/include/pj/config.h index 0465ac9a..cb7cd59c 100644 --- a/pjlib/include/pj/config.h +++ b/pjlib/include/pj/config.h @@ -1,408 +1,429 @@ -/* $Id$ - * - */ - -#ifndef __PJ_CONFIG_H__ -#define __PJ_CONFIG_H__ - -/** - * @file config.h - * @brief PJLIB Main configuration settings. - */ - -/******************************************************************** - * Include compiler specific configuration. - */ -#if defined(_MSC_VER) -# include <pj/compat/cc_msvc.h> -#elif defined(__GNUC__) -# include <pj/compat/cc_gcc.h> -#else -# error "Unknown compiler." -#endif - - -/******************************************************************** - * Include target OS specific configuration. - */ -#if defined(PJ_WIN32) && PJ_WIN32!=0 -# include <pj/compat/os_win32.h> -#elif defined(PJ_LINUX) && PJ_LINUX!=0 -# include <pj/compat/os_linux.h> -#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL!=0 -# include <pj/compat/os_linux_kernel.h> -#elif defined(PJ_PALMOS) && PJ_PALMOS!=0 -# include <pj/compat/os_palmos.h> -#elif defined(PJ_SUNOS) && PJ_SUNOS!=0 -# include <pj/compat/os_sunos.h> -#else -# error "Please specify target os." -#endif - - -/******************************************************************** - * Target machine specific configuration. - */ -#if defined (PJ_M_I386) && PJ_M_I386 != 0 -# include <pj/compat/m_i386.h> -#elif defined (PJ_M_M68K) && PJ_M_M68K != 0 -# include <pj/compat/m_m68k.h> -#elif defined (PJ_M_ALPHA) && PJ_M_ALPHA != 0 -# include <pj/compat/m_alpha.h> -#elif defined (PJ_M_SPARC) && PJ_M_SPARC != 0 -# include <pj/compat/m_sparc.h> -#else -# error "Please specify target machine." -#endif - -/* Include size_t definition. */ -#include <pj/compat/size_t.h> - -/* Include site/user specific configuration to control PJLIB features. - * YOU MUST CREATE THIS FILE YOURSELF!! - */ -#include <pj/config_site.h> - -/******************************************************************** - * PJLIB Features. - */ - -/* Overrides for DOXYGEN */ -#ifdef DOXYGEN -# undef PJ_FUNCTIONS_ARE_INLINED -# undef PJ_HAS_FLOATING_POINT -# undef PJ_LOG_MAX_LEVEL -# undef PJ_LOG_MAX_SIZE -# undef PJ_LOG_USE_STACK_BUFFER -# undef PJ_TERM_HAS_COLOR -# undef PJ_POOL_DEBUG -# undef PJ_HAS_TCP -# undef PJ_MAX_HOSTNAME -# undef PJ_IOQUEUE_MAX_HANDLES -# undef FD_SETSIZE -# undef PJ_HAS_SEMAPHORE -# undef PJ_HAS_EVENT_OBJ -# undef PJ_ENABLE_EXTRA_CHECK -#endif - -/** - * @defgroup pj_config Build Configuration - * @ingroup PJ - * @{ - * - * This section contains macros that can set during PJLIB build process - * to controll various aspects of the library. - * - * <b>Note</b>: the values in this page does NOT necessarily reflect to the - * macro values during the build process. - */ - -/** - * If this macro is set to 1, it will enable some debugging checking - * in the library. - * - * Default: equal to (NOT NDEBUG). - */ -#ifndef PJ_DEBUG -# ifndef NDEBUG -# define PJ_DEBUG 1 -# else -# define PJ_DEBUG 0 -# endif -#endif - -/** - * Expand functions in *_i.h header files as inline. - * - * Default: 0. - */ -#ifndef PJ_FUNCTIONS_ARE_INLINED -# define PJ_FUNCTIONS_ARE_INLINED 0 -#endif - -/** - * Use floating point computations in the library. - * - * Default: 1. - */ -#ifndef PJ_HAS_FLOATING_POINT -# define PJ_HAS_FLOATING_POINT 1 -#endif - -/** - * Declare maximum logging level/verbosity. Lower number indicates higher - * importance, with the highest importance has level zero. The least - * important level is five in this implementation, but this can be extended - * by supplying the appropriate implementation. - * - * The level conventions: - * - 0: fatal error - * - 1: error - * - 2: warning - * - 3: info - * - 4: debug - * - 5: trace - * - 6: more detailed trace - * - * Default: 4 - */ -#ifndef PJ_LOG_MAX_LEVEL -# define PJ_LOG_MAX_LEVEL 5 -#endif - -/** - * Maximum message size that can be sent to output device for each call - * to PJ_LOG(). If the message size is longer than this value, it will be cut. - * This may affect the stack usage, depending whether PJ_LOG_USE_STACK_BUFFER - * flag is set. - * - * Default: 800 - */ -#ifndef PJ_LOG_MAX_SIZE -# define PJ_LOG_MAX_SIZE 800 -#endif - -/** - * Log buffer. - * Does the log get the buffer from the stack? (default is yes). - * If the value is set to NO, then the buffer will be taken from static - * buffer, which in this case will make the log function non-reentrant. - * - * Default: 1 - */ -#ifndef PJ_LOG_USE_STACK_BUFFER -# define PJ_LOG_USE_STACK_BUFFER 1 -#endif - - -/** - * Colorfull terminal (for logging etc). - * - * Default: 1 - */ -#ifndef PJ_TERM_HAS_COLOR -# define PJ_TERM_HAS_COLOR 1 -#endif - -/** - * Pool debugging. - * - * Default: 0 - */ -#ifndef PJ_POOL_DEBUG -# define PJ_POOL_DEBUG 0 -#endif - -/** - * \def PJ_HAS_TCP - * Support TCP in the library. - * Disabling TCP will reduce the footprint slightly (about 6KB). - * - * Default: 1 - */ -#ifndef PJ_HAS_TCP -# define PJ_HAS_TCP 1 -#endif - -/** - * Maximum hostname length. - * Libraries sometimes needs to make copy of an address to stack buffer; - * the value here affects the stack usage. - * - * Default: 128 - */ -#ifndef PJ_MAX_HOSTNAME -# define PJ_MAX_HOSTNAME (128) -#endif - -/** - * Constants for declaring the maximum handles that can be supported by - * a single IOQ framework. This constant might not be relevant to the - * underlying I/O queue impelementation, but still, developers should be - * aware of this constant, to make sure that the program will not break when - * the underlying implementation changes. - * - * For implementation based on select(), the value here will be used as the - * maximum number of socket handles passed to select() (i.e. FD_SETSIZE will - * be set to this value). - * - * Default: 256 - */ -#ifndef PJ_IOQUEUE_MAX_HANDLES -# define PJ_IOQUEUE_MAX_HANDLES (256) -#endif - -/** - * Overrides FD_SETSIZE so it is consistent throughout the library. - * OS specific configuration header (compat/os_*) might have declared - * FD_SETSIZE, thus we only set if it hasn't been declared. - * - * Default: #PJ_IOQUEUE_MAX_HANDLES - */ -#ifndef FD_SETSIZE -# define FD_SETSIZE PJ_IOQUEUE_MAX_HANDLES -#endif - -/** - * Has semaphore functionality? - * - * Default: 1 - */ -#ifndef PJ_HAS_SEMAPHORE -# define PJ_HAS_SEMAPHORE 1 -#endif - - -/** - * Event object (for synchronization, e.g. in Win32) - * - * Default: 1 - */ -#ifndef PJ_HAS_EVENT_OBJ -# define PJ_HAS_EVENT_OBJ 1 -#endif - - -/** - * Enable library's extra check. - * If this macro is enabled, #PJ_ASSERT_RETURN macro will expand to - * run-time checking. If this macro is disabled, #PJ_ASSERT_RETURN - * will simply evaluate to #pj_assert(). - * - * You can disable this macro to reduce size, at the risk of crashes - * if invalid value (e.g. NULL) is passed to the library. - * - * Default: 1 - */ -#ifndef PJ_ENABLE_EXTRA_CHECK -# define PJ_ENABLE_EXTRA_CHECK 1 -#endif - - -/** - * Enable name registration for exceptions with #pj_exception_id_alloc(). - * If this feature is enabled, then the library will keep track of - * names associated with each exception ID requested by application via - * #pj_exception_id_alloc(). - * - * Disabling this macro will reduce the code and .bss size by a tad bit. - * See also #PJ_MAX_EXCEPTION_ID. - * - * Default: 1 - */ -#ifndef PJ_HAS_EXCEPTION_NAMES -# define PJ_HAS_EXCEPTION_NAMES 1 -#endif - -/** - * Maximum number of unique exception IDs that can be requested - * with #pj_exception_id_alloc(). For each entry, a small record will - * be allocated in the .bss segment. - * - * Default: 16 - */ -#ifndef PJ_MAX_EXCEPTION_ID -# define PJ_MAX_EXCEPTION_ID 16 -#endif - -/** @} */ - -/******************************************************************** - * General macros. - */ - -/** - * @def PJ_INLINE(type) - * @param type The return type of the function. - * Expand the function as inline. - */ -#define PJ_INLINE(type) PJ_INLINE_SPECIFIER type - -/** - * @def PJ_DECL(type) - * @param type The return type of the function. - * Declare a function. - */ -/** - * @def PJ_DECL_NO_RETURN(type) - * @param type The return type of the function. - * Declare a function that will not return. - */ -/** - * @def PJ_BEGIN_DECL - * Mark beginning of declaration section in a header file. - */ -/** - * @def PJ_END_DECL - * Mark end of declaration section in a header file. - */ -#ifdef __cplusplus -# define PJ_DECL(type) type -# define PJ_DECL_NO_RETURN(type) type PJ_NORETURN -# define PJ_BEGIN_DECL extern "C" { -# define PJ_END_DECL } -#else -# define PJ_DECL(type) extern type -# define PJ_DECL_NO_RETURN(type) PJ_NORETURN type -# define PJ_BEGIN_DECL -# define PJ_END_DECL -#endif - -/** - * @def PJ_DEF(type) - * @param type The return type of the function. - * Define a function. - */ -#define PJ_DEF(type) type - -/** - * @def PJ_EXPORT_SYMBOL(sym) - * @param sym The symbol to export. - * Export the specified symbol in compilation type that requires export - * (e.g. Linux kernel). - */ -#ifdef __PJ_EXPORT_SYMBOL -# define PJ_EXPORT_SYMBOL(sym) __PJ_EXPORT_SYMBOL(sym) -#else -# define PJ_EXPORT_SYMBOL(sym) -#endif - -/** - * @def PJ_IDECL(type) - * @param type The function's return type. - * Declare a function that may be expanded as inline. - */ -/** - * @def PJ_IDEF(type) - * @param type The function's return type. - * Define a function that may be expanded as inline. - */ - -#if PJ_FUNCTIONS_ARE_INLINED -# define PJ_IDECL(type) PJ_INLINE(type) -# define PJ_IDEF(type) PJ_INLINE(type) -#else -# define PJ_IDECL(type) PJ_DECL(type) -# define PJ_IDEF(type) PJ_DEF(type) -#endif - -/** - * @def PJ_UNUSED_ARG(arg) - * @param arg The argument name. - * PJ_UNUSED_ARG prevents warning about unused argument in a function. - */ -#define PJ_UNUSED_ARG(arg) (void)arg - -/** - * @def PJ_TODO(id) - * @param id Any identifier that will be printed as TODO message. - * PJ_TODO macro will display TODO message as warning during compilation. - * Example: PJ_TODO(CLEAN_UP_ERROR); - */ -#ifndef PJ_TODO -# define PJ_TODO(id) TODO___##id: -#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
+ */
+
+#ifndef __PJ_CONFIG_H__
+#define __PJ_CONFIG_H__
+
+/**
+ * @file config.h
+ * @brief PJLIB Main configuration settings.
+ */
+
+/********************************************************************
+ * Include compiler specific configuration.
+ */
+#if defined(_MSC_VER)
+# include <pj/compat/cc_msvc.h>
+#elif defined(__GNUC__)
+# include <pj/compat/cc_gcc.h>
+#else
+# error "Unknown compiler."
+#endif
+
+
+/********************************************************************
+ * Include target OS specific configuration.
+ */
+#if defined(PJ_WIN32) && PJ_WIN32!=0
+# include <pj/compat/os_win32.h>
+#elif defined(PJ_LINUX) && PJ_LINUX!=0
+# include <pj/compat/os_linux.h>
+#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL!=0
+# include <pj/compat/os_linux_kernel.h>
+#elif defined(PJ_PALMOS) && PJ_PALMOS!=0
+# include <pj/compat/os_palmos.h>
+#elif defined(PJ_SUNOS) && PJ_SUNOS!=0
+# include <pj/compat/os_sunos.h>
+#else
+# error "Please specify target os."
+#endif
+
+
+/********************************************************************
+ * Target machine specific configuration.
+ */
+#if defined (PJ_M_I386) && PJ_M_I386 != 0
+# include <pj/compat/m_i386.h>
+#elif defined (PJ_M_M68K) && PJ_M_M68K != 0
+# include <pj/compat/m_m68k.h>
+#elif defined (PJ_M_ALPHA) && PJ_M_ALPHA != 0
+# include <pj/compat/m_alpha.h>
+#elif defined (PJ_M_SPARC) && PJ_M_SPARC != 0
+# include <pj/compat/m_sparc.h>
+#else
+# error "Please specify target machine."
+#endif
+
+/* Include size_t definition. */
+#include <pj/compat/size_t.h>
+
+/* Include site/user specific configuration to control PJLIB features.
+ * YOU MUST CREATE THIS FILE YOURSELF!!
+ */
+#include <pj/config_site.h>
+
+/********************************************************************
+ * PJLIB Features.
+ */
+
+/* Overrides for DOXYGEN */
+#ifdef DOXYGEN
+# undef PJ_FUNCTIONS_ARE_INLINED
+# undef PJ_HAS_FLOATING_POINT
+# undef PJ_LOG_MAX_LEVEL
+# undef PJ_LOG_MAX_SIZE
+# undef PJ_LOG_USE_STACK_BUFFER
+# undef PJ_TERM_HAS_COLOR
+# undef PJ_POOL_DEBUG
+# undef PJ_HAS_TCP
+# undef PJ_MAX_HOSTNAME
+# undef PJ_IOQUEUE_MAX_HANDLES
+# undef FD_SETSIZE
+# undef PJ_HAS_SEMAPHORE
+# undef PJ_HAS_EVENT_OBJ
+# undef PJ_ENABLE_EXTRA_CHECK
+#endif
+
+/**
+ * @defgroup pj_config Build Configuration
+ * @ingroup PJ
+ * @{
+ *
+ * This section contains macros that can set during PJLIB build process
+ * to controll various aspects of the library.
+ *
+ * <b>Note</b>: the values in this page does NOT necessarily reflect to the
+ * macro values during the build process.
+ */
+
+/**
+ * If this macro is set to 1, it will enable some debugging checking
+ * in the library.
+ *
+ * Default: equal to (NOT NDEBUG).
+ */
+#ifndef PJ_DEBUG
+# ifndef NDEBUG
+# define PJ_DEBUG 1
+# else
+# define PJ_DEBUG 0
+# endif
+#endif
+
+/**
+ * Expand functions in *_i.h header files as inline.
+ *
+ * Default: 0.
+ */
+#ifndef PJ_FUNCTIONS_ARE_INLINED
+# define PJ_FUNCTIONS_ARE_INLINED 0
+#endif
+
+/**
+ * Use floating point computations in the library.
+ *
+ * Default: 1.
+ */
+#ifndef PJ_HAS_FLOATING_POINT
+# define PJ_HAS_FLOATING_POINT 1
+#endif
+
+/**
+ * Declare maximum logging level/verbosity. Lower number indicates higher
+ * importance, with the highest importance has level zero. The least
+ * important level is five in this implementation, but this can be extended
+ * by supplying the appropriate implementation.
+ *
+ * The level conventions:
+ * - 0: fatal error
+ * - 1: error
+ * - 2: warning
+ * - 3: info
+ * - 4: debug
+ * - 5: trace
+ * - 6: more detailed trace
+ *
+ * Default: 4
+ */
+#ifndef PJ_LOG_MAX_LEVEL
+# define PJ_LOG_MAX_LEVEL 5
+#endif
+
+/**
+ * Maximum message size that can be sent to output device for each call
+ * to PJ_LOG(). If the message size is longer than this value, it will be cut.
+ * This may affect the stack usage, depending whether PJ_LOG_USE_STACK_BUFFER
+ * flag is set.
+ *
+ * Default: 800
+ */
+#ifndef PJ_LOG_MAX_SIZE
+# define PJ_LOG_MAX_SIZE 800
+#endif
+
+/**
+ * Log buffer.
+ * Does the log get the buffer from the stack? (default is yes).
+ * If the value is set to NO, then the buffer will be taken from static
+ * buffer, which in this case will make the log function non-reentrant.
+ *
+ * Default: 1
+ */
+#ifndef PJ_LOG_USE_STACK_BUFFER
+# define PJ_LOG_USE_STACK_BUFFER 1
+#endif
+
+
+/**
+ * Colorfull terminal (for logging etc).
+ *
+ * Default: 1
+ */
+#ifndef PJ_TERM_HAS_COLOR
+# define PJ_TERM_HAS_COLOR 1
+#endif
+
+/**
+ * Pool debugging.
+ *
+ * Default: 0
+ */
+#ifndef PJ_POOL_DEBUG
+# define PJ_POOL_DEBUG 0
+#endif
+
+/**
+ * \def PJ_HAS_TCP
+ * Support TCP in the library.
+ * Disabling TCP will reduce the footprint slightly (about 6KB).
+ *
+ * Default: 1
+ */
+#ifndef PJ_HAS_TCP
+# define PJ_HAS_TCP 1
+#endif
+
+/**
+ * Maximum hostname length.
+ * Libraries sometimes needs to make copy of an address to stack buffer;
+ * the value here affects the stack usage.
+ *
+ * Default: 128
+ */
+#ifndef PJ_MAX_HOSTNAME
+# define PJ_MAX_HOSTNAME (128)
+#endif
+
+/**
+ * Constants for declaring the maximum handles that can be supported by
+ * a single IOQ framework. This constant might not be relevant to the
+ * underlying I/O queue impelementation, but still, developers should be
+ * aware of this constant, to make sure that the program will not break when
+ * the underlying implementation changes.
+ *
+ * For implementation based on select(), the value here will be used as the
+ * maximum number of socket handles passed to select() (i.e. FD_SETSIZE will
+ * be set to this value).
+ *
+ * Default: 256
+ */
+#ifndef PJ_IOQUEUE_MAX_HANDLES
+# define PJ_IOQUEUE_MAX_HANDLES (256)
+#endif
+
+/**
+ * Overrides FD_SETSIZE so it is consistent throughout the library.
+ * OS specific configuration header (compat/os_*) might have declared
+ * FD_SETSIZE, thus we only set if it hasn't been declared.
+ *
+ * Default: #PJ_IOQUEUE_MAX_HANDLES
+ */
+#ifndef FD_SETSIZE
+# define FD_SETSIZE PJ_IOQUEUE_MAX_HANDLES
+#endif
+
+/**
+ * Has semaphore functionality?
+ *
+ * Default: 1
+ */
+#ifndef PJ_HAS_SEMAPHORE
+# define PJ_HAS_SEMAPHORE 1
+#endif
+
+
+/**
+ * Event object (for synchronization, e.g. in Win32)
+ *
+ * Default: 1
+ */
+#ifndef PJ_HAS_EVENT_OBJ
+# define PJ_HAS_EVENT_OBJ 1
+#endif
+
+
+/**
+ * Enable library's extra check.
+ * If this macro is enabled, #PJ_ASSERT_RETURN macro will expand to
+ * run-time checking. If this macro is disabled, #PJ_ASSERT_RETURN
+ * will simply evaluate to #pj_assert().
+ *
+ * You can disable this macro to reduce size, at the risk of crashes
+ * if invalid value (e.g. NULL) is passed to the library.
+ *
+ * Default: 1
+ */
+#ifndef PJ_ENABLE_EXTRA_CHECK
+# define PJ_ENABLE_EXTRA_CHECK 1
+#endif
+
+
+/**
+ * Enable name registration for exceptions with #pj_exception_id_alloc().
+ * If this feature is enabled, then the library will keep track of
+ * names associated with each exception ID requested by application via
+ * #pj_exception_id_alloc().
+ *
+ * Disabling this macro will reduce the code and .bss size by a tad bit.
+ * See also #PJ_MAX_EXCEPTION_ID.
+ *
+ * Default: 1
+ */
+#ifndef PJ_HAS_EXCEPTION_NAMES
+# define PJ_HAS_EXCEPTION_NAMES 1
+#endif
+
+/**
+ * Maximum number of unique exception IDs that can be requested
+ * with #pj_exception_id_alloc(). For each entry, a small record will
+ * be allocated in the .bss segment.
+ *
+ * Default: 16
+ */
+#ifndef PJ_MAX_EXCEPTION_ID
+# define PJ_MAX_EXCEPTION_ID 16
+#endif
+
+/** @} */
+
+/********************************************************************
+ * General macros.
+ */
+
+/**
+ * @def PJ_INLINE(type)
+ * @param type The return type of the function.
+ * Expand the function as inline.
+ */
+#define PJ_INLINE(type) PJ_INLINE_SPECIFIER type
+
+/**
+ * @def PJ_DECL(type)
+ * @param type The return type of the function.
+ * Declare a function.
+ */
+/**
+ * @def PJ_DECL_NO_RETURN(type)
+ * @param type The return type of the function.
+ * Declare a function that will not return.
+ */
+/**
+ * @def PJ_BEGIN_DECL
+ * Mark beginning of declaration section in a header file.
+ */
+/**
+ * @def PJ_END_DECL
+ * Mark end of declaration section in a header file.
+ */
+#ifdef __cplusplus
+# define PJ_DECL(type) type
+# define PJ_DECL_NO_RETURN(type) type PJ_NORETURN
+# define PJ_BEGIN_DECL extern "C" {
+# define PJ_END_DECL }
+#else
+# define PJ_DECL(type) extern type
+# define PJ_DECL_NO_RETURN(type) PJ_NORETURN type
+# define PJ_BEGIN_DECL
+# define PJ_END_DECL
+#endif
+
+/**
+ * @def PJ_DEF(type)
+ * @param type The return type of the function.
+ * Define a function.
+ */
+#define PJ_DEF(type) type
+
+/**
+ * @def PJ_EXPORT_SYMBOL(sym)
+ * @param sym The symbol to export.
+ * Export the specified symbol in compilation type that requires export
+ * (e.g. Linux kernel).
+ */
+#ifdef __PJ_EXPORT_SYMBOL
+# define PJ_EXPORT_SYMBOL(sym) __PJ_EXPORT_SYMBOL(sym)
+#else
+# define PJ_EXPORT_SYMBOL(sym)
+#endif
+
+/**
+ * @def PJ_IDECL(type)
+ * @param type The function's return type.
+ * Declare a function that may be expanded as inline.
+ */
+/**
+ * @def PJ_IDEF(type)
+ * @param type The function's return type.
+ * Define a function that may be expanded as inline.
+ */
+
+#if PJ_FUNCTIONS_ARE_INLINED
+# define PJ_IDECL(type) PJ_INLINE(type)
+# define PJ_IDEF(type) PJ_INLINE(type)
+#else
+# define PJ_IDECL(type) PJ_DECL(type)
+# define PJ_IDEF(type) PJ_DEF(type)
+#endif
+
+/**
+ * @def PJ_UNUSED_ARG(arg)
+ * @param arg The argument name.
+ * PJ_UNUSED_ARG prevents warning about unused argument in a function.
+ */
+#define PJ_UNUSED_ARG(arg) (void)arg
+
+/**
+ * @def PJ_TODO(id)
+ * @param id Any identifier that will be printed as TODO message.
+ * PJ_TODO macro will display TODO message as warning during compilation.
+ * Example: PJ_TODO(CLEAN_UP_ERROR);
+ */
+#ifndef PJ_TODO
+# define PJ_TODO(id) TODO___##id:
+#endif
+
/**
* Function attributes to inform that the function may throw exception.
*
@@ -410,42 +431,42 @@ */
#define __pj_throw__(x)
- -/******************************************************************** - * Sanity Checks - */ -#ifndef PJ_HAS_HIGH_RES_TIMER -# error "PJ_HAS_HIGH_RES_TIMER is not defined!" -#endif - -#if !defined(PJ_HAS_PENTIUM) -# error "PJ_HAS_PENTIUM is not defined!" -#endif - -#if !defined(PJ_IS_LITTLE_ENDIAN) -# error "PJ_IS_LITTLE_ENDIAN is not defined!" -#endif - -#if !defined(PJ_IS_BIG_ENDIAN) -# error "PJ_IS_BIG_ENDIAN is not defined!" -#endif - - - -PJ_BEGIN_DECL - -/** - * PJLIB version string. - */ -extern const char *PJ_VERSION; - -/** - * Dump configuration to log with verbosity equal to info(3). - */ -PJ_DECL(void) pj_dump_config(void); - -PJ_END_DECL - - -#endif /* __PJ_CONFIG_H__ */ - +
+/********************************************************************
+ * Sanity Checks
+ */
+#ifndef PJ_HAS_HIGH_RES_TIMER
+# error "PJ_HAS_HIGH_RES_TIMER is not defined!"
+#endif
+
+#if !defined(PJ_HAS_PENTIUM)
+# error "PJ_HAS_PENTIUM is not defined!"
+#endif
+
+#if !defined(PJ_IS_LITTLE_ENDIAN)
+# error "PJ_IS_LITTLE_ENDIAN is not defined!"
+#endif
+
+#if !defined(PJ_IS_BIG_ENDIAN)
+# error "PJ_IS_BIG_ENDIAN is not defined!"
+#endif
+
+
+
+PJ_BEGIN_DECL
+
+/**
+ * PJLIB version string.
+ */
+extern const char *PJ_VERSION;
+
+/**
+ * Dump configuration to log with verbosity equal to info(3).
+ */
+PJ_DECL(void) pj_dump_config(void);
+
+PJ_END_DECL
+
+
+#endif /* __PJ_CONFIG_H__ */
+
diff --git a/pjlib/include/pj/ctype.h b/pjlib/include/pj/ctype.h index 4307fbba..39b45f88 100644 --- a/pjlib/include/pj/ctype.h +++ b/pjlib/include/pj/ctype.h @@ -1,121 +1,142 @@ -/* $Id$ - * - */ -#ifndef __PJ_CTYPE_H__ -#define __PJ_CTYPE_H__ - -/** - * @file ctype.h - * @brief C type helper macros. - */ - -#include <pj/compat/ctype.h> - -/** - * @defgroup pj_ctype ctype - Character Type - * @ingroup PJ_MISC - * @{ - * - * This module contains several inline functions/macros for testing or - * manipulating character types. It is provided in PJLIB because PJLIB - * must not depend to LIBC. - */ - -/** - * Returns a non-zero value if either isalpha or isdigit is true for c. - * @param c The integer character to test. - * @return Non-zero value if either isalpha or isdigit is true for c. - */ -PJ_INLINE(int) pj_isalnum(int c) { return isalnum(c); } - -/** - * Returns a non-zero value if c is a particular representation of an - * alphabetic character. - * @param c The integer character to test. - * @return Non-zero value if c is a particular representation of an - * alphabetic character. - */ -PJ_INLINE(int) pj_isalpha(int c) { return isalpha(c); } - -/** - * Returns a non-zero value if c is a particular representation of an - * ASCII character. - * @param c The integer character to test. - * @return Non-zero value if c is a particular representation of - * an ASCII character. - */ -PJ_INLINE(int) pj_isascii(int c) { return isascii(c); } - -/** - * Returns a non-zero value if c is a particular representation of - * a decimal-digit character. - * @param c The integer character to test. - * @return Non-zero value if c is a particular representation of - * a decimal-digit character. - */ -PJ_INLINE(int) pj_isdigit(int c) { return isdigit(c); } - -/** - * Returns a non-zero value if c is a particular representation of - * a space character (0x09 - 0x0D or 0x20). - * @param c The integer character to test. - * @return Non-zero value if c is a particular representation of - * a space character (0x09 - 0x0D or 0x20). - */ -PJ_INLINE(int) pj_isspace(int c) { return isspace(c); } - -/** - * Returns a non-zero value if c is a particular representation of - * a lowercase character. - * @param c The integer character to test. - * @return Non-zero value if c is a particular representation of - * a lowercase character. - */ -PJ_INLINE(int) pj_islower(int c) { return islower(c); } - - -/** - * Returns a non-zero value if c is a particular representation of - * a uppercase character. - * @param c The integer character to test. - * @return Non-zero value if c is a particular representation of - * a uppercase character. - */ -PJ_INLINE(int) pj_isupper(int c) { return isupper(c); } - -/** - * Returns a non-zero value if c is a particular representation of - * an hexadecimal digit character. - * @param c The integer character to test. - * @return Non-zero value if c is a particular representation of - * an hexadecimal digit character. - */ -PJ_INLINE(int) pj_isxdigit(int c){ return isxdigit(c); } - -/** - * Returns a non-zero value if c is a either a space (' ') or horizontal - * tab ('\\t') character. - * @param c The integer character to test. - * @return Non-zero value if c is a either a space (' ') or horizontal - * tab ('\\t') character. - */ -PJ_INLINE(int) pj_isblank(int c) { return isblank(c); } - -/** - * Converts character to lowercase. - * @param c The integer character to convert. - * @return Lowercase character of c. - */ -PJ_INLINE(int) pj_tolower(int c) { return tolower(c); } - -/** - * Converts character to uppercase. - * @param c The integer character to convert. - * @return Uppercase character of c. - */ -PJ_INLINE(int) pj_toupper(int c) { return toupper(c); } - -/** @} */ - -#endif /* __PJ_CTYPE_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 __PJ_CTYPE_H__
+#define __PJ_CTYPE_H__
+
+/**
+ * @file ctype.h
+ * @brief C type helper macros.
+ */
+
+#include <pj/compat/ctype.h>
+
+/**
+ * @defgroup pj_ctype ctype - Character Type
+ * @ingroup PJ_MISC
+ * @{
+ *
+ * This module contains several inline functions/macros for testing or
+ * manipulating character types. It is provided in PJLIB because PJLIB
+ * must not depend to LIBC.
+ */
+
+/**
+ * Returns a non-zero value if either isalpha or isdigit is true for c.
+ * @param c The integer character to test.
+ * @return Non-zero value if either isalpha or isdigit is true for c.
+ */
+PJ_INLINE(int) pj_isalnum(int c) { return isalnum(c); }
+
+/**
+ * Returns a non-zero value if c is a particular representation of an
+ * alphabetic character.
+ * @param c The integer character to test.
+ * @return Non-zero value if c is a particular representation of an
+ * alphabetic character.
+ */
+PJ_INLINE(int) pj_isalpha(int c) { return isalpha(c); }
+
+/**
+ * Returns a non-zero value if c is a particular representation of an
+ * ASCII character.
+ * @param c The integer character to test.
+ * @return Non-zero value if c is a particular representation of
+ * an ASCII character.
+ */
+PJ_INLINE(int) pj_isascii(int c) { return isascii(c); }
+
+/**
+ * Returns a non-zero value if c is a particular representation of
+ * a decimal-digit character.
+ * @param c The integer character to test.
+ * @return Non-zero value if c is a particular representation of
+ * a decimal-digit character.
+ */
+PJ_INLINE(int) pj_isdigit(int c) { return isdigit(c); }
+
+/**
+ * Returns a non-zero value if c is a particular representation of
+ * a space character (0x09 - 0x0D or 0x20).
+ * @param c The integer character to test.
+ * @return Non-zero value if c is a particular representation of
+ * a space character (0x09 - 0x0D or 0x20).
+ */
+PJ_INLINE(int) pj_isspace(int c) { return isspace(c); }
+
+/**
+ * Returns a non-zero value if c is a particular representation of
+ * a lowercase character.
+ * @param c The integer character to test.
+ * @return Non-zero value if c is a particular representation of
+ * a lowercase character.
+ */
+PJ_INLINE(int) pj_islower(int c) { return islower(c); }
+
+
+/**
+ * Returns a non-zero value if c is a particular representation of
+ * a uppercase character.
+ * @param c The integer character to test.
+ * @return Non-zero value if c is a particular representation of
+ * a uppercase character.
+ */
+PJ_INLINE(int) pj_isupper(int c) { return isupper(c); }
+
+/**
+ * Returns a non-zero value if c is a particular representation of
+ * an hexadecimal digit character.
+ * @param c The integer character to test.
+ * @return Non-zero value if c is a particular representation of
+ * an hexadecimal digit character.
+ */
+PJ_INLINE(int) pj_isxdigit(int c){ return isxdigit(c); }
+
+/**
+ * Returns a non-zero value if c is a either a space (' ') or horizontal
+ * tab ('\\t') character.
+ * @param c The integer character to test.
+ * @return Non-zero value if c is a either a space (' ') or horizontal
+ * tab ('\\t') character.
+ */
+PJ_INLINE(int) pj_isblank(int c) { return isblank(c); }
+
+/**
+ * Converts character to lowercase.
+ * @param c The integer character to convert.
+ * @return Lowercase character of c.
+ */
+PJ_INLINE(int) pj_tolower(int c) { return tolower(c); }
+
+/**
+ * Converts character to uppercase.
+ * @param c The integer character to convert.
+ * @return Uppercase character of c.
+ */
+PJ_INLINE(int) pj_toupper(int c) { return toupper(c); }
+
+/** @} */
+
+#endif /* __PJ_CTYPE_H__ */
+
diff --git a/pjlib/include/pj/doxygen.h b/pjlib/include/pj/doxygen.h index f7b2d14b..891a1921 100644 --- a/pjlib/include/pj/doxygen.h +++ b/pjlib/include/pj/doxygen.h @@ -1,398 +1,419 @@ -/* $Id$ - * - */ -#ifndef __PJ_DOXYGEN_H__ -#define __PJ_DOXYGEN_H__ - -/** - * @file doxygen.h - * @brief Doxygen's mainpage. - */ - -/*////////////////////////////////////////////////////////////////////////// */ -/* - INTRODUCTION PAGE - */ - -/** - * @mainpage Welcome to PJLIB! - * - * @section intro_sec What is PJLIB - * - * PJLIB is a small foundation library written in C for making scalable - * applications. Because of its small footprint, it can be used in embedded - * applications (we hope so!), but yet the library is also aimed for - * facilitating high performance protocol stacks. - * - * PJLIB is released under LGPL terms. - * - * @section download_sec Download - * - * PJLIB and all documentation can be downloaded from - * http://www.pjproject.net. - * - * - * @section how_to_use_sec About This Documentation - * - * This document is generated directly from PJLIB source file using - * \a doxygen (http://www.doxygen.org). Doxygen is a great (and free!) - * tools for generating such documentation. - * - * @subsection doc_ver_subsec Version - * - * This document corresponds to PJLIB version 0.3-pre2. - * - * - * @subsection find_samples_subsec How to Read This Document - * - * This documentation is laid out more to be a reference guide instead - * of tutorial, therefore first time users may find it difficult to - * grasp PJLIB by reading this document alone. - * - * However, we've tried our best to make this document easy to follow. - * For first time users, we would suggest that you follow these steps - * when reading this documentation: - * - * - continue reading this introduction chapter. At the end of this - * chapter, you'll find section called \ref pjlib_fundamentals_sec - * which should guide you to understand basic things about PJLIB. - * - * - find information about specific features that you want to use - * in PJLIB. Use the <b>Module Index</b> to find out about all - * features in PJLIB (if you're browsing the HTML documentation, - * click on the \a Module link on top of the page, or if you're - * reading the PDF documentation, click on \a Module \a Documentation - * on the navigation pane on the left). - * - * @subsection doc_organize_sec How To's - * - * Please find below links to specific tasks that you probably - * want to do: - * - * - <b>How to Build PJLIB</b> - *\n - * Please refer to \ref pjlib_build_sys_pg page for more information. - * - * - <b>How to Use PJLIB in My Application</b> - *\n - * Please refer to \ref configure_app_sec for more information. - * - * - <b>How to Port PJLIB</b> - *\n - * Please refer to \ref porting_pjlib_pg page. - * - * - <b>Where to Read Samples Documentation</b> - *\n - * Most of the modules provide link to the corresponding sample file. - * Alternatively, to get the list of all examples, you can click on - * <b>Related Pages</b> on the top of HTML document or on - * <b>PJLIB Page Documentation</b> on navigation pane of your PDF reader. - *
- * - <b>How to Submit Code to PJLIB Project</b> - *\n +/* $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 __PJ_DOXYGEN_H__
+#define __PJ_DOXYGEN_H__
+
+/**
+ * @file doxygen.h
+ * @brief Doxygen's mainpage.
+ */
+
+/*////////////////////////////////////////////////////////////////////////// */
+/*
+ INTRODUCTION PAGE
+ */
+
+/**
+ * @mainpage Welcome to PJLIB!
+ *
+ * @section intro_sec What is PJLIB
+ *
+ * PJLIB is a small foundation library written in C for making scalable
+ * applications. Because of its small footprint, it can be used in embedded
+ * applications (we hope so!), but yet the library is also aimed for
+ * facilitating high performance protocol stacks.
+ *
+ * PJLIB is released under LGPL terms.
+ *
+ * @section download_sec Download
+ *
+ * PJLIB and all documentation can be downloaded from
+ * http://www.pjproject.net.
+ *
+ *
+ * @section how_to_use_sec About This Documentation
+ *
+ * This document is generated directly from PJLIB source file using
+ * \a doxygen (http://www.doxygen.org). Doxygen is a great (and free!)
+ * tools for generating such documentation.
+ *
+ * @subsection doc_ver_subsec Version
+ *
+ * This document corresponds to PJLIB version 0.3-pre2.
+ *
+ *
+ * @subsection find_samples_subsec How to Read This Document
+ *
+ * This documentation is laid out more to be a reference guide instead
+ * of tutorial, therefore first time users may find it difficult to
+ * grasp PJLIB by reading this document alone.
+ *
+ * However, we've tried our best to make this document easy to follow.
+ * For first time users, we would suggest that you follow these steps
+ * when reading this documentation:
+ *
+ * - continue reading this introduction chapter. At the end of this
+ * chapter, you'll find section called \ref pjlib_fundamentals_sec
+ * which should guide you to understand basic things about PJLIB.
+ *
+ * - find information about specific features that you want to use
+ * in PJLIB. Use the <b>Module Index</b> to find out about all
+ * features in PJLIB (if you're browsing the HTML documentation,
+ * click on the \a Module link on top of the page, or if you're
+ * reading the PDF documentation, click on \a Module \a Documentation
+ * on the navigation pane on the left).
+ *
+ * @subsection doc_organize_sec How To's
+ *
+ * Please find below links to specific tasks that you probably
+ * want to do:
+ *
+ * - <b>How to Build PJLIB</b>
+ *\n
+ * Please refer to \ref pjlib_build_sys_pg page for more information.
+ *
+ * - <b>How to Use PJLIB in My Application</b>
+ *\n
+ * Please refer to \ref configure_app_sec for more information.
+ *
+ * - <b>How to Port PJLIB</b>
+ *\n
+ * Please refer to \ref porting_pjlib_pg page.
+ *
+ * - <b>Where to Read Samples Documentation</b>
+ *\n
+ * Most of the modules provide link to the corresponding sample file.
+ * Alternatively, to get the list of all examples, you can click on
+ * <b>Related Pages</b> on the top of HTML document or on
+ * <b>PJLIB Page Documentation</b> on navigation pane of your PDF reader.
+ *
+ * - <b>How to Submit Code to PJLIB Project</b>
+ *\n
* Please read \ref pjlib_coding_convention_page before submitting
- * your code. Send your code as patch against current Subversion tree + * your code. Send your code as patch against current Subversion tree
* to the appropriate mailing list.
- * - * - * @section features_sec Features - * - * @subsection open_source_feat It's Open Source! - * - * PJLIB is currently released on LGPL license. We may release PJLIB under - * additional schemes in the future (such as GPL or MPL) to incorporate - * linking with specific application, however, one thing for sure is - * we will NEVER be able to make PJLIB a proprietary software. - * - * @subsection extreme_portable_feat Extreme Portability - * - * PJLIB is designed to be extremely portable. It can run on any kind - * of processors (16-bit, 32-bit, or 64-bit, big or little endian, single - * or multi-processors) and operating systems. Floating point or no - * floating point. Multi-threading or not. - * It can even run in environment where no ANSI LIBC is available. - * - * Currently PJLIB is being ported to: - * - x86, Win32 (Win95/98/ME, NT/2000/XP/2003, mingw). - * - x86, Linux (user mode and as <b>kernel module</b>(!)). - * - alpha, Linux - * And coming up: - * - x86, eCos - * - ultra-II, Solaris. - * - powerpc, MacOS - * - m68k, PalmOS. - * - arm, PocketPC - * - * No other library is known to have this extreme portability! - * - * @subsection small_size_feat Small in Size - * - * One of the primary objectives is to have library that is small in size for - * typical embedded applications. As a rough guidance, we aim to keep the - * library size below 100KB for it to be considered as small. - * As the result, most of the functionalities in the library can be tailored - * to meet the requirements; user can enable/disable specific functionalities - * to get the desired size/performance/functionality balance. - * - * For more info, please see @ref pj_config. - * - * @subsection no_dyn_mem No Dynamic Memory Allocations - * - * The central idea of PJLIB is that for applications to run as fast as it can, - * it should not use \a malloc() at all, but instead should get the memory - * from a preallocated storage pool. There are few things that can be - * optimized with this approach: - * - * - \a alloc() is a O(1) operation. - * - no mutex is used inside alloc(). It is assumed that synchronization - * will be used in higher abstraction by application anyway. - * - no \a free() is required. All chunks will be deleted when the pool is - * destroyed. - * - * The performance gained on some systems can be as high as 10x speed up - * against \a malloc() and \a free(). - * - * For more information, see \ref PJ_POOL_GROUP - * - * - * @subsection os_abstract_feat Operating System Abstraction - * - * PJLIB has abstractions for features that are normally not portable - * across operating systems: - * - @ref PJ_THREAD - *\n - * Portable thread manipulation. - * - @ref PJ_TLS - *\n - * Storing data in thread's private data. - * - @ref PJ_MUTEX - *\n - * Mutual exclusion protection. - * - @ref PJ_SEM - *\n - * Semaphores. - * - @ref PJ_ATOMIC - *\n - * Atomic variables and their operations. - * - @ref PJ_CRIT_SEC - *\n - * Fast locking of critical sections. - * - @ref PJ_LOCK - *\n - * High level abstraction for lock objects. - * - @ref PJ_EVENT - *\n - * Event object. - * - @ref PJ_TIME - *\n - * Portable time manipulation. - * - @ref PJ_TIMESTAMP - *\n - * High resolution time value. - * - etc. - * - * - * @subsection ll_network_io_sec Low-Level Network I/O - * - * PJLIB has very portable abstraction and fairly complete set of API for - * doing network I/O communications. At the lowest level, PJLIB provides: - * - * - @ref PJ_SOCK - *\n - * A highly portable socket abstraction, runs on all kind of - * network APIs such as standard BSD socket, Windows socket, Linux - * \b kernel socket, PalmOS networking API, etc. - * - * - @ref pj_addr_resolve - *\n - * Portable address resolution, which implements #pj_gethostbyname(). - * - * - @ref PJ_SOCK_SELECT - *\n - * A portable \a select() like API (#pj_sock_select()) which can be - * implemented with various back-end. - * - * - * @subsection hl_network_io_sec High-Level Network I/O - * - * At higher abstraction, PJLIB provides @ref PJ_IOQUEUE, - * which promotes creating high performance network - * applications by managing asynchronous I/O. This is a passive framework - * that utilizes the most effective way to manage asynchronous I/O - * on a given platform, such as: - * - IoCompletionPort on WinNT, - * - on Linux it can use either /dev/epoll or aio. - * - or to fall back to use @a select() - * - * At even a higher abstraction, PJLIB provides @ref PJ_EQUEUE, which - * combines asynchronous I/O with timer management and thread management - * to fasilitate creating trully high performance, event driven - * application. - * - * - * @subsection timer_mgmt_sec Timer Management - * - * A passive framework for managing timer, see @ref PJ_TIMER for more info. - * There is also function to retrieve high resolution timestamp - * from the system (see @ref PJ_TIMESTAMP). - * - * - * @subsection data_struct_sec Various Data Structures - * - * Various data structures are provided in the library: - * - * - @ref PJ_PSTR - * - @ref PJ_ARRAY - * - @ref PJ_HASH - * - @ref PJ_LIST - * - @ref PJ_RBTREE - * - * - * @subsection exception_sec Exception Construct - * - * A convenient TRY/CATCH like construct to propagate errors, which by - * default are used by the @ref PJ_POOL_GROUP "memory pool" and - * the lexical scanner in pjlib-util. The exception - * construct can be used to write programs like below: - * - * <pre> - * #define SYNTAX_ERROR 1 - * - * PJ_TRY { - * msg = NULL; - * msg = parse_msg(buf, len); - * } - * PJ_CATCH ( SYNTAX_ERROR ) { - * .. handle error .. - * } - * PJ_END; - * </pre> - * - * Please see @ref PJ_EXCEPT for more information. - * - * - * @subsection logging_sec Logging Facility - * - * PJLIB @ref PJ_LOG consists of macros to write logging information to - * some output device. Some of the features of the logging facility: - * - * - the verbosity can be fine-tuned both at compile time (to control - * the library size) or run-time (to control the verbosity of the - * information). - * - output device is configurable (e.g. stdout, printk, file, etc.) - * - log decoration is configurable. - * - * See @ref PJ_LOG for more information. - * - * - * @subsection guid_gen_sec Random and GUID Generation - * - * PJLIB provides facility to create random string - * (#pj_create_random_string()) or globally unique identifier - * (see @ref PJ_GUID). - * - * - * - * @section configure_app_sec Configuring Application to use PJLIB - * - * @subsection pjlib_compil_sec Building PJLIB - * - * Follow the instructions in \ref pjlib_build_sys_pg to build - * PJLIB. - * - * @subsection pjlib_compil_app_sec Building Applications with PJLIB - * - * Use the following settings when building applications with PJLIB. - * - * @subsubsection compil_inc_dir_sec Include Search Path - * - * Add this to your include search path ($PJLIB is PJLIB root directory): - * <pre> - * $PJLIB/include - * </pre> - * - * @subsubsection compil_inc_file_sec Include PJLIB Header - * - * To include all PJLIB headers: - * \verbatim - #include <pjlib.h> - \endverbatim - * - * Alternatively, you can include individual PJLIB headers like this: - * \verbatim - #include <pj/log.h> - #include <pj/os.h> - \endverbatim - * - * - * @subsubsection compil_lib_dir_sec Library Path - * - * Add this to your library search path: - * <pre> - * $PJLIB/lib - * </pre> - * - * Then add the appropriate PJLIB library to your link specification. For - * example, you would add \c libpj-i386-linux-gcc.a when you're building - * applications in Linux. - * - * - * @subsection pjlib_fundamentals_sec Principles in Using PJLIB - * - * Few things that you \b MUST do when using PJLIB, to make sure that - * you create trully portable applications. - * - * @subsubsection call_pjlib_init_sec Call pj_init() - * - * Before you do anything else, call \c pj_init(). This would make sure that - * PJLIB system is properly set up. - * - * @subsubsection no_ansi_subsec Do NOT Use ANSI C - * - * Contrary to popular teaching, ANSI C (and LIBC) is not the most portable - * library in the world, nor it's the most ubiquitous. For example, LIBC - * is not available in Linux kernel. Also normally LIBC will be excluded - * from compilation of RTOSes to reduce size. - * - * So for maximum portability, do NOT use ANSI C. Do not even try to include - * any other header files outside <include/pj>. Stick with the functionalities - * provided by PJLIB. - * - * - * @subsubsection string_rep_subsubsec Use pj_str_t instead of C Strings - * - * PJLIB uses pj_str_t instead of normal C strings. You SHOULD follow this - * convention too. Remember, ANSI string-h is not always available. And - * PJLIB string is faster! - * - * @subsubsection mem_alloc_subsubsec Use Pool for Memory Allocations - * - * You MUST NOT use \a malloc() or any other memory allocation functions. - * Use PJLIB pool instead! It's faster and most portable. - * - * @subsection logging_subsubsec Use Logging for Text Display - * - * DO NOT use <stdio.h> for text output. Use PJLIB logging instead. - * - * - * @section porting_pjlib_sec0 Porting PJLIB - * - * Please see \ref porting_pjlib_pg page on more information to port - * PJLIB to new target. - * - * @section enjoy_sec Enjoy Using PJLIB! - * - * We hope that you find PJLIB usefull for your application. If you - * have any questions, suggestions, critics, bug fixes, or anything - * else, we would be happy to hear it. - * - * Enjoy using PJLIB! - * - * Benny Prijono < bennylp at pjproject dot net > - */ - - - + *
+ *
+ * @section features_sec Features
+ *
+ * @subsection open_source_feat It's Open Source!
+ *
+ * PJLIB is currently released on LGPL license. We may release PJLIB under
+ * additional schemes in the future (such as GPL or MPL) to incorporate
+ * linking with specific application, however, one thing for sure is
+ * we will NEVER be able to make PJLIB a proprietary software.
+ *
+ * @subsection extreme_portable_feat Extreme Portability
+ *
+ * PJLIB is designed to be extremely portable. It can run on any kind
+ * of processors (16-bit, 32-bit, or 64-bit, big or little endian, single
+ * or multi-processors) and operating systems. Floating point or no
+ * floating point. Multi-threading or not.
+ * It can even run in environment where no ANSI LIBC is available.
+ *
+ * Currently PJLIB is being ported to:
+ * - x86, Win32 (Win95/98/ME, NT/2000/XP/2003, mingw).
+ * - x86, Linux (user mode and as <b>kernel module</b>(!)).
+ * - alpha, Linux
+ * And coming up:
+ * - x86, eCos
+ * - ultra-II, Solaris.
+ * - powerpc, MacOS
+ * - m68k, PalmOS.
+ * - arm, PocketPC
+ *
+ * No other library is known to have this extreme portability!
+ *
+ * @subsection small_size_feat Small in Size
+ *
+ * One of the primary objectives is to have library that is small in size for
+ * typical embedded applications. As a rough guidance, we aim to keep the
+ * library size below 100KB for it to be considered as small.
+ * As the result, most of the functionalities in the library can be tailored
+ * to meet the requirements; user can enable/disable specific functionalities
+ * to get the desired size/performance/functionality balance.
+ *
+ * For more info, please see @ref pj_config.
+ *
+ * @subsection no_dyn_mem No Dynamic Memory Allocations
+ *
+ * The central idea of PJLIB is that for applications to run as fast as it can,
+ * it should not use \a malloc() at all, but instead should get the memory
+ * from a preallocated storage pool. There are few things that can be
+ * optimized with this approach:
+ *
+ * - \a alloc() is a O(1) operation.
+ * - no mutex is used inside alloc(). It is assumed that synchronization
+ * will be used in higher abstraction by application anyway.
+ * - no \a free() is required. All chunks will be deleted when the pool is
+ * destroyed.
+ *
+ * The performance gained on some systems can be as high as 10x speed up
+ * against \a malloc() and \a free().
+ *
+ * For more information, see \ref PJ_POOL_GROUP
+ *
+ *
+ * @subsection os_abstract_feat Operating System Abstraction
+ *
+ * PJLIB has abstractions for features that are normally not portable
+ * across operating systems:
+ * - @ref PJ_THREAD
+ *\n
+ * Portable thread manipulation.
+ * - @ref PJ_TLS
+ *\n
+ * Storing data in thread's private data.
+ * - @ref PJ_MUTEX
+ *\n
+ * Mutual exclusion protection.
+ * - @ref PJ_SEM
+ *\n
+ * Semaphores.
+ * - @ref PJ_ATOMIC
+ *\n
+ * Atomic variables and their operations.
+ * - @ref PJ_CRIT_SEC
+ *\n
+ * Fast locking of critical sections.
+ * - @ref PJ_LOCK
+ *\n
+ * High level abstraction for lock objects.
+ * - @ref PJ_EVENT
+ *\n
+ * Event object.
+ * - @ref PJ_TIME
+ *\n
+ * Portable time manipulation.
+ * - @ref PJ_TIMESTAMP
+ *\n
+ * High resolution time value.
+ * - etc.
+ *
+ *
+ * @subsection ll_network_io_sec Low-Level Network I/O
+ *
+ * PJLIB has very portable abstraction and fairly complete set of API for
+ * doing network I/O communications. At the lowest level, PJLIB provides:
+ *
+ * - @ref PJ_SOCK
+ *\n
+ * A highly portable socket abstraction, runs on all kind of
+ * network APIs such as standard BSD socket, Windows socket, Linux
+ * \b kernel socket, PalmOS networking API, etc.
+ *
+ * - @ref pj_addr_resolve
+ *\n
+ * Portable address resolution, which implements #pj_gethostbyname().
+ *
+ * - @ref PJ_SOCK_SELECT
+ *\n
+ * A portable \a select() like API (#pj_sock_select()) which can be
+ * implemented with various back-end.
+ *
+ *
+ * @subsection hl_network_io_sec High-Level Network I/O
+ *
+ * At higher abstraction, PJLIB provides @ref PJ_IOQUEUE,
+ * which promotes creating high performance network
+ * applications by managing asynchronous I/O. This is a passive framework
+ * that utilizes the most effective way to manage asynchronous I/O
+ * on a given platform, such as:
+ * - IoCompletionPort on WinNT,
+ * - on Linux it can use either /dev/epoll or aio.
+ * - or to fall back to use @a select()
+ *
+ * At even a higher abstraction, PJLIB provides @ref PJ_EQUEUE, which
+ * combines asynchronous I/O with timer management and thread management
+ * to fasilitate creating trully high performance, event driven
+ * application.
+ *
+ *
+ * @subsection timer_mgmt_sec Timer Management
+ *
+ * A passive framework for managing timer, see @ref PJ_TIMER for more info.
+ * There is also function to retrieve high resolution timestamp
+ * from the system (see @ref PJ_TIMESTAMP).
+ *
+ *
+ * @subsection data_struct_sec Various Data Structures
+ *
+ * Various data structures are provided in the library:
+ *
+ * - @ref PJ_PSTR
+ * - @ref PJ_ARRAY
+ * - @ref PJ_HASH
+ * - @ref PJ_LIST
+ * - @ref PJ_RBTREE
+ *
+ *
+ * @subsection exception_sec Exception Construct
+ *
+ * A convenient TRY/CATCH like construct to propagate errors, which by
+ * default are used by the @ref PJ_POOL_GROUP "memory pool" and
+ * the lexical scanner in pjlib-util. The exception
+ * construct can be used to write programs like below:
+ *
+ * <pre>
+ * #define SYNTAX_ERROR 1
+ *
+ * PJ_TRY {
+ * msg = NULL;
+ * msg = parse_msg(buf, len);
+ * }
+ * PJ_CATCH ( SYNTAX_ERROR ) {
+ * .. handle error ..
+ * }
+ * PJ_END;
+ * </pre>
+ *
+ * Please see @ref PJ_EXCEPT for more information.
+ *
+ *
+ * @subsection logging_sec Logging Facility
+ *
+ * PJLIB @ref PJ_LOG consists of macros to write logging information to
+ * some output device. Some of the features of the logging facility:
+ *
+ * - the verbosity can be fine-tuned both at compile time (to control
+ * the library size) or run-time (to control the verbosity of the
+ * information).
+ * - output device is configurable (e.g. stdout, printk, file, etc.)
+ * - log decoration is configurable.
+ *
+ * See @ref PJ_LOG for more information.
+ *
+ *
+ * @subsection guid_gen_sec Random and GUID Generation
+ *
+ * PJLIB provides facility to create random string
+ * (#pj_create_random_string()) or globally unique identifier
+ * (see @ref PJ_GUID).
+ *
+ *
+ *
+ * @section configure_app_sec Configuring Application to use PJLIB
+ *
+ * @subsection pjlib_compil_sec Building PJLIB
+ *
+ * Follow the instructions in \ref pjlib_build_sys_pg to build
+ * PJLIB.
+ *
+ * @subsection pjlib_compil_app_sec Building Applications with PJLIB
+ *
+ * Use the following settings when building applications with PJLIB.
+ *
+ * @subsubsection compil_inc_dir_sec Include Search Path
+ *
+ * Add this to your include search path ($PJLIB is PJLIB root directory):
+ * <pre>
+ * $PJLIB/include
+ * </pre>
+ *
+ * @subsubsection compil_inc_file_sec Include PJLIB Header
+ *
+ * To include all PJLIB headers:
+ * \verbatim
+ #include <pjlib.h>
+ \endverbatim
+ *
+ * Alternatively, you can include individual PJLIB headers like this:
+ * \verbatim
+ #include <pj/log.h>
+ #include <pj/os.h>
+ \endverbatim
+ *
+ *
+ * @subsubsection compil_lib_dir_sec Library Path
+ *
+ * Add this to your library search path:
+ * <pre>
+ * $PJLIB/lib
+ * </pre>
+ *
+ * Then add the appropriate PJLIB library to your link specification. For
+ * example, you would add \c libpj-i386-linux-gcc.a when you're building
+ * applications in Linux.
+ *
+ *
+ * @subsection pjlib_fundamentals_sec Principles in Using PJLIB
+ *
+ * Few things that you \b MUST do when using PJLIB, to make sure that
+ * you create trully portable applications.
+ *
+ * @subsubsection call_pjlib_init_sec Call pj_init()
+ *
+ * Before you do anything else, call \c pj_init(). This would make sure that
+ * PJLIB system is properly set up.
+ *
+ * @subsubsection no_ansi_subsec Do NOT Use ANSI C
+ *
+ * Contrary to popular teaching, ANSI C (and LIBC) is not the most portable
+ * library in the world, nor it's the most ubiquitous. For example, LIBC
+ * is not available in Linux kernel. Also normally LIBC will be excluded
+ * from compilation of RTOSes to reduce size.
+ *
+ * So for maximum portability, do NOT use ANSI C. Do not even try to include
+ * any other header files outside <include/pj>. Stick with the functionalities
+ * provided by PJLIB.
+ *
+ *
+ * @subsubsection string_rep_subsubsec Use pj_str_t instead of C Strings
+ *
+ * PJLIB uses pj_str_t instead of normal C strings. You SHOULD follow this
+ * convention too. Remember, ANSI string-h is not always available. And
+ * PJLIB string is faster!
+ *
+ * @subsubsection mem_alloc_subsubsec Use Pool for Memory Allocations
+ *
+ * You MUST NOT use \a malloc() or any other memory allocation functions.
+ * Use PJLIB pool instead! It's faster and most portable.
+ *
+ * @subsection logging_subsubsec Use Logging for Text Display
+ *
+ * DO NOT use <stdio.h> for text output. Use PJLIB logging instead.
+ *
+ *
+ * @section porting_pjlib_sec0 Porting PJLIB
+ *
+ * Please see \ref porting_pjlib_pg page on more information to port
+ * PJLIB to new target.
+ *
+ * @section enjoy_sec Enjoy Using PJLIB!
+ *
+ * We hope that you find PJLIB usefull for your application. If you
+ * have any questions, suggestions, critics, bug fixes, or anything
+ * else, we would be happy to hear it.
+ *
+ * Enjoy using PJLIB!
+ *
+ * Benny Prijono < bennylp at pjproject dot net >
+ */
+
+
+
/*////////////////////////////////////////////////////////////////////////// */
/*
CODING CONVENTION
@@ -439,566 +460,566 @@ *
*/
- -/*////////////////////////////////////////////////////////////////////////// */ -/* - BUILDING AND INSTALLING PJLIB - */ - - - -/** - * @page pjlib_build_sys_pg Building, and Installing PJLIB - * - * @section build_sys_install_sec Build and Installation - * - * @subsection build_sys_install_win32_sec Visual Studio - * - * The PJLIB Visual Studio workspace supports the building of PJLIB - * for Win32 target. Although currently only the Visual Studio 6 Workspace is - * actively maintained, developers with later version of Visual Studio - * can easily imports VS6 workspace into their IDE. - * - * To start building PJLIB projects with Visual Studio 6 or later, open - * the \a workspace file in the corresponding \b \c build directory. You have - * several choices on which \a dsw file to open: - \verbatim - $PJPROJECT/build/pjproject.dsw - $PJPROJECT/pjlib/build/pjlib.dsw - $PJPROJECT/pjsip/build/pjsip.dsw - ..etc - \endverbatim - * - * The easiest way is to open <tt>pjproject.dsw</tt> file in \b \c $PJPROJECT/build - * directory. However this will only build the required projects, not - * the complete projects. For example, the PJLIB test and samples projects - * are not included in this workspace. To build the complete projects, you must - * open and build each \a dsw file in \c build directory in each - * subprojects. For example, to open the complete PJLIB workspace, open - * <tt>pjlib.dsw</tt> in <tt>$PJPROJECT/pjlib/build</tt> directory. - * - * - * @subsubsection config_site_create_vc_sec Create config_site.h - * - * The file <tt><b>$PJPROJECT/pjlib/include/pj/config_site.h</b></tt> - * is supposed to contain configuration that is specific to your site/target. - * This file is not part of PJLIB, so you must create it yourself. Normally - * you just need to create a blank file. - * - * The reason why it's not included in PJLIB is so that you would not accidently - * overwrite your site configuration. - * - * If you fail to do this, Visual C will complain with error like: - * - * <b>"fatal error C1083: Cannot open include file: 'pj/config_site.h': No such file - * or directory"</b>. - * - * @subsubsection build_vc_subsubsec Build the Projects - * - * Just hit the build button! - * - * - * @subsection build_sys_install_unix_sec Make System - * - * For other targets, PJLIB provides a rather comprehensive build system - * that uses GNU \a make (and only GNU \a make will work). - * Currently, the build system supports building * PJLIB for these targets: - * - i386/Win32/mingw - * - i386/Linux - * - i386/Linux (kernel) - * - alpha/linux - * - sparc/SunOS - * - etc.. - * - * - * @subsubsection build_req_sec Requirements - * - * In order to use the \c make based build system, you MUST have: - * - * - <b>GNU make</b> - *\n - * The Makefiles heavily utilize GNU make commands which most likely - * are not available in other \c make system. - * - <b>bash</b> shell is recommended. - *\n - * Specificly, there is a command <tt>"echo -n"</tt> which may not work - * in other shells. This command is used when generating dependencies - * (<tt>make dep</tt>) and it's located in - * <tt>$PJPROJECT/build/rules.mak</tt>. - * - <b>ar</b>, <b>ranlib</b> from GNU binutils - *\n - * In your system has different <tt>ar</tt> or <tt>ranlib</tt> (e.g. they - * may have been installed as <tt>gar</tt> and <tt>granlib</tt>), then - * either you create the relevant symbolic links, <b>or</b> modify - * <tt>$PJPROJECT/build/cc-gcc.mak</tt> and rename <tt>ar</tt> and - * <tt>ranlib</tt> to the appropriate names. - * - <b>gcc</b> to generate dependency. - *\n - * Currently the build system uses <tt>"gcc -MM"</tt> to generate build - * dependencies. If <tt>gcc</tt> is not desired to generate dependency, - * then either you don't run <tt>make dep</tt>, <b>or</b> edit - * <tt>$PJPROJECT/build/rules.mak</tt> to calculate dependency using - * your prefered method. (And let me know when you do so so that I can - * update the file. :) ) - * - * @subsubsection build_overview_sec Building the Project - * - * Generally, steps required to build the PJLIB are: - * - \verbatim - $ cd /home/user/pjproject # <-- go to $PJPROJECT - $ vi build.mak # <-- set build target etc - $ touch pjlib/include/pj/config_site.h - $ cd pjlib/build # <-- go to projet's build dir - $ make # <-- build the project - \endverbatim - * - * For other project, \a cd to <tt>build</tt> directory in the project - * and execute \a make from there. - * - * \note For Linux kernel target, there are additional steps required, which - * will be explained in section \ref linux_kern_target_subsec. - * - * @subsubsection build_mak_sec Editing build.mak - * - * The \c build.mak file in \c $PJPROJECT root directory is used to - * specify the build configuration. This file is expected to export - * the following \a make variables: - * - * - <tt><b>MACHINE_NAME</b></tt> - *\n - * Target machine/processor, one of: <b>{ i386 | alpha | sparc }</b>. - * - * - <tt><b>OS_NAME</b></tt> - *\n - * Target operating system, one of: <b>{ win32 | linux | - * linux-kernel | sunos }</b>. - * - * - <tt><b>CC_NAME</b></tt> - *\n - * Compiler name: <b>{ gcc | vc }</b>\n - * (Note that support for Visual C (vc) compiler with the \c make system is - * experimental, and it will only work when run inside a DOS shell - * (i.e. <tt>"HOST_NAME=win32"</tt>)). - * - * - <tt><b>HOST_NAME</b></tt> - *\n - * Build host: <b>{ unix | mingw | win32 }</b>\n - * (Note: win32 host means a DOS command prompt. Support for this type - * of development host is experimental). - * - * These variables will cause the correct configuration file in - * \c $PJPROJECT/build directory to be executed by \a make. For - * example, specifying \c OS_NAME=linux will cause file \c os-linux.mak - * in \c build directory to be executed. These files contain specific - * configuration for the option that is selected. - * - * For Linux kernel target, you are also required to declare the following - * variables in this file: - * - \c KERNEL_DIR: full path of kernel source tree. - * - \c KERNEL_ARCH: kernel ARCH options (e.g. "ARCH=um"), or leave blank - * for default. - * - \c PJPROJECT_DIR: full path of PJPROJECT source tree. - * - * Apart from these, there are also additional steps required to build - * Linux kernel target, which will be explained in \ref linux_kern_target_subsec. - * - * @subsubsection build_dir_sec Files in "build" Directory - * - * The <tt>*.mak</tt> files in \c $PJPROJECT/build directory are used to specify - * the configuration for the specified compiler, target machine target - * operating system, and host options. These files will be executed - * (included) by \a make during building process, depending on the values - * specified in <b>$PJPROJECT/build.mak</b> file. - * - * Normally you don't need to edit these files, except when you're porting - * PJLIB to new target. - * - * Below are the description of some files in this directory: - * - * - <tt>rules.mak</tt>: contains generic rules always included during make. - * - <tt>cc-gcc.mak</tt>: rules when gcc is used for compiler. - * - <tt>cc-vc.mak</tt>: rules when MSVC compiler is used. - * - <tt>host-mingw.mak</tt>: rules for building in mingw host. - * - <tt>host-unix.mak</tt>: rules for building in Unix/Posix host. - * - <tt>host-win32.mak</tt>: rules for building in Win32 command console - * (only valid when VC is used). - * - <tt>m-i386.mak</tt>: rules when target machine is an i386 processor. - * - <tt>m-m68k.mak</tt>: rules when target machine is an m68k processor. - * - <tt>os-linux.mak</tt>: rules when target OS is Linux. - * - <tt>os-linux-kernel.mak</tt>: rules when PJLIB is to be build as - * part of Linux kernel. - * - <tt>os-win32.mak</tt>: rules when target OS is Win32. - * - * - * @subsubsection config_site_create_sec Create config_site.h - * - * The file <tt><b>$PJPROJECT/pjlib/include/pj/config_site.h</b></tt> - * is supposed to contain configuration that is specific to your site/target. - * This file is not part of PJLIB, so you must create it yourself. - * - * The reason why it's not included in PJLIB is so that you would not accidently - * overwrite your site configuration. - * - * - * @subsubsection invoking_make_sec Invoking make - * - * Normally, \a make is invoked in \c build directory under each project. - * For example, to build PJLIB, you would invoke \a make in - * \c $PJPROJECT/pjlib/build directory like below: - * - \verbatim - $ cd pjlib/build - $ make - \endverbatim - * - * Alternatively you may invoke <tt>make</tt> in <tt>$PJPROJECT</tt> - * directory, to build all projects under that directory (e.g. - * PJLIB, PJSIP, etc.). - * - * - * @subsubsection linux_kern_target_subsec Linux Kernel Target - * - * \note - * <b>BUILDING APPLICATIONS IN LINUX KERNEL MODE IS A VERY DANGEROUS BUSINESS. - * YOU MAY CRASH THE WHOLE OF YOUR SYSTEM, CORRUPT YOUR HARDISK, ETC. PJLIB - * KERNEL MODULES ARE STILL IN EXPERIMENTAL PHASE. DO NOT RUN IT IN PRODUCTION - * SYSTEMS OR OTHER SYSTEMS WHERE RISK OF LOSS OF DATA IS NOT ACCEPTABLE. - * YOU HAVE BEEN WARNED.</b> - * - * \note - * <b>User Mode Linux (UML)</b> provides excellent way to experiment with Linux - * kernel without risking the stability of the host system. See - * http://user-mode-linux.sourceforge.net for details. - * - * \note - * I only use <b>UML</b> to experiment with PJLIB kernel modules. - * <b>I wouldn't be so foolish to use my host Linux machine to experiment - * with this.</b> - * - * \note - * You have been warned. - * - * For building PJLIB for Linux kernel target, there are additional steps required. - * In general, the additional tasks are: - * - Declare some more variables in <b><tt>build.mak</tt></b> file (this - * has been explained in \ref build_mak_sec above). - * - Perform these two small modifications in kernel source tree. - * - * There are two small modification need to be applied to the kernel tree. - * - * <b>1. Edit <tt>Makefile</tt> in kernel root source tree.</b> - * - * Add the following lines at the end of the <tt>Makefile</tt> in your - * <tt>$KERNEL_SRC</tt> dir: - \verbatim -script: - $(SCRIPT) - \endverbatim - * - * \note Remember to replace spaces with <b>tab</b> in the Makefile. - * - * The modification above is needed to capture kernel's \c $CFLAGS and - * \c $CFLAGS_MODULE which will be used for PJLIB's compilation. - * - * <b>2. Add Additional Exports.</b> - * - * We need the kernel to export some more symbols for our use. So we declare - * the additional symbols to be exported in <tt>extra-exports.c</tt> file, and add - * a this file to be compiled into the kernel: - * - * - Copy the file <tt>extra-exports.c</tt> from <tt>pjlib/src/pj</tt> - * directory to <tt>$KERNEL_SRC/kernel/</tt> directory. - * - Edit <tt>Makefile</tt> in that directory, and add this line - * somewhere after the declaration of that variable: - \verbatim -obj-y += extra-exports.o - \endverbatim - * - * To illustrate what have been done in your kernel source tree, below - * is screenshot of my kernel source tree _after_ the modification. - * - \verbatim -[root@vpc-linux linux-2.6.7]# pwd -/usr/src/linux-2.6.7 -[root@vpc-linux linux-2.6.7]# -[root@vpc-linux linux-2.6.7]# -[root@vpc-linux linux-2.6.7]# tail Makefile - -endif # skip-makefile - -FORCE: - -.PHONY: script - -script: - $(SCRIPT) - -[root@vpc-linux linux-2.6.7]# -[root@vpc-linux linux-2.6.7]# -[root@vpc-linux linux-2.6.7]# head kernel/extra-exports.c -#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); -[root@vpc-linux linux-2.6.7]# -[root@vpc-linux linux-2.6.7]# -[root@vpc-linux linux-2.6.7]# head -15 kernel/Makefile -# -# Makefile for the linux kernel. -# - -obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \ - exit.o itimer.o time.o softirq.o resource.o \ - sysctl.o capability.o ptrace.o timer.o user.o \ - signal.o sys.o kmod.o workqueue.o pid.o \ - rcupdate.o intermodule.o extable.o params.o posix-timers.o \ - kthread.o - -obj-y += extra-exports.o - -obj-$(CONFIG_FUTEX) += futex.o -obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o -[root@vpc-linux linux-2.6.7]# - - \endverbatim - * - * Then you must rebuild the kernel. - * If you fail to do this, you won't be able to <b>insmod</b> pjlib. - * - * \note You will see a lots of warning messages during pjlib-test compilation. - * The warning messages complain about unresolved symbols which are defined - * in pjlib module. You can safely ignore these warnings. However, you can not - * ignore warnings about non-pjlib unresolved symbols. - * - * - * @subsection makefile_explained_sec Makefile Explained - * - * The \a Makefile for each project (e.g. PJLIB, PJSIP, etc) should be - * very similar in the contents. The Makefile is located under \c build - * directory in each project subdir. - * - * @subsubsection pjlib_makefile_subsec PJLIB Makefile. - * - * Below is PJLIB's Makefile: - * - * \include build/Makefile - * - * @subsubsection pjlib_os_makefile_subsec PJLIB os-linux.mak. - * - * Below is file <tt><b>os-linux.mak</b></tt> file in - * <tt>$PJPROJECT/pjlib/build</tt> directory, - * which is OS specific configuration file for Linux target that is specific - * for PJLIB project. For \b global OS specific configuration, please see - * <tt>$PJPROJECT/build/os-*.mak</tt>. - * - * \include build/os-linux.mak - * - */ - - -/*////////////////////////////////////////////////////////////////////////// */ -/* - PORTING PJLIB - */ - - - -/** - * @page porting_pjlib_pg Porting PJLIB - * - * - * @section new_arch_sec Porting to New CPU Architecture - * - * Below is step-by-step guide to add support for new CPU architecture. - * This sample is based on porting to Alpha architecture; however steps for - * porting to other CPU architectures should be pretty similar. - * - * Also note that in this example, the operating system used is <b>Linux</b>. - * Should you wish to add support for new operating system, then follow - * the next section \ref porting_os_sec. - * - * Step-by-step guide to port to new CPU architecture: - * - decide the name for the new architecture. In this case, we choose - * <tt><b>alpha</b></tt>. - * - edit file <tt>$PJPROJECT/build.mak</tt>, and add new section for - * the new target: - * <pre> - * # - * # Linux alpha, gcc - * # - * export MACHINE_NAME := <b>alpha</b> - * export OS_NAME := linux - * export CC_NAME := gcc - * export HOST_NAME := unix - * </pre> - * - * - create a new file <tt>$PJPROJECT/build/<b>m-alpha</b>.mak</tt>. - * Alternatively create a copy from other file in this directory. - * The contents of this file will look something like: - * <pre> - * export M_CFLAGS := $(CC_DEF)<b>PJ_M_ALPHA=1</b> - * export M_CXXFLAGS := - * export M_LDFLAGS := - * export M_SOURCES := - * </pre> - * - create a new file <tt>$PJPROJECT/pjlib/include/pj/compat/<b>m_alpha.h</b></tt>. - * Alternatively create a copy from other header file in this directory. - * The contents of this file will look something like: - * <pre> - * #define PJ_HAS_PENTIUM 0 - * #define PJ_IS_LITTLE_ENDIAN 1 - * #define PJ_IS_BIG_ENDIAN 0 - * </pre> - * - edit <tt>pjlib/include/pj/<b>config.h</b></tt>. Add new processor - * configuration in this header file, like follows: - * <pre> - * ... - * #elif defined (PJ_M_ALPHA) && PJ_M_ALPHA != 0 - * # include <pj/compat/m_alpha.h> - * ... - * </pre> - * - done. Build PJLIB with: - * <pre> - * $ cd $PJPROJECT/pjlib/build - * $ make dep - * $ make clean - * $ make - * </pre> - * - * @section porting_os_sec Porting to New Operating System Target - * - * This section will try to give you rough guideline on how to - * port PJLIB to a new target. As a sample, we give the target a name tag, - * for example <tt><b>xos</b></tt> (for X OS). - * - * @subsection new_compat_os_h_file_sec Create New Compat Header File - * - * You'll need to create a new header file - * <b><tt>include/pj/compat/os_xos.h</tt></b>. You can copy as a - * template other header file and edit it accordingly. - * - * @subsection modify_config_h_file_sec Modify config.h - * - * Then modify file <b><tt>include/pj/config.h</tt></b> to include - * this file accordingly (e.g. when macro <tt><b>PJ_XOS</b></tt> is - * defined): - * - \verbatim - ... - #elif defined(PJ_XOS) - # include <pj/compat/os_xos.h> - #else - #... - \endverbatim - * - * @subsection new_target_mak_file_sec Create New Global Make Config File - * - * Then you'll need to create global configuration file that - * is specific for this OS, i.e. <tt><b>os-xos.mak</b></tt> in - * <tt><b>$PJPROJECT/build</b></tt> directory. - * - * At very minimum, the file will normally need to define - * <tt><b>PJ_XOS=1</b></tt> in the \c CFLAGS section: - * - \verbatim -# -# $PJPROJECT/build/os-xos.mak: -# -export OS_CFLAGS := $(CC_DEF)PJ_XOS=1 -export OS_CXXFLAGS := -export OS_LDFLAGS := -export OS_SOURCES := - \endverbatim - * - * - * @subsection new_target_prj_mak_file_sec Create New Project's Make Config File - * - * Then you'll need to create xos-specific configuration file - * for PJLIB. This file is also named <tt><b>os-xos.mak</b></tt>, - * but its located in <tt><b>pjlib/build</b></tt> directory. - * This file will specify source files that are specific to - * this OS to be included in the build process. - * - * Below is a sample: - \verbatim -# -# pjlib/build/os-xos.mak: -# XOS specific configuration for PJLIB. -# -export PJLIB_OBJS += os_core_xos.o \ - os_error_unix.o \ - os_time_ansi.o -export TEST_OBJS += main.o -export TARGETS = pjlib pjlib-test - \endverbatim - * - * @subsection new_target_src_sec Create and Edit Source Files - * - * You'll normally need to create at least these files: - * - <tt><b>os_core_xos.c</b></tt>: core OS specific - * functionality. - * - <tt><b>os_timestamp_xos.c</b></tt>: how to get timestamp - * in this OS. - * - * Depending on how things are done in your OS, you may need - * to create these files: - * - <tt><b>os_error_*.c</b></tt>: how to manipulate - * OS error codes. Alternatively you may use existing - * <tt>os_error_unix.c</tt> if the OS has \c errno and - * \c strerror() function. - * - <tt><b>ioqueue_*.c</b></tt>: if the OS has specific method - * to perform asynchronous I/O. Alternatively you may - * use existing <tt>ioqueue_select.c</tt> if the OS supports - * \c select() function call. - * - <tt><b>sock_*.c</b></tt>: if the OS has specific method - * to perform socket communication. Alternatively you may - * use existing <tt>sock_bsd.c</tt> if the OS supports - * BSD socket API, and edit <tt>include/pj/compat/socket.h</tt> - * file accordingly. - * - * You will also need to check various files in - * <tt><b>include/pj/compat/*.h</b></tt>, to see if they're - * compatible with your OS. - * - * @subsection new_target_build_file_sec Build The Project - * - * After basic building blocks have been created for the OS, then - * the easiest way to see which parts need to be fixed is by building - * the project and see the error messages. - * - * @subsection new_target_edit_vs_new_file_sec Editing Existing Files vs Creating New File - * - * When you encounter compatibility errors in PJLIB during porting, - * you have three options on how to fix the error: - * - edit the existing <tt>*.c</tt> file, and give it <tt>#ifdef</tt> - * switch for the new OS, or - * - edit <tt>include/pj/compat/*.h</tt> instead, or - * - create a totally new file. - * - * Basicly there is no strict rule on which approach is the best - * to use, however the following guidelines may be used: - * - if the file is expected to be completely different than - * any existing file, then perhaps you should create a completely - * new file. For example, file <tt>os_core_xxx.c</tt> will - * normally be different for each OS flavour. - * - if the difference can be localized in <tt>include/compat</tt> - * header file, and existing <tt>#ifdef</tt> switch is there, - * then preferably you should edit this <tt>include/compat</tt> - * header file. - * - if the existing <tt>*.c</tt> file has <tt>#ifdef</tt> switch, - * then you may add another <tt>#elif</tt> switch there. This - * normally is used for behaviors that are not totally - * different on each platform. - * - other than that above, use your own judgement on whether - * to edit the file or create new file etc. - */ - -#endif /* __PJ_DOXYGEN_H__ */ - +
+/*////////////////////////////////////////////////////////////////////////// */
+/*
+ BUILDING AND INSTALLING PJLIB
+ */
+
+
+
+/**
+ * @page pjlib_build_sys_pg Building, and Installing PJLIB
+ *
+ * @section build_sys_install_sec Build and Installation
+ *
+ * @subsection build_sys_install_win32_sec Visual Studio
+ *
+ * The PJLIB Visual Studio workspace supports the building of PJLIB
+ * for Win32 target. Although currently only the Visual Studio 6 Workspace is
+ * actively maintained, developers with later version of Visual Studio
+ * can easily imports VS6 workspace into their IDE.
+ *
+ * To start building PJLIB projects with Visual Studio 6 or later, open
+ * the \a workspace file in the corresponding \b \c build directory. You have
+ * several choices on which \a dsw file to open:
+ \verbatim
+ $PJPROJECT/build/pjproject.dsw
+ $PJPROJECT/pjlib/build/pjlib.dsw
+ $PJPROJECT/pjsip/build/pjsip.dsw
+ ..etc
+ \endverbatim
+ *
+ * The easiest way is to open <tt>pjproject.dsw</tt> file in \b \c $PJPROJECT/build
+ * directory. However this will only build the required projects, not
+ * the complete projects. For example, the PJLIB test and samples projects
+ * are not included in this workspace. To build the complete projects, you must
+ * open and build each \a dsw file in \c build directory in each
+ * subprojects. For example, to open the complete PJLIB workspace, open
+ * <tt>pjlib.dsw</tt> in <tt>$PJPROJECT/pjlib/build</tt> directory.
+ *
+ *
+ * @subsubsection config_site_create_vc_sec Create config_site.h
+ *
+ * The file <tt><b>$PJPROJECT/pjlib/include/pj/config_site.h</b></tt>
+ * is supposed to contain configuration that is specific to your site/target.
+ * This file is not part of PJLIB, so you must create it yourself. Normally
+ * you just need to create a blank file.
+ *
+ * The reason why it's not included in PJLIB is so that you would not accidently
+ * overwrite your site configuration.
+ *
+ * If you fail to do this, Visual C will complain with error like:
+ *
+ * <b>"fatal error C1083: Cannot open include file: 'pj/config_site.h': No such file
+ * or directory"</b>.
+ *
+ * @subsubsection build_vc_subsubsec Build the Projects
+ *
+ * Just hit the build button!
+ *
+ *
+ * @subsection build_sys_install_unix_sec Make System
+ *
+ * For other targets, PJLIB provides a rather comprehensive build system
+ * that uses GNU \a make (and only GNU \a make will work).
+ * Currently, the build system supports building * PJLIB for these targets:
+ * - i386/Win32/mingw
+ * - i386/Linux
+ * - i386/Linux (kernel)
+ * - alpha/linux
+ * - sparc/SunOS
+ * - etc..
+ *
+ *
+ * @subsubsection build_req_sec Requirements
+ *
+ * In order to use the \c make based build system, you MUST have:
+ *
+ * - <b>GNU make</b>
+ *\n
+ * The Makefiles heavily utilize GNU make commands which most likely
+ * are not available in other \c make system.
+ * - <b>bash</b> shell is recommended.
+ *\n
+ * Specificly, there is a command <tt>"echo -n"</tt> which may not work
+ * in other shells. This command is used when generating dependencies
+ * (<tt>make dep</tt>) and it's located in
+ * <tt>$PJPROJECT/build/rules.mak</tt>.
+ * - <b>ar</b>, <b>ranlib</b> from GNU binutils
+ *\n
+ * In your system has different <tt>ar</tt> or <tt>ranlib</tt> (e.g. they
+ * may have been installed as <tt>gar</tt> and <tt>granlib</tt>), then
+ * either you create the relevant symbolic links, <b>or</b> modify
+ * <tt>$PJPROJECT/build/cc-gcc.mak</tt> and rename <tt>ar</tt> and
+ * <tt>ranlib</tt> to the appropriate names.
+ * - <b>gcc</b> to generate dependency.
+ *\n
+ * Currently the build system uses <tt>"gcc -MM"</tt> to generate build
+ * dependencies. If <tt>gcc</tt> is not desired to generate dependency,
+ * then either you don't run <tt>make dep</tt>, <b>or</b> edit
+ * <tt>$PJPROJECT/build/rules.mak</tt> to calculate dependency using
+ * your prefered method. (And let me know when you do so so that I can
+ * update the file. :) )
+ *
+ * @subsubsection build_overview_sec Building the Project
+ *
+ * Generally, steps required to build the PJLIB are:
+ *
+ \verbatim
+ $ cd /home/user/pjproject # <-- go to $PJPROJECT
+ $ vi build.mak # <-- set build target etc
+ $ touch pjlib/include/pj/config_site.h
+ $ cd pjlib/build # <-- go to projet's build dir
+ $ make # <-- build the project
+ \endverbatim
+ *
+ * For other project, \a cd to <tt>build</tt> directory in the project
+ * and execute \a make from there.
+ *
+ * \note For Linux kernel target, there are additional steps required, which
+ * will be explained in section \ref linux_kern_target_subsec.
+ *
+ * @subsubsection build_mak_sec Editing build.mak
+ *
+ * The \c build.mak file in \c $PJPROJECT root directory is used to
+ * specify the build configuration. This file is expected to export
+ * the following \a make variables:
+ *
+ * - <tt><b>MACHINE_NAME</b></tt>
+ *\n
+ * Target machine/processor, one of: <b>{ i386 | alpha | sparc }</b>.
+ *
+ * - <tt><b>OS_NAME</b></tt>
+ *\n
+ * Target operating system, one of: <b>{ win32 | linux |
+ * linux-kernel | sunos }</b>.
+ *
+ * - <tt><b>CC_NAME</b></tt>
+ *\n
+ * Compiler name: <b>{ gcc | vc }</b>\n
+ * (Note that support for Visual C (vc) compiler with the \c make system is
+ * experimental, and it will only work when run inside a DOS shell
+ * (i.e. <tt>"HOST_NAME=win32"</tt>)).
+ *
+ * - <tt><b>HOST_NAME</b></tt>
+ *\n
+ * Build host: <b>{ unix | mingw | win32 }</b>\n
+ * (Note: win32 host means a DOS command prompt. Support for this type
+ * of development host is experimental).
+ *
+ * These variables will cause the correct configuration file in
+ * \c $PJPROJECT/build directory to be executed by \a make. For
+ * example, specifying \c OS_NAME=linux will cause file \c os-linux.mak
+ * in \c build directory to be executed. These files contain specific
+ * configuration for the option that is selected.
+ *
+ * For Linux kernel target, you are also required to declare the following
+ * variables in this file:
+ * - \c KERNEL_DIR: full path of kernel source tree.
+ * - \c KERNEL_ARCH: kernel ARCH options (e.g. "ARCH=um"), or leave blank
+ * for default.
+ * - \c PJPROJECT_DIR: full path of PJPROJECT source tree.
+ *
+ * Apart from these, there are also additional steps required to build
+ * Linux kernel target, which will be explained in \ref linux_kern_target_subsec.
+ *
+ * @subsubsection build_dir_sec Files in "build" Directory
+ *
+ * The <tt>*.mak</tt> files in \c $PJPROJECT/build directory are used to specify
+ * the configuration for the specified compiler, target machine target
+ * operating system, and host options. These files will be executed
+ * (included) by \a make during building process, depending on the values
+ * specified in <b>$PJPROJECT/build.mak</b> file.
+ *
+ * Normally you don't need to edit these files, except when you're porting
+ * PJLIB to new target.
+ *
+ * Below are the description of some files in this directory:
+ *
+ * - <tt>rules.mak</tt>: contains generic rules always included during make.
+ * - <tt>cc-gcc.mak</tt>: rules when gcc is used for compiler.
+ * - <tt>cc-vc.mak</tt>: rules when MSVC compiler is used.
+ * - <tt>host-mingw.mak</tt>: rules for building in mingw host.
+ * - <tt>host-unix.mak</tt>: rules for building in Unix/Posix host.
+ * - <tt>host-win32.mak</tt>: rules for building in Win32 command console
+ * (only valid when VC is used).
+ * - <tt>m-i386.mak</tt>: rules when target machine is an i386 processor.
+ * - <tt>m-m68k.mak</tt>: rules when target machine is an m68k processor.
+ * - <tt>os-linux.mak</tt>: rules when target OS is Linux.
+ * - <tt>os-linux-kernel.mak</tt>: rules when PJLIB is to be build as
+ * part of Linux kernel.
+ * - <tt>os-win32.mak</tt>: rules when target OS is Win32.
+ *
+ *
+ * @subsubsection config_site_create_sec Create config_site.h
+ *
+ * The file <tt><b>$PJPROJECT/pjlib/include/pj/config_site.h</b></tt>
+ * is supposed to contain configuration that is specific to your site/target.
+ * This file is not part of PJLIB, so you must create it yourself.
+ *
+ * The reason why it's not included in PJLIB is so that you would not accidently
+ * overwrite your site configuration.
+ *
+ *
+ * @subsubsection invoking_make_sec Invoking make
+ *
+ * Normally, \a make is invoked in \c build directory under each project.
+ * For example, to build PJLIB, you would invoke \a make in
+ * \c $PJPROJECT/pjlib/build directory like below:
+ *
+ \verbatim
+ $ cd pjlib/build
+ $ make
+ \endverbatim
+ *
+ * Alternatively you may invoke <tt>make</tt> in <tt>$PJPROJECT</tt>
+ * directory, to build all projects under that directory (e.g.
+ * PJLIB, PJSIP, etc.).
+ *
+ *
+ * @subsubsection linux_kern_target_subsec Linux Kernel Target
+ *
+ * \note
+ * <b>BUILDING APPLICATIONS IN LINUX KERNEL MODE IS A VERY DANGEROUS BUSINESS.
+ * YOU MAY CRASH THE WHOLE OF YOUR SYSTEM, CORRUPT YOUR HARDISK, ETC. PJLIB
+ * KERNEL MODULES ARE STILL IN EXPERIMENTAL PHASE. DO NOT RUN IT IN PRODUCTION
+ * SYSTEMS OR OTHER SYSTEMS WHERE RISK OF LOSS OF DATA IS NOT ACCEPTABLE.
+ * YOU HAVE BEEN WARNED.</b>
+ *
+ * \note
+ * <b>User Mode Linux (UML)</b> provides excellent way to experiment with Linux
+ * kernel without risking the stability of the host system. See
+ * http://user-mode-linux.sourceforge.net for details.
+ *
+ * \note
+ * I only use <b>UML</b> to experiment with PJLIB kernel modules.
+ * <b>I wouldn't be so foolish to use my host Linux machine to experiment
+ * with this.</b>
+ *
+ * \note
+ * You have been warned.
+ *
+ * For building PJLIB for Linux kernel target, there are additional steps required.
+ * In general, the additional tasks are:
+ * - Declare some more variables in <b><tt>build.mak</tt></b> file (this
+ * has been explained in \ref build_mak_sec above).
+ * - Perform these two small modifications in kernel source tree.
+ *
+ * There are two small modification need to be applied to the kernel tree.
+ *
+ * <b>1. Edit <tt>Makefile</tt> in kernel root source tree.</b>
+ *
+ * Add the following lines at the end of the <tt>Makefile</tt> in your
+ * <tt>$KERNEL_SRC</tt> dir:
+ \verbatim
+script:
+ $(SCRIPT)
+ \endverbatim
+ *
+ * \note Remember to replace spaces with <b>tab</b> in the Makefile.
+ *
+ * The modification above is needed to capture kernel's \c $CFLAGS and
+ * \c $CFLAGS_MODULE which will be used for PJLIB's compilation.
+ *
+ * <b>2. Add Additional Exports.</b>
+ *
+ * We need the kernel to export some more symbols for our use. So we declare
+ * the additional symbols to be exported in <tt>extra-exports.c</tt> file, and add
+ * a this file to be compiled into the kernel:
+ *
+ * - Copy the file <tt>extra-exports.c</tt> from <tt>pjlib/src/pj</tt>
+ * directory to <tt>$KERNEL_SRC/kernel/</tt> directory.
+ * - Edit <tt>Makefile</tt> in that directory, and add this line
+ * somewhere after the declaration of that variable:
+ \verbatim
+obj-y += extra-exports.o
+ \endverbatim
+ *
+ * To illustrate what have been done in your kernel source tree, below
+ * is screenshot of my kernel source tree _after_ the modification.
+ *
+ \verbatim
+[root@vpc-linux linux-2.6.7]# pwd
+/usr/src/linux-2.6.7
+[root@vpc-linux linux-2.6.7]#
+[root@vpc-linux linux-2.6.7]#
+[root@vpc-linux linux-2.6.7]# tail Makefile
+
+endif # skip-makefile
+
+FORCE:
+
+.PHONY: script
+
+script:
+ $(SCRIPT)
+
+[root@vpc-linux linux-2.6.7]#
+[root@vpc-linux linux-2.6.7]#
+[root@vpc-linux linux-2.6.7]# head kernel/extra-exports.c
+#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);
+[root@vpc-linux linux-2.6.7]#
+[root@vpc-linux linux-2.6.7]#
+[root@vpc-linux linux-2.6.7]# head -15 kernel/Makefile
+#
+# Makefile for the linux kernel.
+#
+
+obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \
+ exit.o itimer.o time.o softirq.o resource.o \
+ sysctl.o capability.o ptrace.o timer.o user.o \
+ signal.o sys.o kmod.o workqueue.o pid.o \
+ rcupdate.o intermodule.o extable.o params.o posix-timers.o \
+ kthread.o
+
+obj-y += extra-exports.o
+
+obj-$(CONFIG_FUTEX) += futex.o
+obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
+[root@vpc-linux linux-2.6.7]#
+
+ \endverbatim
+ *
+ * Then you must rebuild the kernel.
+ * If you fail to do this, you won't be able to <b>insmod</b> pjlib.
+ *
+ * \note You will see a lots of warning messages during pjlib-test compilation.
+ * The warning messages complain about unresolved symbols which are defined
+ * in pjlib module. You can safely ignore these warnings. However, you can not
+ * ignore warnings about non-pjlib unresolved symbols.
+ *
+ *
+ * @subsection makefile_explained_sec Makefile Explained
+ *
+ * The \a Makefile for each project (e.g. PJLIB, PJSIP, etc) should be
+ * very similar in the contents. The Makefile is located under \c build
+ * directory in each project subdir.
+ *
+ * @subsubsection pjlib_makefile_subsec PJLIB Makefile.
+ *
+ * Below is PJLIB's Makefile:
+ *
+ * \include build/Makefile
+ *
+ * @subsubsection pjlib_os_makefile_subsec PJLIB os-linux.mak.
+ *
+ * Below is file <tt><b>os-linux.mak</b></tt> file in
+ * <tt>$PJPROJECT/pjlib/build</tt> directory,
+ * which is OS specific configuration file for Linux target that is specific
+ * for PJLIB project. For \b global OS specific configuration, please see
+ * <tt>$PJPROJECT/build/os-*.mak</tt>.
+ *
+ * \include build/os-linux.mak
+ *
+ */
+
+
+/*////////////////////////////////////////////////////////////////////////// */
+/*
+ PORTING PJLIB
+ */
+
+
+
+/**
+ * @page porting_pjlib_pg Porting PJLIB
+ *
+ *
+ * @section new_arch_sec Porting to New CPU Architecture
+ *
+ * Below is step-by-step guide to add support for new CPU architecture.
+ * This sample is based on porting to Alpha architecture; however steps for
+ * porting to other CPU architectures should be pretty similar.
+ *
+ * Also note that in this example, the operating system used is <b>Linux</b>.
+ * Should you wish to add support for new operating system, then follow
+ * the next section \ref porting_os_sec.
+ *
+ * Step-by-step guide to port to new CPU architecture:
+ * - decide the name for the new architecture. In this case, we choose
+ * <tt><b>alpha</b></tt>.
+ * - edit file <tt>$PJPROJECT/build.mak</tt>, and add new section for
+ * the new target:
+ * <pre>
+ * #
+ * # Linux alpha, gcc
+ * #
+ * export MACHINE_NAME := <b>alpha</b>
+ * export OS_NAME := linux
+ * export CC_NAME := gcc
+ * export HOST_NAME := unix
+ * </pre>
+ *
+ * - create a new file <tt>$PJPROJECT/build/<b>m-alpha</b>.mak</tt>.
+ * Alternatively create a copy from other file in this directory.
+ * The contents of this file will look something like:
+ * <pre>
+ * export M_CFLAGS := $(CC_DEF)<b>PJ_M_ALPHA=1</b>
+ * export M_CXXFLAGS :=
+ * export M_LDFLAGS :=
+ * export M_SOURCES :=
+ * </pre>
+ * - create a new file <tt>$PJPROJECT/pjlib/include/pj/compat/<b>m_alpha.h</b></tt>.
+ * Alternatively create a copy from other header file in this directory.
+ * The contents of this file will look something like:
+ * <pre>
+ * #define PJ_HAS_PENTIUM 0
+ * #define PJ_IS_LITTLE_ENDIAN 1
+ * #define PJ_IS_BIG_ENDIAN 0
+ * </pre>
+ * - edit <tt>pjlib/include/pj/<b>config.h</b></tt>. Add new processor
+ * configuration in this header file, like follows:
+ * <pre>
+ * ...
+ * #elif defined (PJ_M_ALPHA) && PJ_M_ALPHA != 0
+ * # include <pj/compat/m_alpha.h>
+ * ...
+ * </pre>
+ * - done. Build PJLIB with:
+ * <pre>
+ * $ cd $PJPROJECT/pjlib/build
+ * $ make dep
+ * $ make clean
+ * $ make
+ * </pre>
+ *
+ * @section porting_os_sec Porting to New Operating System Target
+ *
+ * This section will try to give you rough guideline on how to
+ * port PJLIB to a new target. As a sample, we give the target a name tag,
+ * for example <tt><b>xos</b></tt> (for X OS).
+ *
+ * @subsection new_compat_os_h_file_sec Create New Compat Header File
+ *
+ * You'll need to create a new header file
+ * <b><tt>include/pj/compat/os_xos.h</tt></b>. You can copy as a
+ * template other header file and edit it accordingly.
+ *
+ * @subsection modify_config_h_file_sec Modify config.h
+ *
+ * Then modify file <b><tt>include/pj/config.h</tt></b> to include
+ * this file accordingly (e.g. when macro <tt><b>PJ_XOS</b></tt> is
+ * defined):
+ *
+ \verbatim
+ ...
+ #elif defined(PJ_XOS)
+ # include <pj/compat/os_xos.h>
+ #else
+ #...
+ \endverbatim
+ *
+ * @subsection new_target_mak_file_sec Create New Global Make Config File
+ *
+ * Then you'll need to create global configuration file that
+ * is specific for this OS, i.e. <tt><b>os-xos.mak</b></tt> in
+ * <tt><b>$PJPROJECT/build</b></tt> directory.
+ *
+ * At very minimum, the file will normally need to define
+ * <tt><b>PJ_XOS=1</b></tt> in the \c CFLAGS section:
+ *
+ \verbatim
+#
+# $PJPROJECT/build/os-xos.mak:
+#
+export OS_CFLAGS := $(CC_DEF)PJ_XOS=1
+export OS_CXXFLAGS :=
+export OS_LDFLAGS :=
+export OS_SOURCES :=
+ \endverbatim
+ *
+ *
+ * @subsection new_target_prj_mak_file_sec Create New Project's Make Config File
+ *
+ * Then you'll need to create xos-specific configuration file
+ * for PJLIB. This file is also named <tt><b>os-xos.mak</b></tt>,
+ * but its located in <tt><b>pjlib/build</b></tt> directory.
+ * This file will specify source files that are specific to
+ * this OS to be included in the build process.
+ *
+ * Below is a sample:
+ \verbatim
+#
+# pjlib/build/os-xos.mak:
+# XOS specific configuration for PJLIB.
+#
+export PJLIB_OBJS += os_core_xos.o \
+ os_error_unix.o \
+ os_time_ansi.o
+export TEST_OBJS += main.o
+export TARGETS = pjlib pjlib-test
+ \endverbatim
+ *
+ * @subsection new_target_src_sec Create and Edit Source Files
+ *
+ * You'll normally need to create at least these files:
+ * - <tt><b>os_core_xos.c</b></tt>: core OS specific
+ * functionality.
+ * - <tt><b>os_timestamp_xos.c</b></tt>: how to get timestamp
+ * in this OS.
+ *
+ * Depending on how things are done in your OS, you may need
+ * to create these files:
+ * - <tt><b>os_error_*.c</b></tt>: how to manipulate
+ * OS error codes. Alternatively you may use existing
+ * <tt>os_error_unix.c</tt> if the OS has \c errno and
+ * \c strerror() function.
+ * - <tt><b>ioqueue_*.c</b></tt>: if the OS has specific method
+ * to perform asynchronous I/O. Alternatively you may
+ * use existing <tt>ioqueue_select.c</tt> if the OS supports
+ * \c select() function call.
+ * - <tt><b>sock_*.c</b></tt>: if the OS has specific method
+ * to perform socket communication. Alternatively you may
+ * use existing <tt>sock_bsd.c</tt> if the OS supports
+ * BSD socket API, and edit <tt>include/pj/compat/socket.h</tt>
+ * file accordingly.
+ *
+ * You will also need to check various files in
+ * <tt><b>include/pj/compat/*.h</b></tt>, to see if they're
+ * compatible with your OS.
+ *
+ * @subsection new_target_build_file_sec Build The Project
+ *
+ * After basic building blocks have been created for the OS, then
+ * the easiest way to see which parts need to be fixed is by building
+ * the project and see the error messages.
+ *
+ * @subsection new_target_edit_vs_new_file_sec Editing Existing Files vs Creating New File
+ *
+ * When you encounter compatibility errors in PJLIB during porting,
+ * you have three options on how to fix the error:
+ * - edit the existing <tt>*.c</tt> file, and give it <tt>#ifdef</tt>
+ * switch for the new OS, or
+ * - edit <tt>include/pj/compat/*.h</tt> instead, or
+ * - create a totally new file.
+ *
+ * Basicly there is no strict rule on which approach is the best
+ * to use, however the following guidelines may be used:
+ * - if the file is expected to be completely different than
+ * any existing file, then perhaps you should create a completely
+ * new file. For example, file <tt>os_core_xxx.c</tt> will
+ * normally be different for each OS flavour.
+ * - if the difference can be localized in <tt>include/compat</tt>
+ * header file, and existing <tt>#ifdef</tt> switch is there,
+ * then preferably you should edit this <tt>include/compat</tt>
+ * header file.
+ * - if the existing <tt>*.c</tt> file has <tt>#ifdef</tt> switch,
+ * then you may add another <tt>#elif</tt> switch there. This
+ * normally is used for behaviors that are not totally
+ * different on each platform.
+ * - other than that above, use your own judgement on whether
+ * to edit the file or create new file etc.
+ */
+
+#endif /* __PJ_DOXYGEN_H__ */
+
diff --git a/pjlib/include/pj/equeue.h b/pjlib/include/pj/equeue.h index cc751e25..44979b0e 100644 --- a/pjlib/include/pj/equeue.h +++ b/pjlib/include/pj/equeue.h @@ -1,321 +1,342 @@ -/* $Id$ - * - */ -#ifndef __PJ_EQUEUE_H__ -#define __PJ_EQUEUE_H__ - -/** - * @file equeue.h - * @brief Event Queue - */ -#include <pj/types.h> - - -PJ_BEGIN_DECL - -/** - * @defgroup PJ_EQUEUE Event Queue - * @brief Event Queue - * @ingroup PJ_OS - * @{ - */ - - -/** - * Opaque data type for Event Queue. - */ -typedef struct pj_equeue_t pj_equeue_t; - -/** - * Opaque data type for Event Queue key. - */ -typedef struct pj_equeue_key_t pj_equeue_key_t; - - -/** - * This structure describes the callbacks to be called when I/O operation - * completes. - */ -typedef struct pj_io_callback -{ - /** - * This callback is called when #pj_equeue_read, #pj_equeue_recv or - * #pj_equeue_recvfrom completes. - * - * @param key The key. - * @param bytes_read The size of data that has just been read. - */ - void (*on_read_complete)(pj_equeue_key_t *key, pj_ssize_t bytes_read); - - /** - * This callback is called when #pj_equeue_write, #pj_equeue_send, or - * #pj_equeue_sendto completes. - * - * @param key The key. - * @param bytes_read The size of data that has just been written. - */ - void (*on_write_complete)(pj_equeue_key_t *key, pj_ssize_t bytes_sent); - - /** - * This callback is called when #pj_equeue_accept completes. - * - * @param key The key. - * @param status Zero if the operation completes successfully. - */ - void (*on_accept_complete)(pj_equeue_key_t *key, int status); - - /** - * This callback is called when #pj_equeue_connect completes. - * - * @param key The key. - * @param status Zero if the operation completes successfully. - */ - void (*on_connect_complete)(pj_equeue_key_t *key, int status); - -} pj_io_callback; - -/** - * Event Queue options. - */ -typedef struct pj_equeue_options -{ - /** Maximum number of threads that are allowed to access Event Queue - * simulteneously. - */ - unsigned nb_threads; - - /** If non-zero, then no mutex protection will be used. */ - pj_bool_t no_lock; - - /** Interval of the busy loop inside the event queue. - * The time resolution here determines the accuracy of the - * timer in the Event Queue. - */ - pj_time_val poll_interval; - -} pj_equeue_options; - - -/** - * Error value returned by I/O operations to indicate that the operation - * can't complete immediately and will complete later. - */ -#define PJ_EQUEUE_PENDING (-2) - -/** - * Types of Event Queue operation. - */ -typedef enum pj_equeue_op -{ - PJ_EQUEUE_OP_NONE = 0, /**< No operation. */ - PJ_EQUEUE_OP_READ = 1, /**< read() operation. */ - PJ_EQUEUE_OP_RECV_FROM = 2, /**< recvfrom() operation. */ - PJ_EQUEUE_OP_WRITE = 4, /**< write() operation. */ - PJ_EQUEUE_OP_SEND_TO = 8, /**< sendto() operation. */ -#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0 - PJ_EQUEUE_OP_ACCEPT = 16, /**< accept() operation. */ - PJ_EQUEUE_OP_CONNECT = 32, /**< connect() operation. */ -#endif /* PJ_HAS_TCP */ -} pj_equeue_op; - - - -/** - * Initialize Event Queue options with default values. - * - * @param options Event Queue options. - */ -PJ_DECL(void) pj_equeue_options_init(pj_equeue_options *options); - -/** - * Create a new Event Queue framework. - * - * @param pool The pool to allocate the event queue structure. - * @param options Event queue options, or if NULL is given, then - * default options will be used. - * @param equeue Pointer to receive event queue structure. - * - * @return zero on success. - */ -PJ_DECL(pj_status_t) pj_equeue_create( pj_pool_t *pool, - const pj_equeue_options *options, - pj_equeue_t **equeue); - -/** - * Get the first instance of Event Queue, or NULL if no Event Queue - * instance has been created in the application. - * - * @return The first instance of Event Queue created, or NULL. - */ -PJ_DECL(pj_equeue_t*) pj_equeue_instance(void); - -/** - * Destroy the Event Queue. - * - * @param equeue The Event Queue instance to be destroyed. - */ -PJ_DECL(pj_status_t) pj_equeue_destroy( pj_equeue_t *equeue ); - -/** - * Customize the lock object that is used by the Event Queue. - * - * @param equeue The Event Queue instance. - * @param lock The lock object. - * @param auto_del If non-zero, the lock will be destroyed by - * Event Queue. - * - * @return Zero on success. - */ -PJ_DECL(pj_status_t) pj_equeue_set_lock( pj_equeue_t *equeue, - pj_lock_t *lock, - pj_bool_t auto_del); - -/** - * Associate an Event Queue key to particular handle. The key is also - * associated with the callback and user data, which will be used by - * the Event Queue framework when signalling event back to application. - * - * @param pool To allocate the resource for the specified handle, which - * must be valid until the handle/key is unregistered - * from Event Queue. - * @param equeue The Event Queue. - * @param hnd The OS handle to be registered, which can be a socket - * descriptor (pj_sock_t), file descriptor, etc. - * @param cb Callback to be called when I/O operation completes. - * @param user_data User data to be associated with the key. - * @param key Pointer to receive the key. - * - * @return Zero on success. - */ -PJ_DECL(pj_status_t) pj_equeue_register( pj_pool_t *pool, - pj_equeue_t *equeue, - pj_oshandle_t hnd, - pj_io_callback *cb, - void *user_data, - pj_equeue_key_t **key); - -/** - * Retrieve user data associated with a key. - * - * @param key The Event Queue key. - * - * @return User data associated with the key. - */ -PJ_DECL(void*) pj_equeue_get_user_data( pj_equeue_key_t *key ); - - -/** - * Unregister Event Queue key from the Event Queue. - * - * @param equeue The Event Queue. - * @param key The key. - * - * @return Zero on success. - */ -PJ_DECL(pj_status_t) pj_equeue_unregister( pj_equeue_t *equeue, - pj_equeue_key_t *key); - -/** - * Instruct the Event Queue to read from the specified handle. This function - * returns immediately (i.e. non-blocking) regardless whether some data has - * been transfered. If the operation can't complete immediately, caller will - * be notified about the completion when it calls pj_equeue_poll(). - * - * @param key The key that uniquely identifies the handle. - * @param buffer The buffer to hold the read data. The caller MUST make sure - * that this buffer remain valid until the framework completes - * reading the handle. - * @param size The maximum size to be read. - * - * @return - * - zero or positive number to indicate the number of bytes has been - * read, and in this case the operation was not queued. - * - (-1) on error, which in this case operation was not queued. - * - PJ_EQUEUE_PENDING if the operation has been queued. - */ -PJ_DECL(pj_ssize_t) pj_equeue_read( pj_equeue_key_t *key, - void *buffer, - pj_size_t size); - -/** - * Start recv() operation on the specified handle. - * - * @see ::pj_ioqueue_read - */ -PJ_DECL(pj_ssize_t) pj_equeue_recv( pj_equeue_key_t *key, - void *buf, - pj_size_t size, - unsigned flags); - -/** - * Start recvfrom() operation on the specified handle. - * - * @see ::pj_equeue_read - */ -PJ_DECL(pj_ssize_t) pj_equeue_recvfrom( pj_equeue_key_t *key, - void *buf, - pj_size_t size, - unsigned flags, - pj_sockaddr_t *addr, - int *addrlen ); - -/** - * Write. - */ -PJ_DECL(pj_ssize_t) pj_equeue_write( pj_equeue_key_t *key, - const void *buf, - pj_size_t size); - -/** - * Send. - */ -PJ_DECL(pj_ssize_t) pj_equeue_send( pj_equeue_key_t *key, - const void *buf, - pj_size_t size, - unsigned flags); - -/** - * Sendto. - */ -PJ_DECL(pj_ssize_t) pj_equeue_sendto( pj_equeue_key_t *key, - const void *buf, - pj_size_t size, - unsigned flags, - const pj_sockaddr_t *addr, - int addrlen); - -/** - * Schedule timer. - */ -PJ_DECL(pj_status_t) pj_equeue_schedule_timer( pj_equeue_t *equeue, - const pj_time_val *timeout, - pj_timer_entry *entry); - -/** - * Cancel timer. - */ -PJ_DECL(pj_status_t) pj_equeue_cancel_timer( pj_equeue_t *equeue, - pj_timer_entry *entry); - -/** - * Poll for events. - */ -PJ_DECL(pj_status_t) pj_equeue_poll( pj_equeue_t *equeue, - const pj_time_val *timeout ); - -/** - * Run. - */ -PJ_DECL(pj_status_t) pj_equeue_run( pj_equeue_t *equeue ); - -/** - * Stop all running threads. - */ -PJ_DECL(pj_status_t) pj_equeue_stop( pj_equeue_t *equeue ); - - -/** @} */ - -PJ_END_DECL - -#endif /* __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
+ */
+#ifndef __PJ_EQUEUE_H__
+#define __PJ_EQUEUE_H__
+
+/**
+ * @file equeue.h
+ * @brief Event Queue
+ */
+#include <pj/types.h>
+
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup PJ_EQUEUE Event Queue
+ * @brief Event Queue
+ * @ingroup PJ_OS
+ * @{
+ */
+
+
+/**
+ * Opaque data type for Event Queue.
+ */
+typedef struct pj_equeue_t pj_equeue_t;
+
+/**
+ * Opaque data type for Event Queue key.
+ */
+typedef struct pj_equeue_key_t pj_equeue_key_t;
+
+
+/**
+ * This structure describes the callbacks to be called when I/O operation
+ * completes.
+ */
+typedef struct pj_io_callback
+{
+ /**
+ * This callback is called when #pj_equeue_read, #pj_equeue_recv or
+ * #pj_equeue_recvfrom completes.
+ *
+ * @param key The key.
+ * @param bytes_read The size of data that has just been read.
+ */
+ void (*on_read_complete)(pj_equeue_key_t *key, pj_ssize_t bytes_read);
+
+ /**
+ * This callback is called when #pj_equeue_write, #pj_equeue_send, or
+ * #pj_equeue_sendto completes.
+ *
+ * @param key The key.
+ * @param bytes_read The size of data that has just been written.
+ */
+ void (*on_write_complete)(pj_equeue_key_t *key, pj_ssize_t bytes_sent);
+
+ /**
+ * This callback is called when #pj_equeue_accept completes.
+ *
+ * @param key The key.
+ * @param status Zero if the operation completes successfully.
+ */
+ void (*on_accept_complete)(pj_equeue_key_t *key, int status);
+
+ /**
+ * This callback is called when #pj_equeue_connect completes.
+ *
+ * @param key The key.
+ * @param status Zero if the operation completes successfully.
+ */
+ void (*on_connect_complete)(pj_equeue_key_t *key, int status);
+
+} pj_io_callback;
+
+/**
+ * Event Queue options.
+ */
+typedef struct pj_equeue_options
+{
+ /** Maximum number of threads that are allowed to access Event Queue
+ * simulteneously.
+ */
+ unsigned nb_threads;
+
+ /** If non-zero, then no mutex protection will be used. */
+ pj_bool_t no_lock;
+
+ /** Interval of the busy loop inside the event queue.
+ * The time resolution here determines the accuracy of the
+ * timer in the Event Queue.
+ */
+ pj_time_val poll_interval;
+
+} pj_equeue_options;
+
+
+/**
+ * Error value returned by I/O operations to indicate that the operation
+ * can't complete immediately and will complete later.
+ */
+#define PJ_EQUEUE_PENDING (-2)
+
+/**
+ * Types of Event Queue operation.
+ */
+typedef enum pj_equeue_op
+{
+ PJ_EQUEUE_OP_NONE = 0, /**< No operation. */
+ PJ_EQUEUE_OP_READ = 1, /**< read() operation. */
+ PJ_EQUEUE_OP_RECV_FROM = 2, /**< recvfrom() operation. */
+ PJ_EQUEUE_OP_WRITE = 4, /**< write() operation. */
+ PJ_EQUEUE_OP_SEND_TO = 8, /**< sendto() operation. */
+#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
+ PJ_EQUEUE_OP_ACCEPT = 16, /**< accept() operation. */
+ PJ_EQUEUE_OP_CONNECT = 32, /**< connect() operation. */
+#endif /* PJ_HAS_TCP */
+} pj_equeue_op;
+
+
+
+/**
+ * Initialize Event Queue options with default values.
+ *
+ * @param options Event Queue options.
+ */
+PJ_DECL(void) pj_equeue_options_init(pj_equeue_options *options);
+
+/**
+ * Create a new Event Queue framework.
+ *
+ * @param pool The pool to allocate the event queue structure.
+ * @param options Event queue options, or if NULL is given, then
+ * default options will be used.
+ * @param equeue Pointer to receive event queue structure.
+ *
+ * @return zero on success.
+ */
+PJ_DECL(pj_status_t) pj_equeue_create( pj_pool_t *pool,
+ const pj_equeue_options *options,
+ pj_equeue_t **equeue);
+
+/**
+ * Get the first instance of Event Queue, or NULL if no Event Queue
+ * instance has been created in the application.
+ *
+ * @return The first instance of Event Queue created, or NULL.
+ */
+PJ_DECL(pj_equeue_t*) pj_equeue_instance(void);
+
+/**
+ * Destroy the Event Queue.
+ *
+ * @param equeue The Event Queue instance to be destroyed.
+ */
+PJ_DECL(pj_status_t) pj_equeue_destroy( pj_equeue_t *equeue );
+
+/**
+ * Customize the lock object that is used by the Event Queue.
+ *
+ * @param equeue The Event Queue instance.
+ * @param lock The lock object.
+ * @param auto_del If non-zero, the lock will be destroyed by
+ * Event Queue.
+ *
+ * @return Zero on success.
+ */
+PJ_DECL(pj_status_t) pj_equeue_set_lock( pj_equeue_t *equeue,
+ pj_lock_t *lock,
+ pj_bool_t auto_del);
+
+/**
+ * Associate an Event Queue key to particular handle. The key is also
+ * associated with the callback and user data, which will be used by
+ * the Event Queue framework when signalling event back to application.
+ *
+ * @param pool To allocate the resource for the specified handle, which
+ * must be valid until the handle/key is unregistered
+ * from Event Queue.
+ * @param equeue The Event Queue.
+ * @param hnd The OS handle to be registered, which can be a socket
+ * descriptor (pj_sock_t), file descriptor, etc.
+ * @param cb Callback to be called when I/O operation completes.
+ * @param user_data User data to be associated with the key.
+ * @param key Pointer to receive the key.
+ *
+ * @return Zero on success.
+ */
+PJ_DECL(pj_status_t) pj_equeue_register( pj_pool_t *pool,
+ pj_equeue_t *equeue,
+ pj_oshandle_t hnd,
+ pj_io_callback *cb,
+ void *user_data,
+ pj_equeue_key_t **key);
+
+/**
+ * Retrieve user data associated with a key.
+ *
+ * @param key The Event Queue key.
+ *
+ * @return User data associated with the key.
+ */
+PJ_DECL(void*) pj_equeue_get_user_data( pj_equeue_key_t *key );
+
+
+/**
+ * Unregister Event Queue key from the Event Queue.
+ *
+ * @param equeue The Event Queue.
+ * @param key The key.
+ *
+ * @return Zero on success.
+ */
+PJ_DECL(pj_status_t) pj_equeue_unregister( pj_equeue_t *equeue,
+ pj_equeue_key_t *key);
+
+/**
+ * Instruct the Event Queue to read from the specified handle. This function
+ * returns immediately (i.e. non-blocking) regardless whether some data has
+ * been transfered. If the operation can't complete immediately, caller will
+ * be notified about the completion when it calls pj_equeue_poll().
+ *
+ * @param key The key that uniquely identifies the handle.
+ * @param buffer The buffer to hold the read data. The caller MUST make sure
+ * that this buffer remain valid until the framework completes
+ * reading the handle.
+ * @param size The maximum size to be read.
+ *
+ * @return
+ * - zero or positive number to indicate the number of bytes has been
+ * read, and in this case the operation was not queued.
+ * - (-1) on error, which in this case operation was not queued.
+ * - PJ_EQUEUE_PENDING if the operation has been queued.
+ */
+PJ_DECL(pj_ssize_t) pj_equeue_read( pj_equeue_key_t *key,
+ void *buffer,
+ pj_size_t size);
+
+/**
+ * Start recv() operation on the specified handle.
+ *
+ * @see ::pj_ioqueue_read
+ */
+PJ_DECL(pj_ssize_t) pj_equeue_recv( pj_equeue_key_t *key,
+ void *buf,
+ pj_size_t size,
+ unsigned flags);
+
+/**
+ * Start recvfrom() operation on the specified handle.
+ *
+ * @see ::pj_equeue_read
+ */
+PJ_DECL(pj_ssize_t) pj_equeue_recvfrom( pj_equeue_key_t *key,
+ void *buf,
+ pj_size_t size,
+ unsigned flags,
+ pj_sockaddr_t *addr,
+ int *addrlen );
+
+/**
+ * Write.
+ */
+PJ_DECL(pj_ssize_t) pj_equeue_write( pj_equeue_key_t *key,
+ const void *buf,
+ pj_size_t size);
+
+/**
+ * Send.
+ */
+PJ_DECL(pj_ssize_t) pj_equeue_send( pj_equeue_key_t *key,
+ const void *buf,
+ pj_size_t size,
+ unsigned flags);
+
+/**
+ * Sendto.
+ */
+PJ_DECL(pj_ssize_t) pj_equeue_sendto( pj_equeue_key_t *key,
+ const void *buf,
+ pj_size_t size,
+ unsigned flags,
+ const pj_sockaddr_t *addr,
+ int addrlen);
+
+/**
+ * Schedule timer.
+ */
+PJ_DECL(pj_status_t) pj_equeue_schedule_timer( pj_equeue_t *equeue,
+ const pj_time_val *timeout,
+ pj_timer_entry *entry);
+
+/**
+ * Cancel timer.
+ */
+PJ_DECL(pj_status_t) pj_equeue_cancel_timer( pj_equeue_t *equeue,
+ pj_timer_entry *entry);
+
+/**
+ * Poll for events.
+ */
+PJ_DECL(pj_status_t) pj_equeue_poll( pj_equeue_t *equeue,
+ const pj_time_val *timeout );
+
+/**
+ * Run.
+ */
+PJ_DECL(pj_status_t) pj_equeue_run( pj_equeue_t *equeue );
+
+/**
+ * Stop all running threads.
+ */
+PJ_DECL(pj_status_t) pj_equeue_stop( pj_equeue_t *equeue );
+
+
+/** @} */
+
+PJ_END_DECL
+
+#endif /* __PJ_EQUEUE_H__ */
diff --git a/pjlib/include/pj/errno.h b/pjlib/include/pj/errno.h index b7c62533..741475fa 100644 --- a/pjlib/include/pj/errno.h +++ b/pjlib/include/pj/errno.h @@ -1,215 +1,236 @@ -/* $Id$ - * - */ -#ifndef __PJ_ERRNO_H__ -#define __PJ_ERRNO_H__ - -/** - * @file errno.h - * @brief PJLIB Error Codes - */ -#include <pj/types.h> -#include <pj/compat/errno.h> - -PJ_BEGIN_DECL - -/** - * @defgroup pj_errno Error Codes - * @ingroup PJ - * @{ - * - * In PJLIB, error/status codes from operating system are translated - * into PJLIB error namespace, and stored in @a pj_status_t. All functions - * that work with @a pj_status_t expect to get PJLIB error code instead - * of native codes. - * - * @section pj_errno_retval Return Values - * - * All functions that returns @a pj_status_t returns @a PJ_SUCCESS if the - * operation was completed successfully, or non-zero value to indicate - * error. If the error came from operating system, then the native error - * code is translated/folded into PJLIB's error namespace by using - * #PJ_STATUS_FROM_OS() macro. The function will do this automatically - * before returning the error to caller. - * - * @section pj_errno_errmsg Error Message - * - * To get the error message corresponding to a particular code, use function - * #pj_strerror(). This function expects error code in PJLIB error namespace, - * not the native error code. Application can pass the value from the - * following sources to this function: - * - #pj_get_os_error() - * - #pj_get_netos_error() - * - any return value from function returning @a pj_status_t. - * - * Application MUST NOT pass native error code (such as error code from - * functions like GetLastError() or errno) to PJLIB functions expecting - * @a pj_status_t. - * - */ - -/** - * Get the last platform error/status, folded into pj_status_t. - * @return OS dependent error code, folded into pj_status_t. - * @remark This function gets errno, or calls GetLastError() function and - * convert the code into pj_status_t with PJ_STATUS_FROM_OS. Do - * not call this for socket functions! - * @see pj_get_netos_error() - */ -PJ_DECL(pj_status_t) pj_get_os_error(void); - -/** - * Set last error. - * @param code pj_status_t - */ -PJ_DECL(void) pj_set_os_error(pj_status_t code); - -/** - * Get the last error from socket operations. - * @return Last socket error, folded into pj_status_t. - */ -PJ_DECL(pj_status_t) pj_get_netos_error(void); - -/** - * Set error code. - * @param code pj_status_t. - */ -PJ_DECL(void) pj_set_netos_error(pj_status_t code); - - -/** - * Get the error message for the specified error code. The message - * string will be NULL terminated. - * - * @param statcode The error code. - * @param buf Buffer to hold the error message string. - * @param bufsize Size of the buffer. - * - * @return The error message as NULL terminated string, - * wrapped with pj_str_t. - */ -PJ_DECL(pj_str_t) pj_strerror( pj_status_t statcode, - char *buf, pj_size_t bufsize); - - -/** - * @hideinitializer - * Return platform os error code folded into pj_status_t code. This is - * the macro that is used throughout the library for all PJLIB's functions - * that returns error from operating system. Application may override - * this macro to reduce size (e.g. by defining it to always return - * #PJ_EUNKNOWN). - * - * Note: - * This macro MUST return non-zero value regardless whether zero is - * passed as the argument. The reason is to protect logic error when - * the operating system doesn't report error codes properly. - * - * @param os_code Platform OS error code. This value may be evaluated - * more than once. - * @return The platform os error code folded into pj_status_t. - */ -#ifndef PJ_RETURN_OS_ERROR -# define PJ_RETURN_OS_ERROR(os_code) (os_code ? \ - PJ_STATUS_FROM_OS(os_code) : -1) -#endif - - -/** - * @hideinitializer - * Fold a platform specific error into an pj_status_t code. - * - * @param e The platform os error code. - * @return pj_status_t - * @warning Macro implementation; the syserr argument may be evaluated - * multiple times. - */ -#define PJ_STATUS_FROM_OS(e) (e == 0 ? PJ_SUCCESS : e + PJ_ERRNO_START_SYS) - -/** - * @hideinitializer - * Fold an pj_status_t code back to the native platform defined error. - * - * @param e The pj_status_t folded platform os error code. - * @return pj_os_err_type - * @warning macro implementation; the statcode argument may be evaluated - * multiple times. If the statcode was not created by - * pj_get_os_error or PJ_STATUS_FROM_OS, the results are undefined. - */ -#define PJ_STATUS_TO_OS(e) (e == 0 ? PJ_SUCCESS : e - PJ_ERRNO_START_SYS) - - -/** - * @defgroup pj_errnum PJLIB's Own Error Codes - * @ingroup pj_errno - * @{ - */ - -/** - * @hideinitializer - * Unknown error has been reported. - */ -#define PJ_EUNKNOWN (PJ_ERRNO_START_STATUS + 1) -/** - * @hideinitializer - * The operation is pending and will be completed later. - */ -#define PJ_EPENDING (PJ_ERRNO_START_STATUS + 2) -/** - * @hideinitializer - * Too many connecting sockets. - */ -#define PJ_ETOOMANYCONN (PJ_ERRNO_START_STATUS + 3) -/** - * @hideinitializer - * Invalid argument. - */ -#define PJ_EINVAL (PJ_ERRNO_START_STATUS + 4) -/** - * @hideinitializer - * Name too long (eg. hostname too long). - */ -#define PJ_ENAMETOOLONG (PJ_ERRNO_START_STATUS + 5) -/** - * @hideinitializer - * Not found. - */ -#define PJ_ENOTFOUND (PJ_ERRNO_START_STATUS + 6) -/** - * @hideinitializer - * Not enough memory. - */ -#define PJ_ENOMEM (PJ_ERRNO_START_STATUS + 7) -/** - * @hideinitializer - * Bug detected! - */ -#define PJ_EBUG (PJ_ERRNO_START_STATUS + 8) -/** - * @hideinitializer - * Operation timed out. - */ -#define PJ_ETIMEDOUT (PJ_ERRNO_START_STATUS + 9) -/** - * @hideinitializer - * Too many objects. - */ -#define PJ_ETOOMANY (PJ_ERRNO_START_STATUS + 10) -/** - * @hideinitializer - * Object is busy. - */ -#define PJ_EBUSY (PJ_ERRNO_START_STATUS + 11) -/** - * @hideinitializer - * The specified option is not supported. - */ -#define PJ_ENOTSUP (PJ_ERRNO_START_STATUS + 12) -/** - * @hideinitializer - * Invalid operation. - */ -#define PJ_EINVALIDOP (PJ_ERRNO_START_STATUS + 13) +/* $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 __PJ_ERRNO_H__
+#define __PJ_ERRNO_H__
+
+/**
+ * @file errno.h
+ * @brief PJLIB Error Codes
+ */
+#include <pj/types.h>
+#include <pj/compat/errno.h>
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup pj_errno Error Codes
+ * @ingroup PJ
+ * @{
+ *
+ * In PJLIB, error/status codes from operating system are translated
+ * into PJLIB error namespace, and stored in @a pj_status_t. All functions
+ * that work with @a pj_status_t expect to get PJLIB error code instead
+ * of native codes.
+ *
+ * @section pj_errno_retval Return Values
+ *
+ * All functions that returns @a pj_status_t returns @a PJ_SUCCESS if the
+ * operation was completed successfully, or non-zero value to indicate
+ * error. If the error came from operating system, then the native error
+ * code is translated/folded into PJLIB's error namespace by using
+ * #PJ_STATUS_FROM_OS() macro. The function will do this automatically
+ * before returning the error to caller.
+ *
+ * @section pj_errno_errmsg Error Message
+ *
+ * To get the error message corresponding to a particular code, use function
+ * #pj_strerror(). This function expects error code in PJLIB error namespace,
+ * not the native error code. Application can pass the value from the
+ * following sources to this function:
+ * - #pj_get_os_error()
+ * - #pj_get_netos_error()
+ * - any return value from function returning @a pj_status_t.
+ *
+ * Application MUST NOT pass native error code (such as error code from
+ * functions like GetLastError() or errno) to PJLIB functions expecting
+ * @a pj_status_t.
+ *
+ */
+
+/**
+ * Get the last platform error/status, folded into pj_status_t.
+ * @return OS dependent error code, folded into pj_status_t.
+ * @remark This function gets errno, or calls GetLastError() function and
+ * convert the code into pj_status_t with PJ_STATUS_FROM_OS. Do
+ * not call this for socket functions!
+ * @see pj_get_netos_error()
+ */
+PJ_DECL(pj_status_t) pj_get_os_error(void);
+
+/**
+ * Set last error.
+ * @param code pj_status_t
+ */
+PJ_DECL(void) pj_set_os_error(pj_status_t code);
+
+/**
+ * Get the last error from socket operations.
+ * @return Last socket error, folded into pj_status_t.
+ */
+PJ_DECL(pj_status_t) pj_get_netos_error(void);
+
+/**
+ * Set error code.
+ * @param code pj_status_t.
+ */
+PJ_DECL(void) pj_set_netos_error(pj_status_t code);
+
+
+/**
+ * Get the error message for the specified error code. The message
+ * string will be NULL terminated.
+ *
+ * @param statcode The error code.
+ * @param buf Buffer to hold the error message string.
+ * @param bufsize Size of the buffer.
+ *
+ * @return The error message as NULL terminated string,
+ * wrapped with pj_str_t.
+ */
+PJ_DECL(pj_str_t) pj_strerror( pj_status_t statcode,
+ char *buf, pj_size_t bufsize);
+
+
+/**
+ * @hideinitializer
+ * Return platform os error code folded into pj_status_t code. This is
+ * the macro that is used throughout the library for all PJLIB's functions
+ * that returns error from operating system. Application may override
+ * this macro to reduce size (e.g. by defining it to always return
+ * #PJ_EUNKNOWN).
+ *
+ * Note:
+ * This macro MUST return non-zero value regardless whether zero is
+ * passed as the argument. The reason is to protect logic error when
+ * the operating system doesn't report error codes properly.
+ *
+ * @param os_code Platform OS error code. This value may be evaluated
+ * more than once.
+ * @return The platform os error code folded into pj_status_t.
+ */
+#ifndef PJ_RETURN_OS_ERROR
+# define PJ_RETURN_OS_ERROR(os_code) (os_code ? \
+ PJ_STATUS_FROM_OS(os_code) : -1)
+#endif
+
+
+/**
+ * @hideinitializer
+ * Fold a platform specific error into an pj_status_t code.
+ *
+ * @param e The platform os error code.
+ * @return pj_status_t
+ * @warning Macro implementation; the syserr argument may be evaluated
+ * multiple times.
+ */
+#define PJ_STATUS_FROM_OS(e) (e == 0 ? PJ_SUCCESS : e + PJ_ERRNO_START_SYS)
+
+/**
+ * @hideinitializer
+ * Fold an pj_status_t code back to the native platform defined error.
+ *
+ * @param e The pj_status_t folded platform os error code.
+ * @return pj_os_err_type
+ * @warning macro implementation; the statcode argument may be evaluated
+ * multiple times. If the statcode was not created by
+ * pj_get_os_error or PJ_STATUS_FROM_OS, the results are undefined.
+ */
+#define PJ_STATUS_TO_OS(e) (e == 0 ? PJ_SUCCESS : e - PJ_ERRNO_START_SYS)
+
+
+/**
+ * @defgroup pj_errnum PJLIB's Own Error Codes
+ * @ingroup pj_errno
+ * @{
+ */
+
+/**
+ * @hideinitializer
+ * Unknown error has been reported.
+ */
+#define PJ_EUNKNOWN (PJ_ERRNO_START_STATUS + 1)
+/**
+ * @hideinitializer
+ * The operation is pending and will be completed later.
+ */
+#define PJ_EPENDING (PJ_ERRNO_START_STATUS + 2)
+/**
+ * @hideinitializer
+ * Too many connecting sockets.
+ */
+#define PJ_ETOOMANYCONN (PJ_ERRNO_START_STATUS + 3)
+/**
+ * @hideinitializer
+ * Invalid argument.
+ */
+#define PJ_EINVAL (PJ_ERRNO_START_STATUS + 4)
+/**
+ * @hideinitializer
+ * Name too long (eg. hostname too long).
+ */
+#define PJ_ENAMETOOLONG (PJ_ERRNO_START_STATUS + 5)
+/**
+ * @hideinitializer
+ * Not found.
+ */
+#define PJ_ENOTFOUND (PJ_ERRNO_START_STATUS + 6)
+/**
+ * @hideinitializer
+ * Not enough memory.
+ */
+#define PJ_ENOMEM (PJ_ERRNO_START_STATUS + 7)
+/**
+ * @hideinitializer
+ * Bug detected!
+ */
+#define PJ_EBUG (PJ_ERRNO_START_STATUS + 8)
+/**
+ * @hideinitializer
+ * Operation timed out.
+ */
+#define PJ_ETIMEDOUT (PJ_ERRNO_START_STATUS + 9)
+/**
+ * @hideinitializer
+ * Too many objects.
+ */
+#define PJ_ETOOMANY (PJ_ERRNO_START_STATUS + 10)
+/**
+ * @hideinitializer
+ * Object is busy.
+ */
+#define PJ_EBUSY (PJ_ERRNO_START_STATUS + 11)
+/**
+ * @hideinitializer
+ * The specified option is not supported.
+ */
+#define PJ_ENOTSUP (PJ_ERRNO_START_STATUS + 12)
+/**
+ * @hideinitializer
+ * Invalid operation.
+ */
+#define PJ_EINVALIDOP (PJ_ERRNO_START_STATUS + 13)
/**
* @hideinitializer
* Operation is cancelled.
@@ -220,42 +241,42 @@ PJ_DECL(pj_str_t) pj_strerror( pj_status_t statcode, * Object already exists.
*/
#define PJ_EEXISTS (PJ_ERRNO_START_STATUS + 14)
- -/** @} */ /* pj_errnum */ - -/** @} */ /* pj_errno */ - - -/** - * PJ_ERRNO_START is where PJLIB specific error values start. - */ -#define PJ_ERRNO_START 20000 - -/** - * PJ_ERRNO_SPACE_SIZE is the maximum number of errors in one of - * the error/status range below. - */ -#define PJ_ERRNO_SPACE_SIZE 50000 - -/** - * PJ_ERRNO_START_STATUS is where PJLIB specific status codes start. - */ -#define PJ_ERRNO_START_STATUS (PJ_ERRNO_START + PJ_ERRNO_SPACE_SIZE) - -/** - * PJ_ERRNO_START_SYS converts platform specific error codes into - * pj_status_t values. - */ -#define PJ_ERRNO_START_SYS (PJ_ERRNO_START_STATUS + PJ_ERRNO_SPACE_SIZE) - -/** - * PJ_ERRNO_START_USER are reserved for applications that use error - * codes along with PJLIB codes. - */ -#define PJ_ERRNO_START_USER (PJ_ERRNO_START_SYS + PJ_ERRNO_SPACE_SIZE) - - -PJ_END_DECL - -#endif /* __PJ_ERRNO_H__ */ - +
+/** @} */ /* pj_errnum */
+
+/** @} */ /* pj_errno */
+
+
+/**
+ * PJ_ERRNO_START is where PJLIB specific error values start.
+ */
+#define PJ_ERRNO_START 20000
+
+/**
+ * PJ_ERRNO_SPACE_SIZE is the maximum number of errors in one of
+ * the error/status range below.
+ */
+#define PJ_ERRNO_SPACE_SIZE 50000
+
+/**
+ * PJ_ERRNO_START_STATUS is where PJLIB specific status codes start.
+ */
+#define PJ_ERRNO_START_STATUS (PJ_ERRNO_START + PJ_ERRNO_SPACE_SIZE)
+
+/**
+ * PJ_ERRNO_START_SYS converts platform specific error codes into
+ * pj_status_t values.
+ */
+#define PJ_ERRNO_START_SYS (PJ_ERRNO_START_STATUS + PJ_ERRNO_SPACE_SIZE)
+
+/**
+ * PJ_ERRNO_START_USER are reserved for applications that use error
+ * codes along with PJLIB codes.
+ */
+#define PJ_ERRNO_START_USER (PJ_ERRNO_START_SYS + PJ_ERRNO_SPACE_SIZE)
+
+
+PJ_END_DECL
+
+#endif /* __PJ_ERRNO_H__ */
+
diff --git a/pjlib/include/pj/except.h b/pjlib/include/pj/except.h index 8bdda480..0405c69b 100644 --- a/pjlib/include/pj/except.h +++ b/pjlib/include/pj/except.h @@ -1,270 +1,291 @@ -/* $Id$ - * - */ - -#ifndef __PJ_EXCEPTION_H__ -#define __PJ_EXCEPTION_H__ - -/** - * @file except.h - * @brief Exception Handling in C. - */ - -#include <pj/types.h> -#include <pj/compat/setjmp.h> - - -PJ_BEGIN_DECL - - -/** - * @defgroup PJ_EXCEPT Exception Handling - * @ingroup PJ_MISC - * @{ - * - * \section pj_except_sample_sec Quick Example - * - * For the impatient, take a look at some examples: - * - @ref page_pjlib_samples_except_c - * - @ref page_pjlib_exception_test - * - * \section pj_except_except Exception Handling - * - * This module provides exception handling syntactically similar to C++ in - * C language. The underlying mechanism use setjmp() and longjmp(), and since - * these constructs are ANSI standard, the mechanism here should be available - * on most platforms/compilers which are ANSI compliant. - * - * If ANSI libc is not available, then setjmp()/longjmp() implementation will - * be provided. See <pj/compat/setjmp.h> for compatibility. - * - * The exception handling mechanism is completely thread safe, so the exception - * thrown by one thread will not interfere with other thread. - * - * CAVEATS: - * - unlike C++ exception, the scheme here won't call destructors of local - * objects if exception is thrown. Care must be taken when a function - * hold some resorce such as pool or mutex etc. - * - You CAN NOT make nested exception in one single function without using - * a nested PJ_USE_EXCEPTION. - * - Exceptions will always be caught by the first handle (unlike C++ where - * exception is only caught if the type matches. - * - * The exception handling constructs are similar to C++. The blocks will be - * constructed similar to the following sample: - * - * \verbatim - #define NO_MEMORY 1 - #define SYNTAX_ERROR 2 - - int main() - { - PJ_USE_EXCEPTION; // declare local exception stack. - - PJ_TRY { - ...// do something.. - } - PJ_CATCH(NO_MEMORY) { - ... // handle exception 1 - } - PJ_CATCH(SYNTAX_ERROR) { - ... // handle exception 2 - } - PJ_DEFAULT { - ... // handle other exceptions. - } - PJ_END; - } - \endverbatim - * - * The above sample uses hard coded exception ID. It is @b strongly - * recommended that applications request a unique exception ID instead - * of hard coded value like above. - * - * \section pj_except_reg Exception ID Allocation - * - * To ensure that exception ID (number) are used consistently and to - * prevent ID collisions in an application, it is strongly suggested that - * applications allocate an exception ID for each possible exception - * type. As a bonus of this process, the application can identify - * the name of the exception when the particular exception is thrown. - * - * Exception ID management are performed with the following APIs: - * - #pj_exception_id_alloc(). - * - #pj_exception_id_free(). - * - #pj_exception_id_name(). - * - * - * PJLIB itself automatically allocates one exception id, i.e. - * #PJ_NO_MEMORY_EXCEPTION which is declared in <pj/pool.h>. This exception - * ID is raised by default pool policy when it fails to allocate memory. - * - * \section PJ_EX_KEYWORDS Keywords - * - * \subsection PJ_THROW PJ_THROW(expression) - * Throw an exception. The expression thrown is an integer as the result of - * the \a expression. This keyword can be specified anywhere within the - * program. - * - * \subsection PJ_USE_EXCEPTION PJ_USE_EXCEPTION - * Specify this in the variable definition section of the function block - * (or any blocks) to specify that the block has \a PJ_TRY/PJ_CATCH exception - * block. - * Actually, this is just a macro to declare local variable which is used to - * push the exception state to the exception stack. - * - * \subsection PJ_TRY PJ_TRY - * The \a PJ_TRY keyword is typically followed by a block. If an exception is - * thrown in this block, then the execution will resume to the \a PJ_CATCH - * handler. - * - * \subsection PJ_CATCH PJ_CATCH(expression) - * The \a PJ_CATCH is normally followed by a block. This block will be executed - * if the exception being thrown is equal to the expression specified in the - * \a PJ_CATCH. - * - * \subsection PJ_DEFAULT PJ_DEFAULT - * The \a PJ_DEFAULT keyword is normally followed by a block. This block will - * be executed if the exception being thrown doesn't match any of the \a - * PJ_CATCH specification. The \a PJ_DEFAULT block \b MUST be placed as the - * last block of the handlers. - * - * \subsection PJ_END PJ_END - * Specify this keyword to mark the end of \a PJ_TRY / \a PJ_CATCH blocks. - * - * \subsection PJ_GET_EXCEPTION PJ_GET_EXCEPTION(void) - * Get the last exception thrown. This macro is normally called inside the - * \a PJ_CATCH or \a PJ_DEFAULT block, altough it can be used anywhere where - * the \a PJ_USE_EXCEPTION definition is in scope. - * - * - * \section pj_except_examples_sec Examples - * - * For some examples on how to use the exception construct, please see: - * - @ref page_pjlib_samples_except_c - * - @ref page_pjlib_exception_test - */ - -/** - * Allocate a unique exception id. - * Applications don't have to allocate a unique exception ID before using - * the exception construct. However, by doing so it ensures that there is - * no collisions of exception ID. - * - * As a bonus, when exception number is acquired through this function, - * the library can assign name to the exception (only if - * PJ_HAS_EXCEPTION_NAMES is enabled (default is yes)) and find out the - * exception name when it catches an exception. - * - * @param name Name to be associated with the exception ID. - * @param id Pointer to receive the ID. - * - * @return PJ_SUCCESS on success or PJ_ETOOMANY if the library - * is running out out ids. - */ -PJ_DECL(pj_status_t) pj_exception_id_alloc(const char *name, - pj_exception_id_t *id); - -/** - * Free an exception id. - * - * @param id The exception ID. - * - * @return PJ_SUCCESS or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_exception_id_free(pj_exception_id_t id); - -/** - * Retrieve name associated with the exception id. - * - * @param id The exception ID. - * - * @return The name associated with the specified ID. - */ -PJ_DECL(const char*) pj_exception_id_name(pj_exception_id_t id); +/* $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 __PJ_EXCEPTION_H__
+#define __PJ_EXCEPTION_H__
+
+/**
+ * @file except.h
+ * @brief Exception Handling in C.
+ */
+
+#include <pj/types.h>
+#include <pj/compat/setjmp.h>
+
+
+PJ_BEGIN_DECL
+
+
+/**
+ * @defgroup PJ_EXCEPT Exception Handling
+ * @ingroup PJ_MISC
+ * @{
+ *
+ * \section pj_except_sample_sec Quick Example
+ *
+ * For the impatient, take a look at some examples:
+ * - @ref page_pjlib_samples_except_c
+ * - @ref page_pjlib_exception_test
+ *
+ * \section pj_except_except Exception Handling
+ *
+ * This module provides exception handling syntactically similar to C++ in
+ * C language. The underlying mechanism use setjmp() and longjmp(), and since
+ * these constructs are ANSI standard, the mechanism here should be available
+ * on most platforms/compilers which are ANSI compliant.
+ *
+ * If ANSI libc is not available, then setjmp()/longjmp() implementation will
+ * be provided. See <pj/compat/setjmp.h> for compatibility.
+ *
+ * The exception handling mechanism is completely thread safe, so the exception
+ * thrown by one thread will not interfere with other thread.
+ *
+ * CAVEATS:
+ * - unlike C++ exception, the scheme here won't call destructors of local
+ * objects if exception is thrown. Care must be taken when a function
+ * hold some resorce such as pool or mutex etc.
+ * - You CAN NOT make nested exception in one single function without using
+ * a nested PJ_USE_EXCEPTION.
+ * - Exceptions will always be caught by the first handle (unlike C++ where
+ * exception is only caught if the type matches.
+ *
+ * The exception handling constructs are similar to C++. The blocks will be
+ * constructed similar to the following sample:
+ *
+ * \verbatim
+ #define NO_MEMORY 1
+ #define SYNTAX_ERROR 2
+
+ int main()
+ {
+ PJ_USE_EXCEPTION; // declare local exception stack.
+
+ PJ_TRY {
+ ...// do something..
+ }
+ PJ_CATCH(NO_MEMORY) {
+ ... // handle exception 1
+ }
+ PJ_CATCH(SYNTAX_ERROR) {
+ ... // handle exception 2
+ }
+ PJ_DEFAULT {
+ ... // handle other exceptions.
+ }
+ PJ_END;
+ }
+ \endverbatim
+ *
+ * The above sample uses hard coded exception ID. It is @b strongly
+ * recommended that applications request a unique exception ID instead
+ * of hard coded value like above.
+ *
+ * \section pj_except_reg Exception ID Allocation
+ *
+ * To ensure that exception ID (number) are used consistently and to
+ * prevent ID collisions in an application, it is strongly suggested that
+ * applications allocate an exception ID for each possible exception
+ * type. As a bonus of this process, the application can identify
+ * the name of the exception when the particular exception is thrown.
+ *
+ * Exception ID management are performed with the following APIs:
+ * - #pj_exception_id_alloc().
+ * - #pj_exception_id_free().
+ * - #pj_exception_id_name().
+ *
+ *
+ * PJLIB itself automatically allocates one exception id, i.e.
+ * #PJ_NO_MEMORY_EXCEPTION which is declared in <pj/pool.h>. This exception
+ * ID is raised by default pool policy when it fails to allocate memory.
+ *
+ * \section PJ_EX_KEYWORDS Keywords
+ *
+ * \subsection PJ_THROW PJ_THROW(expression)
+ * Throw an exception. The expression thrown is an integer as the result of
+ * the \a expression. This keyword can be specified anywhere within the
+ * program.
+ *
+ * \subsection PJ_USE_EXCEPTION PJ_USE_EXCEPTION
+ * Specify this in the variable definition section of the function block
+ * (or any blocks) to specify that the block has \a PJ_TRY/PJ_CATCH exception
+ * block.
+ * Actually, this is just a macro to declare local variable which is used to
+ * push the exception state to the exception stack.
+ *
+ * \subsection PJ_TRY PJ_TRY
+ * The \a PJ_TRY keyword is typically followed by a block. If an exception is
+ * thrown in this block, then the execution will resume to the \a PJ_CATCH
+ * handler.
+ *
+ * \subsection PJ_CATCH PJ_CATCH(expression)
+ * The \a PJ_CATCH is normally followed by a block. This block will be executed
+ * if the exception being thrown is equal to the expression specified in the
+ * \a PJ_CATCH.
+ *
+ * \subsection PJ_DEFAULT PJ_DEFAULT
+ * The \a PJ_DEFAULT keyword is normally followed by a block. This block will
+ * be executed if the exception being thrown doesn't match any of the \a
+ * PJ_CATCH specification. The \a PJ_DEFAULT block \b MUST be placed as the
+ * last block of the handlers.
+ *
+ * \subsection PJ_END PJ_END
+ * Specify this keyword to mark the end of \a PJ_TRY / \a PJ_CATCH blocks.
+ *
+ * \subsection PJ_GET_EXCEPTION PJ_GET_EXCEPTION(void)
+ * Get the last exception thrown. This macro is normally called inside the
+ * \a PJ_CATCH or \a PJ_DEFAULT block, altough it can be used anywhere where
+ * the \a PJ_USE_EXCEPTION definition is in scope.
+ *
+ *
+ * \section pj_except_examples_sec Examples
+ *
+ * For some examples on how to use the exception construct, please see:
+ * - @ref page_pjlib_samples_except_c
+ * - @ref page_pjlib_exception_test
+ */
+
+/**
+ * Allocate a unique exception id.
+ * Applications don't have to allocate a unique exception ID before using
+ * the exception construct. However, by doing so it ensures that there is
+ * no collisions of exception ID.
+ *
+ * As a bonus, when exception number is acquired through this function,
+ * the library can assign name to the exception (only if
+ * PJ_HAS_EXCEPTION_NAMES is enabled (default is yes)) and find out the
+ * exception name when it catches an exception.
+ *
+ * @param name Name to be associated with the exception ID.
+ * @param id Pointer to receive the ID.
+ *
+ * @return PJ_SUCCESS on success or PJ_ETOOMANY if the library
+ * is running out out ids.
+ */
+PJ_DECL(pj_status_t) pj_exception_id_alloc(const char *name,
+ pj_exception_id_t *id);
+
+/**
+ * Free an exception id.
+ *
+ * @param id The exception ID.
+ *
+ * @return PJ_SUCCESS or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_exception_id_free(pj_exception_id_t id);
+
+/**
+ * Retrieve name associated with the exception id.
+ *
+ * @param id The exception ID.
+ *
+ * @return The name associated with the specified ID.
+ */
+PJ_DECL(const char*) pj_exception_id_name(pj_exception_id_t id);
+
+
+/** @} */
+
+/**
+ * This structure (which should be invisible to user) manages the TRY handler
+ * stack.
+ */
+struct pj_exception_state_t
+{
+ struct pj_exception_state_t *prev; /**< Previous state in the list. */
+ pj_jmp_buf state; /**< jmp_buf. */
+};
+
+/**
+ * Throw exception.
+ * @param id Exception Id.
+ */
+PJ_DECL_NO_RETURN(void)
+pj_throw_exception_(pj_exception_id_t id) PJ_ATTR_NORETURN;
+
+/**
+ * Push exception handler.
+ */
+PJ_DECL(void) pj_push_exception_handler_(struct pj_exception_state_t *rec);
+
+/**
+ * Pop exception handler.
+ */
+PJ_DECL(void) pj_pop_exception_handler_(void);
+
+/**
+ * Declare that the function will use exception.
+ * @hideinitializer
+ */
+#define PJ_USE_EXCEPTION struct pj_exception_state_t pj_x_except__; int pj_x_code__
+
+/**
+ * Start exception specification block.
+ * @hideinitializer
+ */
+#define PJ_TRY if (1) { \
+ pj_push_exception_handler_(&pj_x_except__); \
+ pj_x_code__ = pj_setjmp(pj_x_except__.state); \
+ if (pj_x_code__ == 0)
+/**
+ * Catch the specified exception Id.
+ * @param id The exception number to catch.
+ * @hideinitializer
+ */
+#define PJ_CATCH(id) else if (pj_x_code__ == (id))
+
+/**
+ * Catch any exception number.
+ * @hideinitializer
+ */
+#define PJ_DEFAULT else
+
+/**
+ * End of exception specification block.
+ * @hideinitializer
+ */
+#define PJ_END pj_pop_exception_handler_(); \
+ } else {}
+
+/**
+ * Throw exception.
+ * @param exception_id The exception number.
+ * @hideinitializer
+ */
+#define PJ_THROW(exception_id) pj_throw_exception_(exception_id)
+
+/**
+ * Get current exception.
+ * @return Current exception code.
+ * @hideinitializer
+ */
+#define PJ_GET_EXCEPTION() (pj_x_code__)
+
+PJ_END_DECL
+
+
+
+#endif /* __PJ_EXCEPTION_H__ */
+
- -/** @} */ - -/** - * This structure (which should be invisible to user) manages the TRY handler - * stack. - */ -struct pj_exception_state_t -{ - struct pj_exception_state_t *prev; /**< Previous state in the list. */ - pj_jmp_buf state; /**< jmp_buf. */ -}; - -/** - * Throw exception. - * @param id Exception Id. - */ -PJ_DECL_NO_RETURN(void) -pj_throw_exception_(pj_exception_id_t id) PJ_ATTR_NORETURN; - -/** - * Push exception handler. - */ -PJ_DECL(void) pj_push_exception_handler_(struct pj_exception_state_t *rec); - -/** - * Pop exception handler. - */ -PJ_DECL(void) pj_pop_exception_handler_(void); - -/** - * Declare that the function will use exception. - * @hideinitializer - */ -#define PJ_USE_EXCEPTION struct pj_exception_state_t pj_x_except__; int pj_x_code__ - -/** - * Start exception specification block. - * @hideinitializer - */ -#define PJ_TRY if (1) { \ - pj_push_exception_handler_(&pj_x_except__); \ - pj_x_code__ = pj_setjmp(pj_x_except__.state); \ - if (pj_x_code__ == 0) -/** - * Catch the specified exception Id. - * @param id The exception number to catch. - * @hideinitializer - */ -#define PJ_CATCH(id) else if (pj_x_code__ == (id)) - -/** - * Catch any exception number. - * @hideinitializer - */ -#define PJ_DEFAULT else - -/** - * End of exception specification block. - * @hideinitializer - */ -#define PJ_END pj_pop_exception_handler_(); \ - } else {} - -/** - * Throw exception. - * @param exception_id The exception number. - * @hideinitializer - */ -#define PJ_THROW(exception_id) pj_throw_exception_(exception_id) - -/** - * Get current exception. - * @return Current exception code. - * @hideinitializer - */ -#define PJ_GET_EXCEPTION() (pj_x_code__) - -PJ_END_DECL - - - -#endif /* __PJ_EXCEPTION_H__ */ - - diff --git a/pjlib/include/pj/fifobuf.h b/pjlib/include/pj/fifobuf.h index 7f0b33d3..8c770e04 100644 --- a/pjlib/include/pj/fifobuf.h +++ b/pjlib/include/pj/fifobuf.h @@ -1,29 +1,50 @@ -/* $Id$ - * - */ - -#ifndef __PJ_FIFOBUF_H__ -#define __PJ_FIFOBUF_H__ - -#include <pj/types.h> - -PJ_BEGIN_DECL - -typedef struct pj_fifobuf_t pj_fifobuf_t; -struct pj_fifobuf_t -{ - char *first, *last; - char *ubegin, *uend; - int full; -}; - -PJ_DECL(void) pj_fifobuf_init (pj_fifobuf_t *fb, void *buffer, unsigned size); -PJ_DECL(unsigned) pj_fifobuf_max_size (pj_fifobuf_t *fb); -PJ_DECL(void*) pj_fifobuf_alloc (pj_fifobuf_t *fb, unsigned size); -PJ_DECL(pj_status_t) pj_fifobuf_unalloc (pj_fifobuf_t *fb, void *buf); -PJ_DECL(pj_status_t) pj_fifobuf_free (pj_fifobuf_t *fb, void *buf); - -PJ_END_DECL - -#endif /* __PJ_FIFOBUF_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 __PJ_FIFOBUF_H__
+#define __PJ_FIFOBUF_H__
+
+#include <pj/types.h>
+
+PJ_BEGIN_DECL
+
+typedef struct pj_fifobuf_t pj_fifobuf_t;
+struct pj_fifobuf_t
+{
+ char *first, *last;
+ char *ubegin, *uend;
+ int full;
+};
+
+PJ_DECL(void) pj_fifobuf_init (pj_fifobuf_t *fb, void *buffer, unsigned size);
+PJ_DECL(unsigned) pj_fifobuf_max_size (pj_fifobuf_t *fb);
+PJ_DECL(void*) pj_fifobuf_alloc (pj_fifobuf_t *fb, unsigned size);
+PJ_DECL(pj_status_t) pj_fifobuf_unalloc (pj_fifobuf_t *fb, void *buf);
+PJ_DECL(pj_status_t) pj_fifobuf_free (pj_fifobuf_t *fb, void *buf);
+
+PJ_END_DECL
+
+#endif /* __PJ_FIFOBUF_H__ */
+
diff --git a/pjlib/include/pj/file_access.h b/pjlib/include/pj/file_access.h index 473484d8..1034aa8b 100644 --- a/pjlib/include/pj/file_access.h +++ b/pjlib/include/pj/file_access.h @@ -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
+ */
#ifndef __PJ_FILE_ACCESS_H__
#define __PJ_FILE_ACCESS_H__
diff --git a/pjlib/include/pj/file_io.h b/pjlib/include/pj/file_io.h index 7e5fa3ea..708950bc 100644 --- a/pjlib/include/pj/file_io.h +++ b/pjlib/include/pj/file_io.h @@ -1,155 +1,176 @@ -/* $Id$ */ -#ifndef __PJ_FILE_IO_H__ -#define __PJ_FILE_IO_H__ - -/** - * @file file_io.h - * @brief Simple file I/O abstraction. - */ -#include <pj/types.h> - -PJ_BEGIN_DECL - -/** - * @defgroup PJ_FILE_IO File I/O - * @ingroup PJ_IO - * @{ - * - * This file contains functionalities to perform file I/O. The file - * I/O can be implemented with various back-end, either using native - * file API or ANSI stream. - * - * @section pj_file_size_limit_sec Size Limits - * - * There may be limitation on the size that can be handled by the - * #pj_file_setpos() or #pj_file_getpos() functions. The API itself - * uses 64-bit integer for the file offset/position (where available); - * however some backends (such as ANSI) may only support signed 32-bit - * offset resolution. - * - * Reading and writing operation uses signed 32-bit integer to indicate - * the size. - * - * - */ - -/** - * These enumerations are used when opening file. Values PJ_O_RDONLY, - * PJ_O_WRONLY, and PJ_O_RDWR are mutually exclusive. Value PJ_O_APPEND - * can only be used when the file is opened for writing. - */ -enum pj_file_access -{ - PJ_O_RDONLY = 0x1101, /**< Open file for reading. */ - PJ_O_WRONLY = 0x1102, /**< Open file for writing. */ +/* $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 __PJ_FILE_IO_H__
+#define __PJ_FILE_IO_H__
+
+/**
+ * @file file_io.h
+ * @brief Simple file I/O abstraction.
+ */
+#include <pj/types.h>
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup PJ_FILE_IO File I/O
+ * @ingroup PJ_IO
+ * @{
+ *
+ * This file contains functionalities to perform file I/O. The file
+ * I/O can be implemented with various back-end, either using native
+ * file API or ANSI stream.
+ *
+ * @section pj_file_size_limit_sec Size Limits
+ *
+ * There may be limitation on the size that can be handled by the
+ * #pj_file_setpos() or #pj_file_getpos() functions. The API itself
+ * uses 64-bit integer for the file offset/position (where available);
+ * however some backends (such as ANSI) may only support signed 32-bit
+ * offset resolution.
+ *
+ * Reading and writing operation uses signed 32-bit integer to indicate
+ * the size.
+ *
+ *
+ */
+
+/**
+ * These enumerations are used when opening file. Values PJ_O_RDONLY,
+ * PJ_O_WRONLY, and PJ_O_RDWR are mutually exclusive. Value PJ_O_APPEND
+ * can only be used when the file is opened for writing.
+ */
+enum pj_file_access
+{
+ PJ_O_RDONLY = 0x1101, /**< Open file for reading. */
+ PJ_O_WRONLY = 0x1102, /**< Open file for writing. */
PJ_O_RDWR = 0x1103, /**< Open file for reading and writing.
- File will be truncated. */ + File will be truncated. */
PJ_O_APPEND = 0x1108, /**< Append to existing file. */
-}; - -/** - * The seek directive when setting the file position with #pj_file_setpos. - */ -enum pj_file_seek_type -{ - PJ_SEEK_SET = 0x1201, /**< Offset from beginning of the file. */ - PJ_SEEK_CUR = 0x1202, /**< Offset from current position. */ - PJ_SEEK_END = 0x1203, /**< Size of the file plus offset. */ -}; - -/** - * Open the file as specified in \c pathname with the specified - * mode, and return the handle in \c fd. All files will be opened - * as binary. - * - * @param pool Pool to allocate memory for the new file descriptor. - * @param pathname The file name to open. - * @param flags Open flags, which is bitmask combination of - * #pj_file_access enum. The flag must be either - * PJ_O_RDONLY, PJ_O_WRONLY, or PJ_O_RDWR. When file - * writing is specified, existing file will be +};
+
+/**
+ * The seek directive when setting the file position with #pj_file_setpos.
+ */
+enum pj_file_seek_type
+{
+ PJ_SEEK_SET = 0x1201, /**< Offset from beginning of the file. */
+ PJ_SEEK_CUR = 0x1202, /**< Offset from current position. */
+ PJ_SEEK_END = 0x1203, /**< Size of the file plus offset. */
+};
+
+/**
+ * Open the file as specified in \c pathname with the specified
+ * mode, and return the handle in \c fd. All files will be opened
+ * as binary.
+ *
+ * @param pool Pool to allocate memory for the new file descriptor.
+ * @param pathname The file name to open.
+ * @param flags Open flags, which is bitmask combination of
+ * #pj_file_access enum. The flag must be either
+ * PJ_O_RDONLY, PJ_O_WRONLY, or PJ_O_RDWR. When file
+ * writing is specified, existing file will be
* truncated unless PJ_O_APPEND is specified.
- * @param fd The returned descriptor. - * - * @return PJ_SUCCESS or the appropriate error code on error. - */ -PJ_DECL(pj_status_t) pj_file_open(pj_pool_t *pool, - const char *pathname, - unsigned flags, - pj_oshandle_t *fd); - -/** - * Close an opened file descriptor. - * - * @param fd The file descriptor. - * - * @return PJ_SUCCESS or the appropriate error code on error. - */ -PJ_DECL(pj_status_t) pj_file_close(pj_oshandle_t fd); - -/** - * Write data with the specified size to an opened file. - * - * @param fd The file descriptor. - * @param data Data to be written to the file. - * @param size On input, specifies the size of data to be written. - * On return, it contains the number of data actually - * written to the file. - * - * @return PJ_SUCCESS or the appropriate error code on error. - */ -PJ_DECL(pj_status_t) pj_file_write(pj_oshandle_t fd, - const void *data, - pj_ssize_t *size); - -/** + * @param fd The returned descriptor.
+ *
+ * @return PJ_SUCCESS or the appropriate error code on error.
+ */
+PJ_DECL(pj_status_t) pj_file_open(pj_pool_t *pool,
+ const char *pathname,
+ unsigned flags,
+ pj_oshandle_t *fd);
+
+/**
+ * Close an opened file descriptor.
+ *
+ * @param fd The file descriptor.
+ *
+ * @return PJ_SUCCESS or the appropriate error code on error.
+ */
+PJ_DECL(pj_status_t) pj_file_close(pj_oshandle_t fd);
+
+/**
+ * Write data with the specified size to an opened file.
+ *
+ * @param fd The file descriptor.
+ * @param data Data to be written to the file.
+ * @param size On input, specifies the size of data to be written.
+ * On return, it contains the number of data actually
+ * written to the file.
+ *
+ * @return PJ_SUCCESS or the appropriate error code on error.
+ */
+PJ_DECL(pj_status_t) pj_file_write(pj_oshandle_t fd,
+ const void *data,
+ pj_ssize_t *size);
+
+/**
* Read data from the specified file. When end-of-file condition is set,
- * this function will return PJ_SUCCESS but the size will contain zero. - * - * @param fd The file descriptor. - * @param data Pointer to buffer to receive the data. - * @param size On input, specifies the maximum number of data to - * read from the file. On output, it contains the size + * this function will return PJ_SUCCESS but the size will contain zero.
+ *
+ * @param fd The file descriptor.
+ * @param data Pointer to buffer to receive the data.
+ * @param size On input, specifies the maximum number of data to
+ * read from the file. On output, it contains the size
* of data actually read from the file. It will contain
- * zero when EOF occurs. - * + * zero when EOF occurs.
+ *
* @return PJ_SUCCESS or the appropriate error code on error.
* When EOF occurs, the return is PJ_SUCCESS but size
- * will report zero. - */ -PJ_DECL(pj_status_t) pj_file_read(pj_oshandle_t fd, - void *data, - pj_ssize_t *size); -
-/** - * Set file position to new offset according to directive \c whence. - * - * @param fd The file descriptor. - * @param offset The new file position to set. - * @param whence The directive. - * - * @return PJ_SUCCESS or the appropriate error code on error. - */ -PJ_DECL(pj_status_t) pj_file_setpos(pj_oshandle_t fd, - pj_off_t offset, - enum pj_file_seek_type whence); - -/** - * Get current file position. - * - * @param fd The file descriptor. - * @param pos On return contains the file position as measured - * from the beginning of the file. - * - * @return PJ_SUCCESS or the appropriate error code on error. - */ -PJ_DECL(pj_status_t) pj_file_getpos(pj_oshandle_t fd, - pj_off_t *pos); - -/** @} */ - - -PJ_END_DECL - -#endif /* __PJ_FILE_IO_H__ */ - + * will report zero.
+ */
+PJ_DECL(pj_status_t) pj_file_read(pj_oshandle_t fd,
+ void *data,
+ pj_ssize_t *size);
+
+/**
+ * Set file position to new offset according to directive \c whence.
+ *
+ * @param fd The file descriptor.
+ * @param offset The new file position to set.
+ * @param whence The directive.
+ *
+ * @return PJ_SUCCESS or the appropriate error code on error.
+ */
+PJ_DECL(pj_status_t) pj_file_setpos(pj_oshandle_t fd,
+ pj_off_t offset,
+ enum pj_file_seek_type whence);
+
+/**
+ * Get current file position.
+ *
+ * @param fd The file descriptor.
+ * @param pos On return contains the file position as measured
+ * from the beginning of the file.
+ *
+ * @return PJ_SUCCESS or the appropriate error code on error.
+ */
+PJ_DECL(pj_status_t) pj_file_getpos(pj_oshandle_t fd,
+ pj_off_t *pos);
+
+/** @} */
+
+
+PJ_END_DECL
+
+#endif /* __PJ_FILE_IO_H__ */
+
diff --git a/pjlib/include/pj/guid.h b/pjlib/include/pj/guid.h index 652b5474..230ae1b4 100644 --- a/pjlib/include/pj/guid.h +++ b/pjlib/include/pj/guid.h @@ -1,75 +1,96 @@ -/* $header: $ */ - -#ifndef __PJ_GUID_H__ -#define __PJ_GUID_H__ - - -/** - * @file guid.h - * @brief GUID Globally Unique Identifier. - */ -#include <pj/types.h> - - -PJ_BEGIN_DECL - - -/** - * @defgroup PJ_DS Data Structure. - * @ingroup PJ - */ -/** - * @defgroup PJ_GUID Globally Unique Identifier - * @ingroup PJ_DS - * @{ - * - * This module provides API to create string that is globally unique. - * If application doesn't require that strong requirement, it can just - * use #pj_create_random_string() instead. - */ - - -/** - * PJ_GUID_STRING_LENGTH specifies length of GUID string. The value is - * dependent on the algorithm used internally to generate the GUID string. - * If real GUID generator is used, then the length will be 128bit or - * 32 bytes. If shadow GUID generator is used, then the length - * will be 20 bytes. Application should not assume which algorithm will - * be used by GUID generator. - */ -extern const unsigned PJ_GUID_STRING_LENGTH; - -/** - * PJ_GUID_MAX_LENGTH specifies the maximum length of GUID string, - * regardless of which algorithm to use. - */ -#define PJ_GUID_MAX_LENGTH 32 - -/** - * Create a globally unique string, which length is PJ_GUID_STRING_LENGTH - * characters. Caller is responsible for preallocating the storage used - * in the string. - * - * @param str The string to store the result. - * - * @return The string. - */ -PJ_DECL(pj_str_t*) pj_generate_unique_string(pj_str_t *str); - -/** - * Generate a unique string. - * - * @param pool Pool to allocate memory from. - * @param str The string. - */ -PJ_DECL(void) pj_create_unique_string(pj_pool_t *pool, pj_str_t *str); - - -/** - * @} - */ - -PJ_END_DECL - -#endif/* __PJ_GUID_H__ */ - +/* $header: $ */
+/*
+ * 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 __PJ_GUID_H__
+#define __PJ_GUID_H__
+
+
+/**
+ * @file guid.h
+ * @brief GUID Globally Unique Identifier.
+ */
+#include <pj/types.h>
+
+
+PJ_BEGIN_DECL
+
+
+/**
+ * @defgroup PJ_DS Data Structure.
+ * @ingroup PJ
+ */
+/**
+ * @defgroup PJ_GUID Globally Unique Identifier
+ * @ingroup PJ_DS
+ * @{
+ *
+ * This module provides API to create string that is globally unique.
+ * If application doesn't require that strong requirement, it can just
+ * use #pj_create_random_string() instead.
+ */
+
+
+/**
+ * PJ_GUID_STRING_LENGTH specifies length of GUID string. The value is
+ * dependent on the algorithm used internally to generate the GUID string.
+ * If real GUID generator is used, then the length will be 128bit or
+ * 32 bytes. If shadow GUID generator is used, then the length
+ * will be 20 bytes. Application should not assume which algorithm will
+ * be used by GUID generator.
+ */
+extern const unsigned PJ_GUID_STRING_LENGTH;
+
+/**
+ * PJ_GUID_MAX_LENGTH specifies the maximum length of GUID string,
+ * regardless of which algorithm to use.
+ */
+#define PJ_GUID_MAX_LENGTH 32
+
+/**
+ * Create a globally unique string, which length is PJ_GUID_STRING_LENGTH
+ * characters. Caller is responsible for preallocating the storage used
+ * in the string.
+ *
+ * @param str The string to store the result.
+ *
+ * @return The string.
+ */
+PJ_DECL(pj_str_t*) pj_generate_unique_string(pj_str_t *str);
+
+/**
+ * Generate a unique string.
+ *
+ * @param pool Pool to allocate memory from.
+ * @param str The string.
+ */
+PJ_DECL(void) pj_create_unique_string(pj_pool_t *pool, pj_str_t *str);
+
+
+/**
+ * @}
+ */
+
+PJ_END_DECL
+
+#endif/* __PJ_GUID_H__ */
+
diff --git a/pjlib/include/pj/hash.h b/pjlib/include/pj/hash.h index b1eb9d9f..2c4fca4c 100644 --- a/pjlib/include/pj/hash.h +++ b/pjlib/include/pj/hash.h @@ -1,49 +1,70 @@ -/* $Id$ - * - */ - -#ifndef __PJ_HASH_H__ -#define __PJ_HASH_H__ - -/** - * @file hash.h - * @brief Hash Table. - */ - -#include <pj/types.h> - -PJ_BEGIN_DECL - -/** - * @defgroup PJ_HASH Hash Table - * @ingroup PJ_DS - * @{ - * A hash table is a dictionary in which keys are mapped to array positions by - * hash functions. Having the keys of more than one item map to the same - * position is called a collision. In this library, we will chain the nodes - * that have the same key in a list. - */ - -/** - * If this constant is used as keylen, then the key is interpreted as - * NULL terminated string. - */ -#define PJ_HASH_KEY_STRING ((unsigned)-1) - -/** - * This is the function that is used by the hash table to calculate hash value - * of the specified key. - * - * @param hval the initial hash value, or zero. - * @param key the key to calculate. - * @param keylen the length of the key, or PJ_HASH_KEY_STRING to treat - * the key as null terminated string. - * - * @return the hash value. - */ -PJ_DECL(pj_uint32_t) pj_hash_calc(pj_uint32_t hval, - const void *key, unsigned keylen); - +/* $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 __PJ_HASH_H__
+#define __PJ_HASH_H__
+
+/**
+ * @file hash.h
+ * @brief Hash Table.
+ */
+
+#include <pj/types.h>
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup PJ_HASH Hash Table
+ * @ingroup PJ_DS
+ * @{
+ * A hash table is a dictionary in which keys are mapped to array positions by
+ * hash functions. Having the keys of more than one item map to the same
+ * position is called a collision. In this library, we will chain the nodes
+ * that have the same key in a list.
+ */
+
+/**
+ * If this constant is used as keylen, then the key is interpreted as
+ * NULL terminated string.
+ */
+#define PJ_HASH_KEY_STRING ((unsigned)-1)
+
+/**
+ * This is the function that is used by the hash table to calculate hash value
+ * of the specified key.
+ *
+ * @param hval the initial hash value, or zero.
+ * @param key the key to calculate.
+ * @param keylen the length of the key, or PJ_HASH_KEY_STRING to treat
+ * the key as null terminated string.
+ *
+ * @return the hash value.
+ */
+PJ_DECL(pj_uint32_t) pj_hash_calc(pj_uint32_t hval,
+ const void *key, unsigned keylen);
+
/**
* Convert the key to lowercase and calculate the hash value. The resulting
@@ -59,99 +80,99 @@ PJ_DECL(pj_uint32_t) pj_hash_calc(pj_uint32_t hval, PJ_DECL(pj_uint32_t) pj_hash_calc_tolower(pj_uint32_t hval,
char *result,
const pj_str_t *key);
- -/** - * Create a hash table with the specified 'bucket' size. - * - * @param pool the pool from which the hash table will be allocated from. - * @param size the bucket size, which will be round-up to the nearest 2^n+1 - * - * @return the hash table. - */ -PJ_DECL(pj_hash_table_t*) pj_hash_create(pj_pool_t *pool, unsigned size); - - -/** - * Get the value associated with the specified key. - * - * @param ht the hash table. - * @param key the key to look for. - * @param keylen the length of the key, or PJ_HASH_KEY_STRING to use the - * string length of the key. - * - * @return the value associated with the key, or NULL if the key is not found. - */ -PJ_DECL(void *) pj_hash_get( pj_hash_table_t *ht, - const void *key, unsigned keylen ); - - -/** - * Associate/disassociate a value with the specified key. - * - * @param pool the pool to allocate the new entry if a new entry has to be - * created. - * @param ht the hash table. - * @param key the key. - * @param keylen the length of the key, or PJ_HASH_KEY_STRING to use the - * string length of the key. - * @param value value to be associated, or NULL to delete the entry with - * the specified key. - */ -PJ_DECL(void) pj_hash_set( pj_pool_t *pool, pj_hash_table_t *ht, - const void *key, unsigned keylen, - void *value ); - -/** - * Get the total number of entries in the hash table. - * - * @param ht the hash table. - * - * @return the number of entries in the hash table. - */ -PJ_DECL(unsigned) pj_hash_count( pj_hash_table_t *ht ); - - -/** - * Get the iterator to the first element in the hash table. - * - * @param ht the hash table. - * @param it the iterator for iterating hash elements. - * - * @return the iterator to the hash element, or NULL if no element presents. - */ -PJ_DECL(pj_hash_iterator_t*) pj_hash_first( pj_hash_table_t *ht, - pj_hash_iterator_t *it ); - - -/** - * Get the next element from the iterator. - * - * @param ht the hash table. - * @param it the hash iterator. - * - * @return the next iterator, or NULL if there's no more element. - */ -PJ_DECL(pj_hash_iterator_t*) pj_hash_next( pj_hash_table_t *ht, - pj_hash_iterator_t *it ); - -/** - * Get the value associated with a hash iterator. - * - * @param ht the hash table. - * @param it the hash iterator. - * - * @return the value associated with the current element in iterator. - */ -PJ_DECL(void*) pj_hash_this( pj_hash_table_t *ht, - pj_hash_iterator_t *it ); - - -/** - * @} - */ - -PJ_END_DECL - -#endif - - +
+/**
+ * Create a hash table with the specified 'bucket' size.
+ *
+ * @param pool the pool from which the hash table will be allocated from.
+ * @param size the bucket size, which will be round-up to the nearest 2^n+1
+ *
+ * @return the hash table.
+ */
+PJ_DECL(pj_hash_table_t*) pj_hash_create(pj_pool_t *pool, unsigned size);
+
+
+/**
+ * Get the value associated with the specified key.
+ *
+ * @param ht the hash table.
+ * @param key the key to look for.
+ * @param keylen the length of the key, or PJ_HASH_KEY_STRING to use the
+ * string length of the key.
+ *
+ * @return the value associated with the key, or NULL if the key is not found.
+ */
+PJ_DECL(void *) pj_hash_get( pj_hash_table_t *ht,
+ const void *key, unsigned keylen );
+
+
+/**
+ * Associate/disassociate a value with the specified key.
+ *
+ * @param pool the pool to allocate the new entry if a new entry has to be
+ * created.
+ * @param ht the hash table.
+ * @param key the key.
+ * @param keylen the length of the key, or PJ_HASH_KEY_STRING to use the
+ * string length of the key.
+ * @param value value to be associated, or NULL to delete the entry with
+ * the specified key.
+ */
+PJ_DECL(void) pj_hash_set( pj_pool_t *pool, pj_hash_table_t *ht,
+ const void *key, unsigned keylen,
+ void *value );
+
+/**
+ * Get the total number of entries in the hash table.
+ *
+ * @param ht the hash table.
+ *
+ * @return the number of entries in the hash table.
+ */
+PJ_DECL(unsigned) pj_hash_count( pj_hash_table_t *ht );
+
+
+/**
+ * Get the iterator to the first element in the hash table.
+ *
+ * @param ht the hash table.
+ * @param it the iterator for iterating hash elements.
+ *
+ * @return the iterator to the hash element, or NULL if no element presents.
+ */
+PJ_DECL(pj_hash_iterator_t*) pj_hash_first( pj_hash_table_t *ht,
+ pj_hash_iterator_t *it );
+
+
+/**
+ * Get the next element from the iterator.
+ *
+ * @param ht the hash table.
+ * @param it the hash iterator.
+ *
+ * @return the next iterator, or NULL if there's no more element.
+ */
+PJ_DECL(pj_hash_iterator_t*) pj_hash_next( pj_hash_table_t *ht,
+ pj_hash_iterator_t *it );
+
+/**
+ * Get the value associated with a hash iterator.
+ *
+ * @param ht the hash table.
+ * @param it the hash iterator.
+ *
+ * @return the value associated with the current element in iterator.
+ */
+PJ_DECL(void*) pj_hash_this( pj_hash_table_t *ht,
+ pj_hash_iterator_t *it );
+
+
+/**
+ * @}
+ */
+
+PJ_END_DECL
+
+#endif
+
+
diff --git a/pjlib/include/pj/ioqueue.h b/pjlib/include/pj/ioqueue.h index d1aea694..87f9c104 100644 --- a/pjlib/include/pj/ioqueue.h +++ b/pjlib/include/pj/ioqueue.h @@ -1,344 +1,365 @@ -/* $Id$ - */ - -#ifndef __PJ_IOQUEUE_H__ -#define __PJ_IOQUEUE_H__ - -/** - * @file ioqueue.h - * @brief I/O Dispatching Mechanism - */ - -#include <pj/types.h> - -PJ_BEGIN_DECL - -/** - * @defgroup PJ_IO Input/Output - * @brief Input/Output - * @ingroup PJ_OS - * - * This section contains API building blocks to perform network I/O and - * communications. If provides: - * - @ref PJ_SOCK - *\n - * A highly portable socket abstraction, runs on all kind of - * network APIs such as standard BSD socket, Windows socket, Linux - * \b kernel socket, PalmOS networking API, etc. - * - * - @ref pj_addr_resolve - *\n - * Portable address resolution, which implements #pj_gethostbyname(). - * - * - @ref PJ_SOCK_SELECT - *\n - * A portable \a select() like API (#pj_sock_select()) which can be - * implemented with various back-ends. - * - * - @ref PJ_IOQUEUE - *\n - * Framework for dispatching network events. - * - * For more information see the modules below. - */ - -/** - * @defgroup PJ_IOQUEUE I/O Event Dispatching Queue - * @ingroup PJ_IO - * @{ - * - * I/O Queue provides API for performing asynchronous I/O operations. It - * conforms to proactor pattern, which allows application to submit an - * asynchronous operation and to be notified later when the operation has - * completed. - * - * The I/O Queue can work on both socket and file descriptors. For - * asynchronous file operations however, one must make sure that the correct - * file I/O back-end is used, because not all file I/O back-end can be - * used with the ioqueue. Please see \ref PJ_FILE_IO for more details. - * - * The framework works natively in platforms where asynchronous operation API - * exists, such as in Windows NT with IoCompletionPort/IOCP. In other - * platforms, the I/O queue abstracts the operating system's event poll API - * to provide semantics similar to IoCompletionPort with minimal penalties - * (i.e. per ioqueue and per handle mutex protection). - * - * The I/O queue provides more than just unified abstraction. It also: - * - makes sure that the operation uses the most effective way to utilize - * the underlying mechanism, to achieve the maximum theoritical - * throughput possible on a given platform. - * - choose the most efficient mechanism for event polling on a given - * platform. - * - * Currently, the I/O Queue is implemented using: - * - <tt><b>select()</b></tt>, as the common denominator, but the least - * efficient. Also the number of descriptor is limited to - * \c PJ_IOQUEUE_MAX_HANDLES (which by default is 64). - * - <tt><b>/dev/epoll</b></tt> on Linux (user mode and kernel mode), - * a much faster replacement for select() on Linux (and more importantly - * doesn't have limitation on number of descriptors). - * - <b>I/O Completion ports</b> on Windows NT/2000/XP, which is the most - * efficient way to dispatch events in Windows NT based OSes, and most - * importantly, it doesn't have the limit on how many handles to monitor. - * And it works with files (not only sockets) as well. - * - * - * \section pj_ioqueue_concurrency_sec Concurrency Rules - * - * The items below describe rules that must be obeyed when using the I/O - * queue, with regard to concurrency: - * - simultaneous operations (by different threads) to different key is safe. - * - simultaneous operations to the same key is also safe, except - * <b>unregistration</b>, which is described below. - * - <b>care must be taken when unregistering a key</b> from the - * ioqueue. Application must take care that when one thread is issuing - * an unregistration, other thread is not simultaneously invoking an - * operation <b>to the same key</b>. - *\n - * This happens because the ioqueue functions are working with a pointer - * to the key, and there is a possible race condition where the pointer - * has been rendered invalid by other threads before the ioqueue has a - * chance to acquire mutex on it. - * - * \section pj_ioqeuue_examples_sec Examples - * - * For some examples on how to use the I/O Queue, please see: - * - * - \ref page_pjlib_ioqueue_tcp_test - * - \ref page_pjlib_ioqueue_udp_test - * - \ref page_pjlib_ioqueue_perf_test - */ - - -/** - * This structure describes operation specific key to be submitted to - * I/O Queue when performing the asynchronous operation. This key will - * be returned to the application when completion callback is called. - * - * Application normally wants to attach it's specific data in the - * \c user_data field so that it can keep track of which operation has - * completed when the callback is called. Alternatively, application can - * also extend this struct to include its data, because the pointer that - * is returned in the completion callback will be exactly the same as - * the pointer supplied when the asynchronous function is called. - */ -typedef struct pj_ioqueue_op_key_t -{ - void *internal__[32]; /**< Internal I/O Queue data. */ - void *user_data; /**< Application data. */ -} pj_ioqueue_op_key_t; - -/** - * This structure describes the callbacks to be called when I/O operation - * completes. - */ -typedef struct pj_ioqueue_callback -{ - /** - * This callback is called when #pj_ioqueue_recv or #pj_ioqueue_recvfrom - * completes. - * - * @param key The key. - * @param op_key Operation key. - * @param bytes_read >= 0 to indicate the amount of data read, - * otherwise negative value containing the error - * code. To obtain the pj_status_t error code, use - * (pj_status_t code = -bytes_read). - */ - void (*on_read_complete)(pj_ioqueue_key_t *key, - pj_ioqueue_op_key_t *op_key, - pj_ssize_t bytes_read); - - /** - * This callback is called when #pj_ioqueue_write or #pj_ioqueue_sendto - * completes. - * - * @param key The key. - * @param op_key Operation key. - * @param bytes_sent >= 0 to indicate the amount of data written, - * otherwise negative value containing the error - * code. To obtain the pj_status_t error code, use - * (pj_status_t code = -bytes_sent). - */ - void (*on_write_complete)(pj_ioqueue_key_t *key, - pj_ioqueue_op_key_t *op_key, - pj_ssize_t bytes_sent); - - /** - * This callback is called when #pj_ioqueue_accept completes. - * - * @param key The key. - * @param op_key Operation key. - * @param sock Newly connected socket. - * @param status Zero if the operation completes successfully. - */ - void (*on_accept_complete)(pj_ioqueue_key_t *key, - pj_ioqueue_op_key_t *op_key, - pj_sock_t sock, - pj_status_t status); - - /** - * This callback is called when #pj_ioqueue_connect completes. - * - * @param key The key. - * @param status PJ_SUCCESS if the operation completes successfully. - */ - void (*on_connect_complete)(pj_ioqueue_key_t *key, - pj_status_t status); -} pj_ioqueue_callback; - - -/** - * Types of pending I/O Queue operation. This enumeration is only used - * internally within the ioqueue. - */ -typedef enum pj_ioqueue_operation_e -{ - PJ_IOQUEUE_OP_NONE = 0, /**< No operation. */ - PJ_IOQUEUE_OP_READ = 1, /**< read() operation. */ - PJ_IOQUEUE_OP_RECV = 2, /**< recv() operation. */ - PJ_IOQUEUE_OP_RECV_FROM = 4, /**< recvfrom() operation. */ - PJ_IOQUEUE_OP_WRITE = 8, /**< write() operation. */ - PJ_IOQUEUE_OP_SEND = 16, /**< send() operation. */ - PJ_IOQUEUE_OP_SEND_TO = 32, /**< sendto() operation. */ -#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0 - PJ_IOQUEUE_OP_ACCEPT = 64, /**< accept() operation. */ - PJ_IOQUEUE_OP_CONNECT = 128, /**< connect() operation. */ -#endif /* PJ_HAS_TCP */ -} pj_ioqueue_operation_e; - - -/** - * This macro specifies the maximum number of events that can be - * processed by the ioqueue on a single poll cycle, on implementation - * that supports it. The value is only meaningfull when specified - * during PJLIB build. - */ -#ifndef PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL -# define PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL (16) -#endif - -/** - * Return the name of the ioqueue implementation. - * - * @return Implementation name. - */ -PJ_DECL(const char*) pj_ioqueue_name(void); - - -/** - * Create a new I/O Queue framework. - * - * @param pool The pool to allocate the I/O queue structure. - * @param max_fd The maximum number of handles to be supported, which - * should not exceed PJ_IOQUEUE_MAX_HANDLES. - * @param ioqueue Pointer to hold the newly created I/O Queue. - * - * @return PJ_SUCCESS on success. - */ -PJ_DECL(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, - pj_size_t max_fd, - pj_ioqueue_t **ioqueue); - -/** - * Destroy the I/O queue. - * - * @param ioque The I/O Queue to be destroyed. - * - * @return PJ_SUCCESS if success. - */ -PJ_DECL(pj_status_t) pj_ioqueue_destroy( pj_ioqueue_t *ioque ); - -/** - * Set the lock object to be used by the I/O Queue. This function can only - * be called right after the I/O queue is created, before any handle is - * registered to the I/O queue. - * - * Initially the I/O queue is created with non-recursive mutex protection. - * Applications can supply alternative lock to be used by calling this - * function. - * - * @param ioque The ioqueue instance. - * @param lock The lock to be used by the ioqueue. - * @param auto_delete In non-zero, the lock will be deleted by the ioqueue. - * - * @return PJ_SUCCESS or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioque, - pj_lock_t *lock, - pj_bool_t auto_delete ); - -/** - * Register a socket to the I/O queue framework. - * When a socket is registered to the IOQueue, it may be modified to use - * non-blocking IO. If it is modified, there is no guarantee that this - * modification will be restored after the socket is unregistered. - * - * @param pool To allocate the resource for the specified handle, - * which must be valid until the handle/key is unregistered - * from I/O Queue. - * @param ioque The I/O Queue. - * @param sock The socket. - * @param user_data User data to be associated with the key, which can be - * retrieved later. - * @param cb Callback to be called when I/O operation completes. - * @param key Pointer to receive the key to be associated with this - * socket. Subsequent I/O queue operation will need this - * key. - * - * @return PJ_SUCCESS on success, or the error code. - */ -PJ_DECL(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 **key ); - -/** - * Unregister from the I/O Queue framework. Caller must make sure that - * the key doesn't have any pending operations before calling this function, +/* $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 __PJ_IOQUEUE_H__
+#define __PJ_IOQUEUE_H__
+
+/**
+ * @file ioqueue.h
+ * @brief I/O Dispatching Mechanism
+ */
+
+#include <pj/types.h>
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup PJ_IO Input/Output
+ * @brief Input/Output
+ * @ingroup PJ_OS
+ *
+ * This section contains API building blocks to perform network I/O and
+ * communications. If provides:
+ * - @ref PJ_SOCK
+ *\n
+ * A highly portable socket abstraction, runs on all kind of
+ * network APIs such as standard BSD socket, Windows socket, Linux
+ * \b kernel socket, PalmOS networking API, etc.
+ *
+ * - @ref pj_addr_resolve
+ *\n
+ * Portable address resolution, which implements #pj_gethostbyname().
+ *
+ * - @ref PJ_SOCK_SELECT
+ *\n
+ * A portable \a select() like API (#pj_sock_select()) which can be
+ * implemented with various back-ends.
+ *
+ * - @ref PJ_IOQUEUE
+ *\n
+ * Framework for dispatching network events.
+ *
+ * For more information see the modules below.
+ */
+
+/**
+ * @defgroup PJ_IOQUEUE I/O Event Dispatching Queue
+ * @ingroup PJ_IO
+ * @{
+ *
+ * I/O Queue provides API for performing asynchronous I/O operations. It
+ * conforms to proactor pattern, which allows application to submit an
+ * asynchronous operation and to be notified later when the operation has
+ * completed.
+ *
+ * The I/O Queue can work on both socket and file descriptors. For
+ * asynchronous file operations however, one must make sure that the correct
+ * file I/O back-end is used, because not all file I/O back-end can be
+ * used with the ioqueue. Please see \ref PJ_FILE_IO for more details.
+ *
+ * The framework works natively in platforms where asynchronous operation API
+ * exists, such as in Windows NT with IoCompletionPort/IOCP. In other
+ * platforms, the I/O queue abstracts the operating system's event poll API
+ * to provide semantics similar to IoCompletionPort with minimal penalties
+ * (i.e. per ioqueue and per handle mutex protection).
+ *
+ * The I/O queue provides more than just unified abstraction. It also:
+ * - makes sure that the operation uses the most effective way to utilize
+ * the underlying mechanism, to achieve the maximum theoritical
+ * throughput possible on a given platform.
+ * - choose the most efficient mechanism for event polling on a given
+ * platform.
+ *
+ * Currently, the I/O Queue is implemented using:
+ * - <tt><b>select()</b></tt>, as the common denominator, but the least
+ * efficient. Also the number of descriptor is limited to
+ * \c PJ_IOQUEUE_MAX_HANDLES (which by default is 64).
+ * - <tt><b>/dev/epoll</b></tt> on Linux (user mode and kernel mode),
+ * a much faster replacement for select() on Linux (and more importantly
+ * doesn't have limitation on number of descriptors).
+ * - <b>I/O Completion ports</b> on Windows NT/2000/XP, which is the most
+ * efficient way to dispatch events in Windows NT based OSes, and most
+ * importantly, it doesn't have the limit on how many handles to monitor.
+ * And it works with files (not only sockets) as well.
+ *
+ *
+ * \section pj_ioqueue_concurrency_sec Concurrency Rules
+ *
+ * The items below describe rules that must be obeyed when using the I/O
+ * queue, with regard to concurrency:
+ * - simultaneous operations (by different threads) to different key is safe.
+ * - simultaneous operations to the same key is also safe, except
+ * <b>unregistration</b>, which is described below.
+ * - <b>care must be taken when unregistering a key</b> from the
+ * ioqueue. Application must take care that when one thread is issuing
+ * an unregistration, other thread is not simultaneously invoking an
+ * operation <b>to the same key</b>.
+ *\n
+ * This happens because the ioqueue functions are working with a pointer
+ * to the key, and there is a possible race condition where the pointer
+ * has been rendered invalid by other threads before the ioqueue has a
+ * chance to acquire mutex on it.
+ *
+ * \section pj_ioqeuue_examples_sec Examples
+ *
+ * For some examples on how to use the I/O Queue, please see:
+ *
+ * - \ref page_pjlib_ioqueue_tcp_test
+ * - \ref page_pjlib_ioqueue_udp_test
+ * - \ref page_pjlib_ioqueue_perf_test
+ */
+
+
+/**
+ * This structure describes operation specific key to be submitted to
+ * I/O Queue when performing the asynchronous operation. This key will
+ * be returned to the application when completion callback is called.
+ *
+ * Application normally wants to attach it's specific data in the
+ * \c user_data field so that it can keep track of which operation has
+ * completed when the callback is called. Alternatively, application can
+ * also extend this struct to include its data, because the pointer that
+ * is returned in the completion callback will be exactly the same as
+ * the pointer supplied when the asynchronous function is called.
+ */
+typedef struct pj_ioqueue_op_key_t
+{
+ void *internal__[32]; /**< Internal I/O Queue data. */
+ void *user_data; /**< Application data. */
+} pj_ioqueue_op_key_t;
+
+/**
+ * This structure describes the callbacks to be called when I/O operation
+ * completes.
+ */
+typedef struct pj_ioqueue_callback
+{
+ /**
+ * This callback is called when #pj_ioqueue_recv or #pj_ioqueue_recvfrom
+ * completes.
+ *
+ * @param key The key.
+ * @param op_key Operation key.
+ * @param bytes_read >= 0 to indicate the amount of data read,
+ * otherwise negative value containing the error
+ * code. To obtain the pj_status_t error code, use
+ * (pj_status_t code = -bytes_read).
+ */
+ void (*on_read_complete)(pj_ioqueue_key_t *key,
+ pj_ioqueue_op_key_t *op_key,
+ pj_ssize_t bytes_read);
+
+ /**
+ * This callback is called when #pj_ioqueue_write or #pj_ioqueue_sendto
+ * completes.
+ *
+ * @param key The key.
+ * @param op_key Operation key.
+ * @param bytes_sent >= 0 to indicate the amount of data written,
+ * otherwise negative value containing the error
+ * code. To obtain the pj_status_t error code, use
+ * (pj_status_t code = -bytes_sent).
+ */
+ void (*on_write_complete)(pj_ioqueue_key_t *key,
+ pj_ioqueue_op_key_t *op_key,
+ pj_ssize_t bytes_sent);
+
+ /**
+ * This callback is called when #pj_ioqueue_accept completes.
+ *
+ * @param key The key.
+ * @param op_key Operation key.
+ * @param sock Newly connected socket.
+ * @param status Zero if the operation completes successfully.
+ */
+ void (*on_accept_complete)(pj_ioqueue_key_t *key,
+ pj_ioqueue_op_key_t *op_key,
+ pj_sock_t sock,
+ pj_status_t status);
+
+ /**
+ * This callback is called when #pj_ioqueue_connect completes.
+ *
+ * @param key The key.
+ * @param status PJ_SUCCESS if the operation completes successfully.
+ */
+ void (*on_connect_complete)(pj_ioqueue_key_t *key,
+ pj_status_t status);
+} pj_ioqueue_callback;
+
+
+/**
+ * Types of pending I/O Queue operation. This enumeration is only used
+ * internally within the ioqueue.
+ */
+typedef enum pj_ioqueue_operation_e
+{
+ PJ_IOQUEUE_OP_NONE = 0, /**< No operation. */
+ PJ_IOQUEUE_OP_READ = 1, /**< read() operation. */
+ PJ_IOQUEUE_OP_RECV = 2, /**< recv() operation. */
+ PJ_IOQUEUE_OP_RECV_FROM = 4, /**< recvfrom() operation. */
+ PJ_IOQUEUE_OP_WRITE = 8, /**< write() operation. */
+ PJ_IOQUEUE_OP_SEND = 16, /**< send() operation. */
+ PJ_IOQUEUE_OP_SEND_TO = 32, /**< sendto() operation. */
+#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
+ PJ_IOQUEUE_OP_ACCEPT = 64, /**< accept() operation. */
+ PJ_IOQUEUE_OP_CONNECT = 128, /**< connect() operation. */
+#endif /* PJ_HAS_TCP */
+} pj_ioqueue_operation_e;
+
+
+/**
+ * This macro specifies the maximum number of events that can be
+ * processed by the ioqueue on a single poll cycle, on implementation
+ * that supports it. The value is only meaningfull when specified
+ * during PJLIB build.
+ */
+#ifndef PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL
+# define PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL (16)
+#endif
+
+/**
+ * Return the name of the ioqueue implementation.
+ *
+ * @return Implementation name.
+ */
+PJ_DECL(const char*) pj_ioqueue_name(void);
+
+
+/**
+ * Create a new I/O Queue framework.
+ *
+ * @param pool The pool to allocate the I/O queue structure.
+ * @param max_fd The maximum number of handles to be supported, which
+ * should not exceed PJ_IOQUEUE_MAX_HANDLES.
+ * @param ioqueue Pointer to hold the newly created I/O Queue.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_create( pj_pool_t *pool,
+ pj_size_t max_fd,
+ pj_ioqueue_t **ioqueue);
+
+/**
+ * Destroy the I/O queue.
+ *
+ * @param ioque The I/O Queue to be destroyed.
+ *
+ * @return PJ_SUCCESS if success.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_destroy( pj_ioqueue_t *ioque );
+
+/**
+ * Set the lock object to be used by the I/O Queue. This function can only
+ * be called right after the I/O queue is created, before any handle is
+ * registered to the I/O queue.
+ *
+ * Initially the I/O queue is created with non-recursive mutex protection.
+ * Applications can supply alternative lock to be used by calling this
+ * function.
+ *
+ * @param ioque The ioqueue instance.
+ * @param lock The lock to be used by the ioqueue.
+ * @param auto_delete In non-zero, the lock will be deleted by the ioqueue.
+ *
+ * @return PJ_SUCCESS or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioque,
+ pj_lock_t *lock,
+ pj_bool_t auto_delete );
+
+/**
+ * Register a socket to the I/O queue framework.
+ * When a socket is registered to the IOQueue, it may be modified to use
+ * non-blocking IO. If it is modified, there is no guarantee that this
+ * modification will be restored after the socket is unregistered.
+ *
+ * @param pool To allocate the resource for the specified handle,
+ * which must be valid until the handle/key is unregistered
+ * from I/O Queue.
+ * @param ioque The I/O Queue.
+ * @param sock The socket.
+ * @param user_data User data to be associated with the key, which can be
+ * retrieved later.
+ * @param cb Callback to be called when I/O operation completes.
+ * @param key Pointer to receive the key to be associated with this
+ * socket. Subsequent I/O queue operation will need this
+ * key.
+ *
+ * @return PJ_SUCCESS on success, or the error code.
+ */
+PJ_DECL(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 **key );
+
+/**
+ * Unregister from the I/O Queue framework. Caller must make sure that
+ * the key doesn't have any pending operations before calling this function,
* by calling #pj_ioqueue_is_pending() for all previously submitted
* operations except asynchronous connect, and if necessary call
* #pj_ioqueue_post_completion() to cancel the pending operations.
*
* Note that asynchronous connect operation will automatically be
- * cancelled during the unregistration. - * - * @param key The key that was previously obtained from registration. - * + * cancelled during the unregistration.
+ *
+ * @param key The key that was previously obtained from registration.
+ *
* @return PJ_SUCCESS on success or the error code.
*
- * @see pj_ioqueue_is_pending - */ -PJ_DECL(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key ); - - -/** - * Get user data associated with an ioqueue key. - * - * @param key The key that was previously obtained from registration. - * - * @return The user data associated with the descriptor, or NULL - * on error or if no data is associated with the key during - * registration. - */ -PJ_DECL(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key ); - -/** - * Set or change the user data to be associated with the file descriptor or - * handle or socket descriptor. - * - * @param key The key that was previously obtained from registration. - * @param user_data User data to be associated with the descriptor. - * @param old_data Optional parameter to retrieve the old user data. - * - * @return PJ_SUCCESS on success or the error code. - */ -PJ_DECL(pj_status_t) pj_ioqueue_set_user_data( pj_ioqueue_key_t *key, - void *user_data, - void **old_data); - + * @see pj_ioqueue_is_pending
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key );
+
+
+/**
+ * Get user data associated with an ioqueue key.
+ *
+ * @param key The key that was previously obtained from registration.
+ *
+ * @return The user data associated with the descriptor, or NULL
+ * on error or if no data is associated with the key during
+ * registration.
+ */
+PJ_DECL(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key );
+
+/**
+ * Set or change the user data to be associated with the file descriptor or
+ * handle or socket descriptor.
+ *
+ * @param key The key that was previously obtained from registration.
+ * @param user_data User data to be associated with the descriptor.
+ * @param old_data Optional parameter to retrieve the old user data.
+ *
+ * @return PJ_SUCCESS on success or the error code.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_set_user_data( pj_ioqueue_key_t *key,
+ void *user_data,
+ void **old_data);
+
/**
* Initialize operation key.
@@ -384,256 +405,256 @@ PJ_DECL(pj_status_t) pj_ioqueue_post_completion( pj_ioqueue_key_t *key, pj_ssize_t bytes_status );
- -#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0 -/** - * Instruct I/O Queue to accept incoming connection on the specified - * listening socket. This function will return immediately (i.e. non-blocking) - * regardless whether a connection is immediately available. If the function - * can't complete immediately, the caller will be notified about the incoming - * connection when it calls pj_ioqueue_poll(). If a new connection is - * immediately available, the function returns PJ_SUCCESS with the new - * connection; in this case, the callback WILL NOT be called. - * - * @param key The key which registered to the server socket. - * @param op_key An operation specific key to be associated with the - * pending operation, so that application can keep track of - * which operation has been completed when the callback is - * called. - * @param new_sock Argument which contain pointer to receive the new socket - * for the incoming connection. - * @param local Optional argument which contain pointer to variable to - * receive local address. - * @param remote Optional argument which contain pointer to variable to - * receive the remote address. - * @param addrlen On input, contains the length of the buffer for the - * address, and on output, contains the actual length of the - * address. This argument is optional. - * @return - * - PJ_SUCCESS When connection is available immediately, and the - * parameters will be updated to contain information about - * the new connection. In this case, a completion callback - * WILL NOT be called. - * - PJ_EPENDING If no connection is available immediately. When a new - * connection arrives, the callback will be called. - * - non-zero which indicates the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_ioqueue_accept( pj_ioqueue_key_t *key, - pj_ioqueue_op_key_t *op_key, - pj_sock_t *sock, - pj_sockaddr_t *local, - pj_sockaddr_t *remote, - int *addrlen ); - -/** - * Initiate non-blocking socket connect. If the socket can NOT be connected - * immediately, asynchronous connect() will be scheduled and caller will be - * notified via completion callback when it calls pj_ioqueue_poll(). If - * socket is connected immediately, the function returns PJ_SUCCESS and - * completion callback WILL NOT be called. - * - * @param key The key associated with TCP socket - * @param addr The remote address. - * @param addrlen The remote address length. - * - * @return - * - PJ_SUCCESS If socket is connected immediately. In this case, the - * completion callback WILL NOT be called. - * - PJ_EPENDING If operation is queued, or - * - non-zero Indicates the error code. - */ -PJ_DECL(pj_status_t) pj_ioqueue_connect( pj_ioqueue_key_t *key, - const pj_sockaddr_t *addr, - int addrlen ); - -#endif /* PJ_HAS_TCP */ - -/** - * Poll the I/O Queue for completed events. - * - * @param ioque the I/O Queue. - * @param timeout polling timeout, or NULL if the thread wishes to wait - * indefinetely for the event. - * - * @return - * - zero if timed out (no event). - * - (<0) if error occured during polling. Callback will NOT be called. - * - (>1) to indicate numbers of events. Callbacks have been called. - */ -PJ_DECL(int) pj_ioqueue_poll( pj_ioqueue_t *ioque, - const pj_time_val *timeout); - - -/** - * Instruct the I/O Queue to read from the specified handle. This function - * returns immediately (i.e. non-blocking) regardless whether some data has - * been transfered. If the operation can't complete immediately, caller will - * be notified about the completion when it calls pj_ioqueue_poll(). If data - * is immediately available, the function will return PJ_SUCCESS and the - * callback WILL NOT be called. - * - * @param key The key that uniquely identifies the handle. - * @param op_key An operation specific key to be associated with the - * pending operation, so that application can keep track of - * which operation has been completed when the callback is - * called. Caller must make sure that this key remains - * valid until the function completes. - * @param buffer The buffer to hold the read data. The caller MUST make sure - * that this buffer remain valid until the framework completes - * reading the handle. - * @param length On input, it specifies the size of the buffer. If data is - * available to be read immediately, the function returns - * PJ_SUCCESS and this argument will be filled with the - * amount of data read. If the function is pending, caller - * will be notified about the amount of data read in the - * callback. This parameter can point to local variable in - * caller's stack and doesn't have to remain valid for the - * duration of pending operation. - * @param flags Recv flag. - * - * @return - * - PJ_SUCCESS If immediate data has been received in the buffer. In this - * case, the callback WILL NOT be called. - * - PJ_EPENDING If the operation has been queued, and the callback will be - * called when data has been received. - * - non-zero The return value indicates the error code. - */ -PJ_DECL(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 ); - -/** - * This function behaves similarly as #pj_ioqueue_recv(), except that it is - * normally called for socket, and the remote address will also be returned - * along with the data. Caller MUST make sure that both buffer and addr - * remain valid until the framework completes reading the data. - * - * @param key The key that uniquely identifies the handle. - * @param op_key An operation specific key to be associated with the - * pending operation, so that application can keep track of - * which operation has been completed when the callback is - * called. - * @param buffer The buffer to hold the read data. The caller MUST make sure - * that this buffer remain valid until the framework completes - * reading the handle. - * @param length On input, it specifies the size of the buffer. If data is - * available to be read immediately, the function returns - * PJ_SUCCESS and this argument will be filled with the - * amount of data read. If the function is pending, caller - * will be notified about the amount of data read in the - * callback. This parameter can point to local variable in - * caller's stack and doesn't have to remain valid for the - * duration of pending operation. - * @param flags Recv flag. - * @param addr Optional Pointer to buffer to receive the address. - * @param addrlen On input, specifies the length of the address buffer. - * On output, it will be filled with the actual length of - * the address. This argument can be NULL if \c addr is not - * specified. - * - * @return - * - PJ_SUCCESS If immediate data has been received. In this case, the - * callback must have been called before this function - * returns, and no pending operation is scheduled. - * - PJ_EPENDING If the operation has been queued. - * - non-zero The return value indicates the error code. - */ -PJ_DECL(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); - -/** - * Instruct the I/O Queue to write to the handle. This function will return - * immediately (i.e. non-blocking) regardless whether some data has been - * transfered. If the function can't complete immediately, the caller will - * be notified about the completion when it calls pj_ioqueue_poll(). If - * operation completes immediately and data has been transfered, the function - * returns PJ_SUCCESS and the callback will NOT be called. - * - * @param key The key that identifies the handle. - * @param op_key An operation specific key to be associated with the - * pending operation, so that application can keep track of - * which operation has been completed when the callback is - * called. - * @param data The data to send. Caller MUST make sure that this buffer - * remains valid until the write operation completes. - * @param length On input, it specifies the length of data to send. When - * data was sent immediately, this function returns PJ_SUCCESS - * and this parameter contains the length of data sent. If - * data can not be sent immediately, an asynchronous operation - * is scheduled and caller will be notified via callback the - * number of bytes sent. This parameter can point to local - * variable on caller's stack and doesn't have to remain - * valid until the operation has completed. - * @param flags Send flags. - * - * @return - * - PJ_SUCCESS If data was immediately transfered. In this case, no - * pending operation has been scheduled and the callback - * WILL NOT be called. - * - PJ_EPENDING If the operation has been queued. Once data base been - * transfered, the callback will be called. - * - non-zero The return value indicates the error code. - */ -PJ_DECL(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 ); - - -/** - * Instruct the I/O Queue to write to the handle. This function will return - * immediately (i.e. non-blocking) regardless whether some data has been - * transfered. If the function can't complete immediately, the caller will - * be notified about the completion when it calls pj_ioqueue_poll(). If - * operation completes immediately and data has been transfered, the function - * returns PJ_SUCCESS and the callback will NOT be called. - * - * @param key the key that identifies the handle. - * @param op_key An operation specific key to be associated with the - * pending operation, so that application can keep track of - * which operation has been completed when the callback is - * called. - * @param data the data to send. Caller MUST make sure that this buffer - * remains valid until the write operation completes. - * @param length On input, it specifies the length of data to send. When - * data was sent immediately, this function returns PJ_SUCCESS - * and this parameter contains the length of data sent. If - * data can not be sent immediately, an asynchronous operation - * is scheduled and caller will be notified via callback the - * number of bytes sent. This parameter can point to local - * variable on caller's stack and doesn't have to remain - * valid until the operation has completed. - * @param flags send flags. - * @param addr Optional remote address. - * @param addrlen Remote address length, \c addr is specified. - * - * @return - * - PJ_SUCCESS If data was immediately written. - * - PJ_EPENDING If the operation has been queued. - * - non-zero The return value indicates the error code. - */ -PJ_DECL(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); - - -/** - * !} - */ - -PJ_END_DECL - -#endif /* __PJ_IOQUEUE_H__ */ - +
+#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
+/**
+ * Instruct I/O Queue to accept incoming connection on the specified
+ * listening socket. This function will return immediately (i.e. non-blocking)
+ * regardless whether a connection is immediately available. If the function
+ * can't complete immediately, the caller will be notified about the incoming
+ * connection when it calls pj_ioqueue_poll(). If a new connection is
+ * immediately available, the function returns PJ_SUCCESS with the new
+ * connection; in this case, the callback WILL NOT be called.
+ *
+ * @param key The key which registered to the server socket.
+ * @param op_key An operation specific key to be associated with the
+ * pending operation, so that application can keep track of
+ * which operation has been completed when the callback is
+ * called.
+ * @param new_sock Argument which contain pointer to receive the new socket
+ * for the incoming connection.
+ * @param local Optional argument which contain pointer to variable to
+ * receive local address.
+ * @param remote Optional argument which contain pointer to variable to
+ * receive the remote address.
+ * @param addrlen On input, contains the length of the buffer for the
+ * address, and on output, contains the actual length of the
+ * address. This argument is optional.
+ * @return
+ * - PJ_SUCCESS When connection is available immediately, and the
+ * parameters will be updated to contain information about
+ * the new connection. In this case, a completion callback
+ * WILL NOT be called.
+ * - PJ_EPENDING If no connection is available immediately. When a new
+ * connection arrives, the callback will be called.
+ * - non-zero which indicates the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_accept( pj_ioqueue_key_t *key,
+ pj_ioqueue_op_key_t *op_key,
+ pj_sock_t *sock,
+ pj_sockaddr_t *local,
+ pj_sockaddr_t *remote,
+ int *addrlen );
+
+/**
+ * Initiate non-blocking socket connect. If the socket can NOT be connected
+ * immediately, asynchronous connect() will be scheduled and caller will be
+ * notified via completion callback when it calls pj_ioqueue_poll(). If
+ * socket is connected immediately, the function returns PJ_SUCCESS and
+ * completion callback WILL NOT be called.
+ *
+ * @param key The key associated with TCP socket
+ * @param addr The remote address.
+ * @param addrlen The remote address length.
+ *
+ * @return
+ * - PJ_SUCCESS If socket is connected immediately. In this case, the
+ * completion callback WILL NOT be called.
+ * - PJ_EPENDING If operation is queued, or
+ * - non-zero Indicates the error code.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_connect( pj_ioqueue_key_t *key,
+ const pj_sockaddr_t *addr,
+ int addrlen );
+
+#endif /* PJ_HAS_TCP */
+
+/**
+ * Poll the I/O Queue for completed events.
+ *
+ * @param ioque the I/O Queue.
+ * @param timeout polling timeout, or NULL if the thread wishes to wait
+ * indefinetely for the event.
+ *
+ * @return
+ * - zero if timed out (no event).
+ * - (<0) if error occured during polling. Callback will NOT be called.
+ * - (>1) to indicate numbers of events. Callbacks have been called.
+ */
+PJ_DECL(int) pj_ioqueue_poll( pj_ioqueue_t *ioque,
+ const pj_time_val *timeout);
+
+
+/**
+ * Instruct the I/O Queue to read from the specified handle. This function
+ * returns immediately (i.e. non-blocking) regardless whether some data has
+ * been transfered. If the operation can't complete immediately, caller will
+ * be notified about the completion when it calls pj_ioqueue_poll(). If data
+ * is immediately available, the function will return PJ_SUCCESS and the
+ * callback WILL NOT be called.
+ *
+ * @param key The key that uniquely identifies the handle.
+ * @param op_key An operation specific key to be associated with the
+ * pending operation, so that application can keep track of
+ * which operation has been completed when the callback is
+ * called. Caller must make sure that this key remains
+ * valid until the function completes.
+ * @param buffer The buffer to hold the read data. The caller MUST make sure
+ * that this buffer remain valid until the framework completes
+ * reading the handle.
+ * @param length On input, it specifies the size of the buffer. If data is
+ * available to be read immediately, the function returns
+ * PJ_SUCCESS and this argument will be filled with the
+ * amount of data read. If the function is pending, caller
+ * will be notified about the amount of data read in the
+ * callback. This parameter can point to local variable in
+ * caller's stack and doesn't have to remain valid for the
+ * duration of pending operation.
+ * @param flags Recv flag.
+ *
+ * @return
+ * - PJ_SUCCESS If immediate data has been received in the buffer. In this
+ * case, the callback WILL NOT be called.
+ * - PJ_EPENDING If the operation has been queued, and the callback will be
+ * called when data has been received.
+ * - non-zero The return value indicates the error code.
+ */
+PJ_DECL(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 );
+
+/**
+ * This function behaves similarly as #pj_ioqueue_recv(), except that it is
+ * normally called for socket, and the remote address will also be returned
+ * along with the data. Caller MUST make sure that both buffer and addr
+ * remain valid until the framework completes reading the data.
+ *
+ * @param key The key that uniquely identifies the handle.
+ * @param op_key An operation specific key to be associated with the
+ * pending operation, so that application can keep track of
+ * which operation has been completed when the callback is
+ * called.
+ * @param buffer The buffer to hold the read data. The caller MUST make sure
+ * that this buffer remain valid until the framework completes
+ * reading the handle.
+ * @param length On input, it specifies the size of the buffer. If data is
+ * available to be read immediately, the function returns
+ * PJ_SUCCESS and this argument will be filled with the
+ * amount of data read. If the function is pending, caller
+ * will be notified about the amount of data read in the
+ * callback. This parameter can point to local variable in
+ * caller's stack and doesn't have to remain valid for the
+ * duration of pending operation.
+ * @param flags Recv flag.
+ * @param addr Optional Pointer to buffer to receive the address.
+ * @param addrlen On input, specifies the length of the address buffer.
+ * On output, it will be filled with the actual length of
+ * the address. This argument can be NULL if \c addr is not
+ * specified.
+ *
+ * @return
+ * - PJ_SUCCESS If immediate data has been received. In this case, the
+ * callback must have been called before this function
+ * returns, and no pending operation is scheduled.
+ * - PJ_EPENDING If the operation has been queued.
+ * - non-zero The return value indicates the error code.
+ */
+PJ_DECL(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);
+
+/**
+ * Instruct the I/O Queue to write to the handle. This function will return
+ * immediately (i.e. non-blocking) regardless whether some data has been
+ * transfered. If the function can't complete immediately, the caller will
+ * be notified about the completion when it calls pj_ioqueue_poll(). If
+ * operation completes immediately and data has been transfered, the function
+ * returns PJ_SUCCESS and the callback will NOT be called.
+ *
+ * @param key The key that identifies the handle.
+ * @param op_key An operation specific key to be associated with the
+ * pending operation, so that application can keep track of
+ * which operation has been completed when the callback is
+ * called.
+ * @param data The data to send. Caller MUST make sure that this buffer
+ * remains valid until the write operation completes.
+ * @param length On input, it specifies the length of data to send. When
+ * data was sent immediately, this function returns PJ_SUCCESS
+ * and this parameter contains the length of data sent. If
+ * data can not be sent immediately, an asynchronous operation
+ * is scheduled and caller will be notified via callback the
+ * number of bytes sent. This parameter can point to local
+ * variable on caller's stack and doesn't have to remain
+ * valid until the operation has completed.
+ * @param flags Send flags.
+ *
+ * @return
+ * - PJ_SUCCESS If data was immediately transfered. In this case, no
+ * pending operation has been scheduled and the callback
+ * WILL NOT be called.
+ * - PJ_EPENDING If the operation has been queued. Once data base been
+ * transfered, the callback will be called.
+ * - non-zero The return value indicates the error code.
+ */
+PJ_DECL(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 );
+
+
+/**
+ * Instruct the I/O Queue to write to the handle. This function will return
+ * immediately (i.e. non-blocking) regardless whether some data has been
+ * transfered. If the function can't complete immediately, the caller will
+ * be notified about the completion when it calls pj_ioqueue_poll(). If
+ * operation completes immediately and data has been transfered, the function
+ * returns PJ_SUCCESS and the callback will NOT be called.
+ *
+ * @param key the key that identifies the handle.
+ * @param op_key An operation specific key to be associated with the
+ * pending operation, so that application can keep track of
+ * which operation has been completed when the callback is
+ * called.
+ * @param data the data to send. Caller MUST make sure that this buffer
+ * remains valid until the write operation completes.
+ * @param length On input, it specifies the length of data to send. When
+ * data was sent immediately, this function returns PJ_SUCCESS
+ * and this parameter contains the length of data sent. If
+ * data can not be sent immediately, an asynchronous operation
+ * is scheduled and caller will be notified via callback the
+ * number of bytes sent. This parameter can point to local
+ * variable on caller's stack and doesn't have to remain
+ * valid until the operation has completed.
+ * @param flags send flags.
+ * @param addr Optional remote address.
+ * @param addrlen Remote address length, \c addr is specified.
+ *
+ * @return
+ * - PJ_SUCCESS If data was immediately written.
+ * - PJ_EPENDING If the operation has been queued.
+ * - non-zero The return value indicates the error code.
+ */
+PJ_DECL(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);
+
+
+/**
+ * !}
+ */
+
+PJ_END_DECL
+
+#endif /* __PJ_IOQUEUE_H__ */
+
diff --git a/pjlib/include/pj/list.h b/pjlib/include/pj/list.h index f6662eb6..72dd0096 100644 --- a/pjlib/include/pj/list.h +++ b/pjlib/include/pj/list.h @@ -1,222 +1,243 @@ -/* $Id$ - * - */ - -#ifndef __PJ_LIST_H__ -#define __PJ_LIST_H__ - -/** - * @file list.h - * @brief Linked List data structure. - */ - -#include <pj/types.h> - -PJ_BEGIN_DECL - -/* - * @defgroup PJ_DS Data Structure. - * @ingroup PJ - */ - -/** - * @defgroup PJ_LIST Linked List - * @ingroup PJ_DS - * @{ - * - * List in PJLIB is implemented as doubly-linked list, and it won't require - * dynamic memory allocation (just as all PJLIB data structures). The list here - * should be viewed more like a low level C list instead of high level C++ list - * (which normally are easier to use but require dynamic memory allocations), - * therefore all caveats with C list apply here too (such as you can NOT put - * a node in more than one lists). - * - * \section pj_list_example_sec Examples - * - * See below for examples on how to manipulate linked list: - * - @ref page_pjlib_samples_list_c - * - @ref page_pjlib_list_test - */ - - -/** - * Use this macro in the start of the structure declaration to declare that - * the structure can be used in the linked list operation. This macro simply - * declares additional member @a prev and @a next to the structure. - * @hideinitializer - */ +/* $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 __PJ_LIST_H__
+#define __PJ_LIST_H__
+
+/**
+ * @file list.h
+ * @brief Linked List data structure.
+ */
+
+#include <pj/types.h>
+
+PJ_BEGIN_DECL
+
+/*
+ * @defgroup PJ_DS Data Structure.
+ * @ingroup PJ
+ */
+
+/**
+ * @defgroup PJ_LIST Linked List
+ * @ingroup PJ_DS
+ * @{
+ *
+ * List in PJLIB is implemented as doubly-linked list, and it won't require
+ * dynamic memory allocation (just as all PJLIB data structures). The list here
+ * should be viewed more like a low level C list instead of high level C++ list
+ * (which normally are easier to use but require dynamic memory allocations),
+ * therefore all caveats with C list apply here too (such as you can NOT put
+ * a node in more than one lists).
+ *
+ * \section pj_list_example_sec Examples
+ *
+ * See below for examples on how to manipulate linked list:
+ * - @ref page_pjlib_samples_list_c
+ * - @ref page_pjlib_list_test
+ */
+
+
+/**
+ * Use this macro in the start of the structure declaration to declare that
+ * the structure can be used in the linked list operation. This macro simply
+ * declares additional member @a prev and @a next to the structure.
+ * @hideinitializer
+ */
#define PJ_DECL_LIST_MEMBER(type) \
/** List @a prev. */ \
type *prev; \
- /** List @a next. */ \ - type *next - - -/** - * This structure describes generic list node and list. The owner of this list - * must initialize the 'value' member to an appropriate value (typically the - * owner itself). - */ -struct pj_list -{ - PJ_DECL_LIST_MEMBER(void); -}; - - -/** - * Initialize the list. - * Initially, the list will have no member, and function pj_list_empty() will - * always return nonzero (which indicates TRUE) for the newly initialized - * list. - * - * @param node The list head. - */ -PJ_INLINE(void) pj_list_init(pj_list_type * node) -{ - ((pj_list*)node)->next = ((pj_list*)node)->prev = node; -} - - -/** - * Check that the list is empty. - * - * @param node The list head. - * - * @return Non-zero if the list is not-empty, or zero if it is empty. - * - */ -PJ_INLINE(int) pj_list_empty(const pj_list_type * node) -{ - return ((pj_list*)node)->next == node; -} - - -/** - * Insert the node to the list before the specified element position. - * - * @param pos The element to which the node will be inserted before. - * @param node The element to be inserted. - * - * @return void. - */ -PJ_IDECL(void) pj_list_insert_before(pj_list_type *pos, pj_list_type *node); - - -/** - * Inserts all nodes in \a nodes to the target list. - * - * @param lst The target list. - * @param nodes Nodes list. - */ -PJ_IDECL(void) pj_list_insert_nodes_before(pj_list_type *lst, - pj_list_type *nodes); - -/** - * Insert a node to the list after the specified element position. - * - * @param pos The element in the list which will precede the inserted - * element. - * @param node The element to be inserted after the position element. - * - * @return void. - */ -PJ_IDECL(void) pj_list_insert_after(pj_list_type *pos, pj_list_type *node); - -/** - * Insert all nodes in \a nodes to the target list. - * - * @param lst The target list. - * @param nodes Nodes list. - */ -PJ_IDECL(void) pj_list_insert_nodes_after(pj_list_type *lst, - pj_list_type *nodes); - - -/** - * Remove elements from the source list, and insert them to the destination - * list. The elements of the source list will occupy the - * front elements of the target list. Note that the node pointed by \a list2 - * itself is not considered as a node, but rather as the list descriptor, so - * it will not be inserted to the \a list1. The elements to be inserted starts - * at \a list2->next. If \a list2 is to be included in the operation, use - * \a pj_list_insert_nodes_before. - * - * @param list1 The destination list. - * @param list2 The source list. - * - * @return void. - */ -PJ_IDECL(void) pj_list_merge_first(pj_list_type *list1, pj_list_type *list2); - - -/** - * Remove elements from the second list argument, and insert them to the list - * in the first argument. The elements from the second list will be appended - * to the first list. Note that the node pointed by \a list2 - * itself is not considered as a node, but rather as the list descriptor, so - * it will not be inserted to the \a list1. The elements to be inserted starts - * at \a list2->next. If \a list2 is to be included in the operation, use - * \a pj_list_insert_nodes_before. - * - * @param list1 The element in the list which will precede the inserted - * element. - * @param list2 The element in the list to be inserted. - * - * @return void. - */ -PJ_IDECL(void) pj_list_merge_last( pj_list_type *list1, pj_list_type *list2); - - -/** - * Erase the node from the list it currently belongs. - * - * @param node The element to be erased. - */ -PJ_IDECL(void) pj_list_erase(pj_list_type *node); - - -/** - * Find node in the list. - * - * @param list The list head. - * @param node The node element to be searched. - * - * @return The node itself if it is found in the list, or NULL if it is not - * found in the list. - */ -PJ_IDECL(pj_list_type*) pj_list_find_node(pj_list_type *list, - pj_list_type *node); - - -/** - * Search the list for the specified value, using the specified comparison - * function. This function iterates on nodes in the list, started with the - * first node, and call the user supplied comparison function until the - * comparison function returns ZERO. - * - * @param list The list head. - * @param value The user defined value to be passed in the comparison - * function - * @param comp The comparison function, which should return ZERO to - * indicate that the searched value is found. - * - * @return The first node that matched, or NULL if it is not found. - */ -PJ_IDECL(pj_list_type*) pj_list_search(pj_list_type *list, void *value, - int (*comp)(void *value, - const pj_list_type *node) - ); - - -/** - * @} - */ - -#if PJ_FUNCTIONS_ARE_INLINED -# include "list_i.h" -#endif - -PJ_END_DECL - -#endif /* __PJ_LIST_H__ */ - + /** List @a next. */ \
+ type *next
+
+
+/**
+ * This structure describes generic list node and list. The owner of this list
+ * must initialize the 'value' member to an appropriate value (typically the
+ * owner itself).
+ */
+struct pj_list
+{
+ PJ_DECL_LIST_MEMBER(void);
+};
+
+
+/**
+ * Initialize the list.
+ * Initially, the list will have no member, and function pj_list_empty() will
+ * always return nonzero (which indicates TRUE) for the newly initialized
+ * list.
+ *
+ * @param node The list head.
+ */
+PJ_INLINE(void) pj_list_init(pj_list_type * node)
+{
+ ((pj_list*)node)->next = ((pj_list*)node)->prev = node;
+}
+
+
+/**
+ * Check that the list is empty.
+ *
+ * @param node The list head.
+ *
+ * @return Non-zero if the list is not-empty, or zero if it is empty.
+ *
+ */
+PJ_INLINE(int) pj_list_empty(const pj_list_type * node)
+{
+ return ((pj_list*)node)->next == node;
+}
+
+
+/**
+ * Insert the node to the list before the specified element position.
+ *
+ * @param pos The element to which the node will be inserted before.
+ * @param node The element to be inserted.
+ *
+ * @return void.
+ */
+PJ_IDECL(void) pj_list_insert_before(pj_list_type *pos, pj_list_type *node);
+
+
+/**
+ * Inserts all nodes in \a nodes to the target list.
+ *
+ * @param lst The target list.
+ * @param nodes Nodes list.
+ */
+PJ_IDECL(void) pj_list_insert_nodes_before(pj_list_type *lst,
+ pj_list_type *nodes);
+
+/**
+ * Insert a node to the list after the specified element position.
+ *
+ * @param pos The element in the list which will precede the inserted
+ * element.
+ * @param node The element to be inserted after the position element.
+ *
+ * @return void.
+ */
+PJ_IDECL(void) pj_list_insert_after(pj_list_type *pos, pj_list_type *node);
+
+/**
+ * Insert all nodes in \a nodes to the target list.
+ *
+ * @param lst The target list.
+ * @param nodes Nodes list.
+ */
+PJ_IDECL(void) pj_list_insert_nodes_after(pj_list_type *lst,
+ pj_list_type *nodes);
+
+
+/**
+ * Remove elements from the source list, and insert them to the destination
+ * list. The elements of the source list will occupy the
+ * front elements of the target list. Note that the node pointed by \a list2
+ * itself is not considered as a node, but rather as the list descriptor, so
+ * it will not be inserted to the \a list1. The elements to be inserted starts
+ * at \a list2->next. If \a list2 is to be included in the operation, use
+ * \a pj_list_insert_nodes_before.
+ *
+ * @param list1 The destination list.
+ * @param list2 The source list.
+ *
+ * @return void.
+ */
+PJ_IDECL(void) pj_list_merge_first(pj_list_type *list1, pj_list_type *list2);
+
+
+/**
+ * Remove elements from the second list argument, and insert them to the list
+ * in the first argument. The elements from the second list will be appended
+ * to the first list. Note that the node pointed by \a list2
+ * itself is not considered as a node, but rather as the list descriptor, so
+ * it will not be inserted to the \a list1. The elements to be inserted starts
+ * at \a list2->next. If \a list2 is to be included in the operation, use
+ * \a pj_list_insert_nodes_before.
+ *
+ * @param list1 The element in the list which will precede the inserted
+ * element.
+ * @param list2 The element in the list to be inserted.
+ *
+ * @return void.
+ */
+PJ_IDECL(void) pj_list_merge_last( pj_list_type *list1, pj_list_type *list2);
+
+
+/**
+ * Erase the node from the list it currently belongs.
+ *
+ * @param node The element to be erased.
+ */
+PJ_IDECL(void) pj_list_erase(pj_list_type *node);
+
+
+/**
+ * Find node in the list.
+ *
+ * @param list The list head.
+ * @param node The node element to be searched.
+ *
+ * @return The node itself if it is found in the list, or NULL if it is not
+ * found in the list.
+ */
+PJ_IDECL(pj_list_type*) pj_list_find_node(pj_list_type *list,
+ pj_list_type *node);
+
+
+/**
+ * Search the list for the specified value, using the specified comparison
+ * function. This function iterates on nodes in the list, started with the
+ * first node, and call the user supplied comparison function until the
+ * comparison function returns ZERO.
+ *
+ * @param list The list head.
+ * @param value The user defined value to be passed in the comparison
+ * function
+ * @param comp The comparison function, which should return ZERO to
+ * indicate that the searched value is found.
+ *
+ * @return The first node that matched, or NULL if it is not found.
+ */
+PJ_IDECL(pj_list_type*) pj_list_search(pj_list_type *list, void *value,
+ int (*comp)(void *value,
+ const pj_list_type *node)
+ );
+
+
+/**
+ * @}
+ */
+
+#if PJ_FUNCTIONS_ARE_INLINED
+# include "list_i.h"
+#endif
+
+PJ_END_DECL
+
+#endif /* __PJ_LIST_H__ */
+
diff --git a/pjlib/include/pj/list_i.h b/pjlib/include/pj/list_i.h index 9ca6e1dd..4f2fd000 100644 --- a/pjlib/include/pj/list_i.h +++ b/pjlib/include/pj/list_i.h @@ -1,103 +1,124 @@ -/* $Id$ - * - */ - - -/* Internal */ -PJ_IDEF(void) pj_link_node(pj_list_type *prev, pj_list_type *next) -{ - ((pj_list*)prev)->next = next; - ((pj_list*)next)->prev = prev; -} - -/* -PJ_IDEF(void) -pj_list_init(pj_list_type * node) -{ - ((pj_list*)node)->next = ((pj_list*)node)->prev = node; -} - -PJ_IDEF(int) pj_list_empty(const pj_list_type * node) -{ - return ((pj_list*)node)->next == node; -} -*/ - -PJ_IDEF(void) -pj_list_insert_after(pj_list_type *pos, pj_list_type *node) -{ - ((pj_list*)node)->prev = pos; - ((pj_list*)node)->next = ((pj_list*)pos)->next; - ((pj_list*) ((pj_list*)pos)->next) ->prev = node; - ((pj_list*)pos)->next = node; -} - - -PJ_IDEF(void) -pj_list_insert_before(pj_list_type *pos, pj_list_type *node) -{ - pj_list_insert_after(((pj_list*)pos)->prev, node); -} - - -PJ_IDEF(void) -pj_list_insert_nodes_after(pj_list_type *pos, pj_list_type *lst) -{ - pj_list *lst_last = (pj_list *) ((pj_list*)lst)->prev; - pj_list *pos_next = (pj_list *) ((pj_list*)pos)->next; - - pj_link_node(pos, lst); - pj_link_node(lst_last, pos_next); -} - -PJ_IDEF(void) -pj_list_insert_nodes_before(pj_list_type *pos, pj_list_type *lst) -{ - pj_list_insert_nodes_after(((pj_list*)pos)->prev, lst); -} - -PJ_IDEF(void) -pj_list_merge_last(pj_list_type *lst1, pj_list_type *lst2) -{ - pj_link_node(((pj_list*)lst1)->prev, ((pj_list*)lst2)->next); - pj_link_node(((pj_list*)lst2)->prev, lst1); - pj_list_init(lst2); -} - -PJ_IDEF(void) -pj_list_merge_first(pj_list_type *lst1, pj_list_type *lst2) -{ - pj_link_node(((pj_list*)lst2)->prev, ((pj_list*)lst1)->next); - pj_link_node(((pj_list*)lst1), ((pj_list*)lst2)->next); - pj_list_init(lst2); -} - -PJ_IDEF(void) -pj_list_erase(pj_list_type *node) -{ - pj_link_node( ((pj_list*)node)->prev, ((pj_list*)node)->next); -} - - -PJ_IDEF(pj_list_type*) -pj_list_find_node(pj_list_type *list, pj_list_type *node) -{ - pj_list *p = (pj_list *) ((pj_list*)list)->next; - while (p != list && p != node) - p = (pj_list *) p->next; - - return p==node ? p : NULL; -} - - -PJ_IDEF(pj_list_type*) -pj_list_search(pj_list_type *list, void *value, - int (*comp)(void *value, const pj_list_type *node)) -{ - pj_list *p = (pj_list *) ((pj_list*)list)->next; - while (p != list && (*comp)(value, p) != 0) - p = (pj_list *) p->next; - - return p==list ? NULL : p; -} - +/* $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
+ */
+
+
+/* Internal */
+PJ_IDEF(void) pj_link_node(pj_list_type *prev, pj_list_type *next)
+{
+ ((pj_list*)prev)->next = next;
+ ((pj_list*)next)->prev = prev;
+}
+
+/*
+PJ_IDEF(void)
+pj_list_init(pj_list_type * node)
+{
+ ((pj_list*)node)->next = ((pj_list*)node)->prev = node;
+}
+
+PJ_IDEF(int) pj_list_empty(const pj_list_type * node)
+{
+ return ((pj_list*)node)->next == node;
+}
+*/
+
+PJ_IDEF(void)
+pj_list_insert_after(pj_list_type *pos, pj_list_type *node)
+{
+ ((pj_list*)node)->prev = pos;
+ ((pj_list*)node)->next = ((pj_list*)pos)->next;
+ ((pj_list*) ((pj_list*)pos)->next) ->prev = node;
+ ((pj_list*)pos)->next = node;
+}
+
+
+PJ_IDEF(void)
+pj_list_insert_before(pj_list_type *pos, pj_list_type *node)
+{
+ pj_list_insert_after(((pj_list*)pos)->prev, node);
+}
+
+
+PJ_IDEF(void)
+pj_list_insert_nodes_after(pj_list_type *pos, pj_list_type *lst)
+{
+ pj_list *lst_last = (pj_list *) ((pj_list*)lst)->prev;
+ pj_list *pos_next = (pj_list *) ((pj_list*)pos)->next;
+
+ pj_link_node(pos, lst);
+ pj_link_node(lst_last, pos_next);
+}
+
+PJ_IDEF(void)
+pj_list_insert_nodes_before(pj_list_type *pos, pj_list_type *lst)
+{
+ pj_list_insert_nodes_after(((pj_list*)pos)->prev, lst);
+}
+
+PJ_IDEF(void)
+pj_list_merge_last(pj_list_type *lst1, pj_list_type *lst2)
+{
+ pj_link_node(((pj_list*)lst1)->prev, ((pj_list*)lst2)->next);
+ pj_link_node(((pj_list*)lst2)->prev, lst1);
+ pj_list_init(lst2);
+}
+
+PJ_IDEF(void)
+pj_list_merge_first(pj_list_type *lst1, pj_list_type *lst2)
+{
+ pj_link_node(((pj_list*)lst2)->prev, ((pj_list*)lst1)->next);
+ pj_link_node(((pj_list*)lst1), ((pj_list*)lst2)->next);
+ pj_list_init(lst2);
+}
+
+PJ_IDEF(void)
+pj_list_erase(pj_list_type *node)
+{
+ pj_link_node( ((pj_list*)node)->prev, ((pj_list*)node)->next);
+}
+
+
+PJ_IDEF(pj_list_type*)
+pj_list_find_node(pj_list_type *list, pj_list_type *node)
+{
+ pj_list *p = (pj_list *) ((pj_list*)list)->next;
+ while (p != list && p != node)
+ p = (pj_list *) p->next;
+
+ return p==node ? p : NULL;
+}
+
+
+PJ_IDEF(pj_list_type*)
+pj_list_search(pj_list_type *list, void *value,
+ int (*comp)(void *value, const pj_list_type *node))
+{
+ pj_list *p = (pj_list *) ((pj_list*)list)->next;
+ while (p != list && (*comp)(value, p) != 0)
+ p = (pj_list *) p->next;
+
+ return p==list ? NULL : p;
+}
+
diff --git a/pjlib/include/pj/lock.h b/pjlib/include/pj/lock.h index 8c292040..e15eaf6c 100644 --- a/pjlib/include/pj/lock.h +++ b/pjlib/include/pj/lock.h @@ -1,138 +1,159 @@ -/* $Id$ - * - */ -#ifndef __PJ_LOCK_H__ -#define __PJ_LOCK_H__ - -/** - * @file lock.h - * @brief Higher abstraction for locking objects. - */ -#include <pj/types.h> - -PJ_BEGIN_DECL - -/** - * @defgroup PJ_LOCK Lock Objects - * @ingroup PJ_OS - * @{ - * - * <b>Lock Objects</b> are higher abstraction for different lock mechanisms. - * It offers the same API for manipulating different lock types (e.g. - * @ref PJ_MUTEX "mutex", @ref PJ_SEM "semaphores", or null locks). - * Because Lock Objects have the same API for different types of lock - * implementation, it can be passed around in function arguments. As the - * result, it can be used to control locking policy for a particular - * feature. - */ - - -/** - * Create simple, non recursive mutex lock object. - * - * @param pool Memory pool. - * @param name Lock object's name. - * @param lock Pointer to store the returned handle. - * - * @return PJ_SUCCESS or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_lock_create_simple_mutex( pj_pool_t *pool, - const char *name, - pj_lock_t **lock ); - -/** - * Create recursive mutex lock object. - * - * @param pool Memory pool. - * @param name Lock object's name. - * @param lock Pointer to store the returned handle. - * - * @return PJ_SUCCESS or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_lock_create_recursive_mutex( pj_pool_t *pool, - const char *name, - pj_lock_t **lock ); - - -/** - * Create NULL mutex. A NULL mutex doesn't actually have any synchronization - * object attached to it. - * - * @param pool Memory pool. - * @param name Lock object's name. - * @param lock Pointer to store the returned handle. - * - * @return PJ_SUCCESS or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_lock_create_null_mutex( pj_pool_t *pool, - const char *name, - pj_lock_t **lock ); - - -#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0 -/** - * Create semaphore lock object. - * - * @param pool Memory pool. - * @param name Lock object's name. - * @param initial Initial value of the semaphore. - * @param max Maximum value of the semaphore. - * @param lock Pointer to store the returned handle. - * - * @return PJ_SUCCESS or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_lock_create_semaphore( pj_pool_t *pool, - const char *name, - unsigned initial, - unsigned max, - pj_lock_t **lock ); - -#endif /* PJ_HAS_SEMAPHORE */ - -/** - * Acquire lock on the specified lock object. - * - * @param lock The lock object. - * - * @return PJ_SUCCESS or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_lock_acquire( pj_lock_t *lock ); - - -/** - * Try to acquire lock on the specified lock object. - * - * @param lock The lock object. - * - * @return PJ_SUCCESS or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_lock_tryacquire( pj_lock_t *lock ); - - -/** - * Release lock on the specified lock object. - * - * @param lock The lock object. - * - * @return PJ_SUCCESS or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_lock_release( pj_lock_t *lock ); - - -/** - * Destroy the lock object. - * - * @param lock The lock object. - * - * @return PJ_SUCCESS or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_lock_destroy( pj_lock_t *lock ); - - -/** @} */ - -PJ_END_DECL - - -#endif /* __PJ_LOCK_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 __PJ_LOCK_H__
+#define __PJ_LOCK_H__
+
+/**
+ * @file lock.h
+ * @brief Higher abstraction for locking objects.
+ */
+#include <pj/types.h>
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup PJ_LOCK Lock Objects
+ * @ingroup PJ_OS
+ * @{
+ *
+ * <b>Lock Objects</b> are higher abstraction for different lock mechanisms.
+ * It offers the same API for manipulating different lock types (e.g.
+ * @ref PJ_MUTEX "mutex", @ref PJ_SEM "semaphores", or null locks).
+ * Because Lock Objects have the same API for different types of lock
+ * implementation, it can be passed around in function arguments. As the
+ * result, it can be used to control locking policy for a particular
+ * feature.
+ */
+
+
+/**
+ * Create simple, non recursive mutex lock object.
+ *
+ * @param pool Memory pool.
+ * @param name Lock object's name.
+ * @param lock Pointer to store the returned handle.
+ *
+ * @return PJ_SUCCESS or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_lock_create_simple_mutex( pj_pool_t *pool,
+ const char *name,
+ pj_lock_t **lock );
+
+/**
+ * Create recursive mutex lock object.
+ *
+ * @param pool Memory pool.
+ * @param name Lock object's name.
+ * @param lock Pointer to store the returned handle.
+ *
+ * @return PJ_SUCCESS or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_lock_create_recursive_mutex( pj_pool_t *pool,
+ const char *name,
+ pj_lock_t **lock );
+
+
+/**
+ * Create NULL mutex. A NULL mutex doesn't actually have any synchronization
+ * object attached to it.
+ *
+ * @param pool Memory pool.
+ * @param name Lock object's name.
+ * @param lock Pointer to store the returned handle.
+ *
+ * @return PJ_SUCCESS or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_lock_create_null_mutex( pj_pool_t *pool,
+ const char *name,
+ pj_lock_t **lock );
+
+
+#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
+/**
+ * Create semaphore lock object.
+ *
+ * @param pool Memory pool.
+ * @param name Lock object's name.
+ * @param initial Initial value of the semaphore.
+ * @param max Maximum value of the semaphore.
+ * @param lock Pointer to store the returned handle.
+ *
+ * @return PJ_SUCCESS or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_lock_create_semaphore( pj_pool_t *pool,
+ const char *name,
+ unsigned initial,
+ unsigned max,
+ pj_lock_t **lock );
+
+#endif /* PJ_HAS_SEMAPHORE */
+
+/**
+ * Acquire lock on the specified lock object.
+ *
+ * @param lock The lock object.
+ *
+ * @return PJ_SUCCESS or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_lock_acquire( pj_lock_t *lock );
+
+
+/**
+ * Try to acquire lock on the specified lock object.
+ *
+ * @param lock The lock object.
+ *
+ * @return PJ_SUCCESS or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_lock_tryacquire( pj_lock_t *lock );
+
+
+/**
+ * Release lock on the specified lock object.
+ *
+ * @param lock The lock object.
+ *
+ * @return PJ_SUCCESS or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_lock_release( pj_lock_t *lock );
+
+
+/**
+ * Destroy the lock object.
+ *
+ * @param lock The lock object.
+ *
+ * @return PJ_SUCCESS or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_lock_destroy( pj_lock_t *lock );
+
+
+/** @} */
+
+PJ_END_DECL
+
+
+#endif /* __PJ_LOCK_H__ */
+
diff --git a/pjlib/include/pj/log.h b/pjlib/include/pj/log.h index 5dfe17c1..6e89d72b 100644 --- a/pjlib/include/pj/log.h +++ b/pjlib/include/pj/log.h @@ -1,306 +1,327 @@ -/* $Id$ - * - */ - -#ifndef __PJ_LOG_H__ -#define __PJ_LOG_H__ - -/** - * @file log.h - * @brief Logging Utility. - */ - -#include <pj/types.h> - - -PJ_BEGIN_DECL - -/** - * @defgroup PJ_MISC Miscelaneous - * @ingroup PJ - */ - -/** - * @defgroup PJ_LOG Logging Facility - * @ingroup PJ_MISC - * @{ - * - * The PJLIB logging facility is a configurable, flexible, and convenient - * way to write logging or trace information. - * - * To write to the log, one uses construct like below: - * - * <pre> - * ... - * PJ_LOG(3, ("main.c", "Starting hello...")); - * ... - * PJ_LOG(3, ("main.c", "Hello world from process %d", pj_getpid())); - * ... - * </pre> - * - * In the above example, the number @b 3 controls the verbosity level of - * the information (which means "information", by convention). The string - * "main.c" specifies the source or sender of the message. - * - * - * \section pj_log_quick_sample_sec Examples - * - * For examples, see: - * - @ref page_pjlib_samples_log_c. - * - */ - -/** - * Log decoration flag, to be specified with #pj_log_set_decor(). - */ -enum pj_log_decoration -{ - PJ_LOG_HAS_DAY_NAME = 1, /**< Include day name [default: no]. */ - PJ_LOG_HAS_YEAR = 2, /**< Include year digit [default: no] */ - PJ_LOG_HAS_MONTH = 4, /**< Include month [default: no] */ - PJ_LOG_HAS_DAY_OF_MON = 8, /**< Include day of month [default: no] */ - PJ_LOG_HAS_TIME = 16, /**< Include time [default: yes]. */ - PJ_LOG_HAS_MICRO_SEC = 32, /**< Include microseconds [yes] */ - PJ_LOG_HAS_SENDER = 64, /**< Include sender in the log [yes]. */ - PJ_LOG_HAS_NEWLINE = 128, /**< Terminate each call with newline [yes].*/ -}; - -/** - * Write log message. - * This is the main macro used to write text to the logging backend. - * - * @param level The logging verbosity level. Lower number indicates higher - * importance, with level zero indicates fatal error. Only - * numeral argument is permitted (e.g. not variable). - * @param arg Enclosed 'printf' like arguments, with the first - * argument is the sender, the second argument is format - * string and the following arguments are variable number of - * arguments suitable for the format string. - * - * Sample: - * \verbatim - PJ_LOG(2, (__FILE__, "current value is %d", value)); - \endverbatim - * @hideinitializer - */ -#define PJ_LOG(level,arg) pj_log_wrapper_##level(arg) - -/** - * Signature for function to be registered to the logging subsystem to - * write the actual log message to some output device. - * - * @param level Log level. - * @param data Log message. - * @param len Message length. - */ -typedef void pj_log_func(int level, const char *data, int len); - -/** - * Default logging writer function used by front end logger function. - * Application normally should NOT need to call this function, but - * rather use the PJ_LOG macro. - * - * @param level Log level. - * @param buffer Log message. - * @param len Message length. - */ -PJ_DECL(void) pj_log_write(int level, const char *buffer, int len); - - -#if PJ_LOG_MAX_LEVEL >= 1 - -/** - * Change log output function. The front-end logging functions will call - * this function to write the actual message to the desired device. - * By default, the front-end functions use pj_log_write() to write - * the messages, unless it's changed by calling this function. - * - * @param func The function that will be called to write the log - * messages to the desired device. - */ -PJ_DECL(void) pj_log_set_log_func( pj_log_func *func ); - -/** - * Get the current log output function that is used to write log messages. - * - * @return Current log output function. - */ -PJ_DECL(pj_log_func*) pj_log_get_log_func(void); - -/** - * Set maximum log level. Application can call this function to set - * the desired level of verbosity of the logging messages. The bigger the - * value, the more verbose the logging messages will be printed. However, - * the maximum level of verbosity can not exceed compile time value of - * PJ_LOG_MAX_LEVEL. - * - * @param level The maximum level of verbosity of the logging - * messages (6=very detailed..1=error only, 0=disabled) - */ -PJ_DECL(void) pj_log_set_level(int level); - -/** - * Get current maximum log verbositylevel. - * - * @return Current log maximum level. - */ -PJ_DECL(int) pj_log_get_level(void); - -/** - * Set log decoration. The log decoration flag controls what are printed - * to output device alongside the actual message. For example, application - * can specify that date/time information should be displayed with each - * log message. - * - * @param decor Bitmask combination of #pj_log_decoration to control - * the layout of the log message. - */ -PJ_DECL(void) pj_log_set_decor(unsigned decor); - -/** - * Get current log decoration flag. - * - * @return Log decoration flag. - */ -PJ_DECL(unsigned) pj_log_get_decor(void); - - -#else /* #if PJ_LOG_MAX_LEVEL >= 1 */ - -/** - * Change log output function. The front-end logging functions will call - * this function to write the actual message to the desired device. - * By default, the front-end functions use pj_log_write() to write - * the messages, unless it's changed by calling this function. - * - * @param func The function that will be called to write the log - * messages to the desired device. - */ -# define pj_log_set_log_func(func) - -/** - * Set maximum log level. Application can call this function to set - * the desired level of verbosity of the logging messages. The bigger the - * value, the more verbose the logging messages will be printed. However, - * the maximum level of verbosity can not exceed compile time value of - * PJ_LOG_MAX_LEVEL. - * - * @param level The maximum level of verbosity of the logging - * messages (6=very detailed..1=error only, 0=disabled) - */ -# define pj_log_set_level(level) - -/** - * Set log decoration. The log decoration flag controls what are printed - * to output device alongside the actual message. For example, application - * can specify that date/time information should be displayed with each - * log message. - * - * @param decor Bitmask combination of #pj_log_decoration to control - * the layout of the log message. - */ -# define pj_log_set_decor(decor) - -#endif /* #if PJ_LOG_MAX_LEVEL >= 1 */ - -/** - * @} - */ - -/////////////////////////////////////////////////////////////////////////////// -/* - * Log functions implementation prototypes. - * These functions are called by PJ_LOG macros according to verbosity - * level specified when calling the macro. Applications should not normally - * need to call these functions directly. - */ - -/** - * @def pj_log_wrapper_1(arg) - * Internal function to write log with verbosity 1. Will evaluate to - * empty expression if PJ_LOG_MAX_LEVEL is below 1. - * @param arg Log expression. - */ -#if PJ_LOG_MAX_LEVEL >= 1 - #define pj_log_wrapper_1(arg) pj_log_1 arg - /** Internal function. */ - PJ_DECL(void) pj_log_1(const char *src, const char *format, ...); -#else - #define pj_log_wrapper_1(arg) -#endif - -/** - * @def pj_log_wrapper_2(arg) - * Internal function to write log with verbosity 2. Will evaluate to - * empty expression if PJ_LOG_MAX_LEVEL is below 2. - * @param arg Log expression. - */ -#if PJ_LOG_MAX_LEVEL >= 2 - #define pj_log_wrapper_2(arg) pj_log_2 arg - /** Internal function. */ - PJ_DECL(void) pj_log_2(const char *src, const char *format, ...); -#else - #define pj_log_wrapper_2(arg) -#endif - -/** - * @def pj_log_wrapper_3(arg) - * Internal function to write log with verbosity 3. Will evaluate to - * empty expression if PJ_LOG_MAX_LEVEL is below 3. - * @param arg Log expression. - */ -#if PJ_LOG_MAX_LEVEL >= 3 - #define pj_log_wrapper_3(arg) pj_log_3 arg - /** Internal function. */ - PJ_DECL(void) pj_log_3(const char *src, const char *format, ...); -#else - #define pj_log_wrapper_3(arg) -#endif - -/** - * @def pj_log_wrapper_4(arg) - * Internal function to write log with verbosity 4. Will evaluate to - * empty expression if PJ_LOG_MAX_LEVEL is below 4. - * @param arg Log expression. - */ -#if PJ_LOG_MAX_LEVEL >= 4 - #define pj_log_wrapper_4(arg) pj_log_4 arg - /** Internal function. */ - PJ_DECL(void) pj_log_4(const char *src, const char *format, ...); -#else - #define pj_log_wrapper_4(arg) -#endif - -/** - * @def pj_log_wrapper_5(arg) - * Internal function to write log with verbosity 5. Will evaluate to - * empty expression if PJ_LOG_MAX_LEVEL is below 5. - * @param arg Log expression. - */ -#if PJ_LOG_MAX_LEVEL >= 5 - #define pj_log_wrapper_5(arg) pj_log_5 arg - /** Internal function. */ - PJ_DECL(void) pj_log_5(const char *src, const char *format, ...); -#else - #define pj_log_wrapper_5(arg) -#endif - -/** - * @def pj_log_wrapper_6(arg) - * Internal function to write log with verbosity 6. Will evaluate to - * empty expression if PJ_LOG_MAX_LEVEL is below 6. - * @param arg Log expression. - */ -#if PJ_LOG_MAX_LEVEL >= 6 - #define pj_log_wrapper_6(arg) pj_log_6 arg - /** Internal function. */ - PJ_DECL(void) pj_log_6(const char *src, const char *format, ...); -#else - #define pj_log_wrapper_6(arg) -#endif - - -PJ_END_DECL - -#endif /* __PJ_LOG_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 __PJ_LOG_H__
+#define __PJ_LOG_H__
+
+/**
+ * @file log.h
+ * @brief Logging Utility.
+ */
+
+#include <pj/types.h>
+
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup PJ_MISC Miscelaneous
+ * @ingroup PJ
+ */
+
+/**
+ * @defgroup PJ_LOG Logging Facility
+ * @ingroup PJ_MISC
+ * @{
+ *
+ * The PJLIB logging facility is a configurable, flexible, and convenient
+ * way to write logging or trace information.
+ *
+ * To write to the log, one uses construct like below:
+ *
+ * <pre>
+ * ...
+ * PJ_LOG(3, ("main.c", "Starting hello..."));
+ * ...
+ * PJ_LOG(3, ("main.c", "Hello world from process %d", pj_getpid()));
+ * ...
+ * </pre>
+ *
+ * In the above example, the number @b 3 controls the verbosity level of
+ * the information (which means "information", by convention). The string
+ * "main.c" specifies the source or sender of the message.
+ *
+ *
+ * \section pj_log_quick_sample_sec Examples
+ *
+ * For examples, see:
+ * - @ref page_pjlib_samples_log_c.
+ *
+ */
+
+/**
+ * Log decoration flag, to be specified with #pj_log_set_decor().
+ */
+enum pj_log_decoration
+{
+ PJ_LOG_HAS_DAY_NAME = 1, /**< Include day name [default: no]. */
+ PJ_LOG_HAS_YEAR = 2, /**< Include year digit [default: no] */
+ PJ_LOG_HAS_MONTH = 4, /**< Include month [default: no] */
+ PJ_LOG_HAS_DAY_OF_MON = 8, /**< Include day of month [default: no] */
+ PJ_LOG_HAS_TIME = 16, /**< Include time [default: yes]. */
+ PJ_LOG_HAS_MICRO_SEC = 32, /**< Include microseconds [yes] */
+ PJ_LOG_HAS_SENDER = 64, /**< Include sender in the log [yes]. */
+ PJ_LOG_HAS_NEWLINE = 128, /**< Terminate each call with newline [yes].*/
+};
+
+/**
+ * Write log message.
+ * This is the main macro used to write text to the logging backend.
+ *
+ * @param level The logging verbosity level. Lower number indicates higher
+ * importance, with level zero indicates fatal error. Only
+ * numeral argument is permitted (e.g. not variable).
+ * @param arg Enclosed 'printf' like arguments, with the first
+ * argument is the sender, the second argument is format
+ * string and the following arguments are variable number of
+ * arguments suitable for the format string.
+ *
+ * Sample:
+ * \verbatim
+ PJ_LOG(2, (__FILE__, "current value is %d", value));
+ \endverbatim
+ * @hideinitializer
+ */
+#define PJ_LOG(level,arg) pj_log_wrapper_##level(arg)
+
+/**
+ * Signature for function to be registered to the logging subsystem to
+ * write the actual log message to some output device.
+ *
+ * @param level Log level.
+ * @param data Log message.
+ * @param len Message length.
+ */
+typedef void pj_log_func(int level, const char *data, int len);
+
+/**
+ * Default logging writer function used by front end logger function.
+ * Application normally should NOT need to call this function, but
+ * rather use the PJ_LOG macro.
+ *
+ * @param level Log level.
+ * @param buffer Log message.
+ * @param len Message length.
+ */
+PJ_DECL(void) pj_log_write(int level, const char *buffer, int len);
+
+
+#if PJ_LOG_MAX_LEVEL >= 1
+
+/**
+ * Change log output function. The front-end logging functions will call
+ * this function to write the actual message to the desired device.
+ * By default, the front-end functions use pj_log_write() to write
+ * the messages, unless it's changed by calling this function.
+ *
+ * @param func The function that will be called to write the log
+ * messages to the desired device.
+ */
+PJ_DECL(void) pj_log_set_log_func( pj_log_func *func );
+
+/**
+ * Get the current log output function that is used to write log messages.
+ *
+ * @return Current log output function.
+ */
+PJ_DECL(pj_log_func*) pj_log_get_log_func(void);
+
+/**
+ * Set maximum log level. Application can call this function to set
+ * the desired level of verbosity of the logging messages. The bigger the
+ * value, the more verbose the logging messages will be printed. However,
+ * the maximum level of verbosity can not exceed compile time value of
+ * PJ_LOG_MAX_LEVEL.
+ *
+ * @param level The maximum level of verbosity of the logging
+ * messages (6=very detailed..1=error only, 0=disabled)
+ */
+PJ_DECL(void) pj_log_set_level(int level);
+
+/**
+ * Get current maximum log verbositylevel.
+ *
+ * @return Current log maximum level.
+ */
+PJ_DECL(int) pj_log_get_level(void);
+
+/**
+ * Set log decoration. The log decoration flag controls what are printed
+ * to output device alongside the actual message. For example, application
+ * can specify that date/time information should be displayed with each
+ * log message.
+ *
+ * @param decor Bitmask combination of #pj_log_decoration to control
+ * the layout of the log message.
+ */
+PJ_DECL(void) pj_log_set_decor(unsigned decor);
+
+/**
+ * Get current log decoration flag.
+ *
+ * @return Log decoration flag.
+ */
+PJ_DECL(unsigned) pj_log_get_decor(void);
+
+
+#else /* #if PJ_LOG_MAX_LEVEL >= 1 */
+
+/**
+ * Change log output function. The front-end logging functions will call
+ * this function to write the actual message to the desired device.
+ * By default, the front-end functions use pj_log_write() to write
+ * the messages, unless it's changed by calling this function.
+ *
+ * @param func The function that will be called to write the log
+ * messages to the desired device.
+ */
+# define pj_log_set_log_func(func)
+
+/**
+ * Set maximum log level. Application can call this function to set
+ * the desired level of verbosity of the logging messages. The bigger the
+ * value, the more verbose the logging messages will be printed. However,
+ * the maximum level of verbosity can not exceed compile time value of
+ * PJ_LOG_MAX_LEVEL.
+ *
+ * @param level The maximum level of verbosity of the logging
+ * messages (6=very detailed..1=error only, 0=disabled)
+ */
+# define pj_log_set_level(level)
+
+/**
+ * Set log decoration. The log decoration flag controls what are printed
+ * to output device alongside the actual message. For example, application
+ * can specify that date/time information should be displayed with each
+ * log message.
+ *
+ * @param decor Bitmask combination of #pj_log_decoration to control
+ * the layout of the log message.
+ */
+# define pj_log_set_decor(decor)
+
+#endif /* #if PJ_LOG_MAX_LEVEL >= 1 */
+
+/**
+ * @}
+ */
+
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * Log functions implementation prototypes.
+ * These functions are called by PJ_LOG macros according to verbosity
+ * level specified when calling the macro. Applications should not normally
+ * need to call these functions directly.
+ */
+
+/**
+ * @def pj_log_wrapper_1(arg)
+ * Internal function to write log with verbosity 1. Will evaluate to
+ * empty expression if PJ_LOG_MAX_LEVEL is below 1.
+ * @param arg Log expression.
+ */
+#if PJ_LOG_MAX_LEVEL >= 1
+ #define pj_log_wrapper_1(arg) pj_log_1 arg
+ /** Internal function. */
+ PJ_DECL(void) pj_log_1(const char *src, const char *format, ...);
+#else
+ #define pj_log_wrapper_1(arg)
+#endif
+
+/**
+ * @def pj_log_wrapper_2(arg)
+ * Internal function to write log with verbosity 2. Will evaluate to
+ * empty expression if PJ_LOG_MAX_LEVEL is below 2.
+ * @param arg Log expression.
+ */
+#if PJ_LOG_MAX_LEVEL >= 2
+ #define pj_log_wrapper_2(arg) pj_log_2 arg
+ /** Internal function. */
+ PJ_DECL(void) pj_log_2(const char *src, const char *format, ...);
+#else
+ #define pj_log_wrapper_2(arg)
+#endif
+
+/**
+ * @def pj_log_wrapper_3(arg)
+ * Internal function to write log with verbosity 3. Will evaluate to
+ * empty expression if PJ_LOG_MAX_LEVEL is below 3.
+ * @param arg Log expression.
+ */
+#if PJ_LOG_MAX_LEVEL >= 3
+ #define pj_log_wrapper_3(arg) pj_log_3 arg
+ /** Internal function. */
+ PJ_DECL(void) pj_log_3(const char *src, const char *format, ...);
+#else
+ #define pj_log_wrapper_3(arg)
+#endif
+
+/**
+ * @def pj_log_wrapper_4(arg)
+ * Internal function to write log with verbosity 4. Will evaluate to
+ * empty expression if PJ_LOG_MAX_LEVEL is below 4.
+ * @param arg Log expression.
+ */
+#if PJ_LOG_MAX_LEVEL >= 4
+ #define pj_log_wrapper_4(arg) pj_log_4 arg
+ /** Internal function. */
+ PJ_DECL(void) pj_log_4(const char *src, const char *format, ...);
+#else
+ #define pj_log_wrapper_4(arg)
+#endif
+
+/**
+ * @def pj_log_wrapper_5(arg)
+ * Internal function to write log with verbosity 5. Will evaluate to
+ * empty expression if PJ_LOG_MAX_LEVEL is below 5.
+ * @param arg Log expression.
+ */
+#if PJ_LOG_MAX_LEVEL >= 5
+ #define pj_log_wrapper_5(arg) pj_log_5 arg
+ /** Internal function. */
+ PJ_DECL(void) pj_log_5(const char *src, const char *format, ...);
+#else
+ #define pj_log_wrapper_5(arg)
+#endif
+
+/**
+ * @def pj_log_wrapper_6(arg)
+ * Internal function to write log with verbosity 6. Will evaluate to
+ * empty expression if PJ_LOG_MAX_LEVEL is below 6.
+ * @param arg Log expression.
+ */
+#if PJ_LOG_MAX_LEVEL >= 6
+ #define pj_log_wrapper_6(arg) pj_log_6 arg
+ /** Internal function. */
+ PJ_DECL(void) pj_log_6(const char *src, const char *format, ...);
+#else
+ #define pj_log_wrapper_6(arg)
+#endif
+
+
+PJ_END_DECL
+
+#endif /* __PJ_LOG_H__ */
+
diff --git a/pjlib/include/pj/os.h b/pjlib/include/pj/os.h index a1fef6b8..5e244504 100644 --- a/pjlib/include/pj/os.h +++ b/pjlib/include/pj/os.h @@ -1,329 +1,350 @@ -/* $Id$ - * - */ - -#ifndef __PJ_OS_H__ -#define __PJ_OS_H__ - -/** - * @file os.h - * @brief OS dependent functions - */ -#include <pj/types.h> - -PJ_BEGIN_DECL - -/** - * @defgroup PJ_OS Operating System Dependent Functionality. - * @ingroup PJ - */ - - -/////////////////////////////////////////////////////////////////////////////// -/** - * @defgroup PJ_THREAD Threads - * @ingroup PJ_OS - * @{ - * This module provides multithreading API. - * - * \section pj_thread_examples_sec Examples - * - * For examples, please see: - * - \ref page_pjlib_thread_test - * - \ref page_pjlib_sleep_test - * - */ - -/** - * Thread creation flags: - * - PJ_THREAD_SUSPENDED: specify that the thread should be created suspended. - */ -typedef enum pj_thread_create_flags -{ - PJ_THREAD_SUSPENDED = 1 -} pj_thread_create_flags; - - -/** - * Specify this as \a stack_size argument in #pj_thread_create() to specify - * that thread should use default stack size for the current platform. - */ -#define PJ_THREAD_DEFAULT_STACK_SIZE 0 - -/** - * Type of thread entry function. - */ -typedef int (PJ_THREAD_FUNC pj_thread_proc)(void*); - -/** - * Size of thread struct. - */ -#if !defined(PJ_THREAD_DESC_SIZE) -# define PJ_THREAD_DESC_SIZE (16) -#endif - -/** - * Thread structure, to thread's state when the thread is created by external - * or native API. - */ -typedef long pj_thread_desc[PJ_THREAD_DESC_SIZE]; - -/** - * Get process ID. - * @return process ID. - */ -PJ_DECL(pj_uint32_t) pj_getpid(void); - -/** - * Create a new thread. - * - * @param pool The memory pool from which the thread record - * will be allocated from. - * @param thread_name The optional name to be assigned to the thread. - * @param proc Thread entry function. - * @param arg Argument to be passed to the thread entry function. - * @param stack_size The size of the stack for the new thread, or ZERO or - * PJ_THREAD_DEFAULT_STACK_SIZE to let the - * library choose the reasonable size for the stack. - * For some systems, the stack will be allocated from - * the pool, so the pool must have suitable capacity. - * @param flags Flags for thread creation, which is bitmask combination - * from enum pj_thread_create_flags. - * @param thread Pointer to hold the newly created thread. - * - * @return PJ_SUCCESS on success, or the error code. - */ -PJ_DECL(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 ); - -/** - * Register a thread that was created by external or native API to PJLIB. - * This function must be called in the context of the thread being registered. - * When the thread is created by external function or API call, - * it must be 'registered' to PJLIB using pj_thread_register(), so that it can - * cooperate with PJLIB's framework. During registration, some data needs to - * be maintained, and this data must remain available during the thread's - * lifetime. - * - * @param thread_name The optional name to be assigned to the thread. - * @param desc Thread descriptor, which must be available throughout - * the lifetime of the thread. - * @param thread Pointer to hold the created thread handle. - * - * @return PJ_SUCCESS on success, or the error code. - */ -PJ_DECL(pj_status_t) pj_thread_register ( const char *thread_name, - pj_thread_desc desc, - pj_thread_t **thread); - -/** - * Get thread name. - * - * @param thread The thread handle. - * - * @return Thread name as null terminated string. - */ -PJ_DECL(const char*) pj_thread_get_name(pj_thread_t *thread); - -/** - * Resume a suspended thread. - * - * @param thread The thread handle. - * - * @return zero on success. - */ -PJ_DECL(pj_status_t) pj_thread_resume(pj_thread_t *thread); - -/** - * Get the current thread. - * - * @return Thread handle of current thread. - */ -PJ_DECL(pj_thread_t*) pj_thread_this(void); - -/** - * Join thread. - * This function will block the caller thread until the specified thread exits. - * - * @param thread The thread handle. - * - * @return zero on success. - */ -PJ_DECL(pj_status_t) pj_thread_join(pj_thread_t *thread); - - -/** - * Destroy thread and release resources allocated for the thread. - * However, the memory allocated for the pj_thread_t itself will only be released - * when the pool used to create the thread is destroyed. - * - * @param thread The thread handle. - * - * @return zero on success. - */ -PJ_DECL(pj_status_t) pj_thread_destroy(pj_thread_t *thread); - - -/** - * Put the current thread to sleep for the specified miliseconds. - * - * @param msec Miliseconds delay. - * - * @return zero if successfull. - */ -PJ_DECL(pj_status_t) pj_thread_sleep(unsigned msec); - -/** - * @def PJ_CHECK_STACK() - * PJ_CHECK_STACK() macro is used to check the sanity of the stack. - * The OS implementation may check that no stack overflow occurs, and - * it also may collect statistic about stack usage. - */ -#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0 - -# define PJ_CHECK_STACK() pj_thread_check_stack(__FILE__, __LINE__) - -/** @internal - * The implementation of stack checking. - */ -PJ_DECL(void) pj_thread_check_stack(const char *file, int line); - -/** @internal - * Get maximum stack usage statistic. - */ -PJ_DECL(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread); - -/** @internal - * Dump thread stack status. - */ -PJ_DECL(pj_status_t) pj_thread_get_stack_info(pj_thread_t *thread, - const char **file, - int *line); -#else - -# define PJ_CHECK_STACK() -/** pj_thread_get_stack_max_usage() for the thread */ -# define pj_thread_get_stack_max_usage(thread) 0 -/** pj_thread_get_stack_info() for the thread */ -# define pj_thread_get_stack_info(thread,f,l) (*(f)="",*(l)=0) -#endif /* PJ_OS_HAS_CHECK_STACK */ - -/** - * @} - */ - -/////////////////////////////////////////////////////////////////////////////// -/** - * @defgroup PJ_TLS Thread Local Storage. - * @ingroup PJ_OS - * @{ - */ - -/** - * Allocate thread local storage index. The initial value of the variable at - * the index is zero. - * - * @param index Pointer to hold the return value. - * @return PJ_SUCCESS on success, or the error code. - */ -PJ_DECL(pj_status_t) pj_thread_local_alloc(long *index); - -/** - * Deallocate thread local variable. - * - * @param index The variable index. - */ -PJ_DECL(void) pj_thread_local_free(long index); - -/** - * Set the value of thread local variable. - * - * @param index The index of the variable. - * @param value The value. - */ -PJ_DECL(pj_status_t) pj_thread_local_set(long index, void *value); - -/** - * Get the value of thread local variable. - * - * @param index The index of the variable. - * @return The value. - */ -PJ_DECL(void*) pj_thread_local_get(long index); - - -/** - * @} - */ - - -/////////////////////////////////////////////////////////////////////////////// -/** - * @defgroup PJ_ATOMIC Atomic Variables - * @ingroup PJ_OS - * @{ - * - * This module provides API to manipulate atomic variables. - * - * \section pj_atomic_examples_sec Examples - * - * For some example codes, please see: - * - @ref page_pjlib_atomic_test - */ - - -/** - * Create atomic variable. - * - * @param pool The pool. - * @param initial The initial value of the atomic variable. - * @param atomic Pointer to hold the atomic variable upon return. - * - * @return PJ_SUCCESS on success, or the error code. - */ -PJ_DECL(pj_status_t) pj_atomic_create( pj_pool_t *pool, - pj_atomic_value_t initial, - pj_atomic_t **atomic ); - -/** - * Destroy atomic variable. - * - * @param atomic_var the atomic variable. - * - * @return PJ_SUCCESS if success. - */ -PJ_DECL(pj_status_t) pj_atomic_destroy( pj_atomic_t *atomic_var ); - -/** - * Set the value of an atomic type, and return the previous value. - * - * @param atomic_var the atomic variable. - * @param value value to be set to the variable. - */ -PJ_DECL(void) pj_atomic_set( pj_atomic_t *atomic_var, - pj_atomic_value_t value); - -/** - * Get the value of an atomic type. - * - * @param atomic_var the atomic variable. - * - * @return the value of the atomic variable. - */ -PJ_DECL(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var); - -/** - * Increment the value of an atomic type. - * - * @param atomic_var the atomic variable. - */ -PJ_DECL(void) pj_atomic_inc(pj_atomic_t *atomic_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
+ */
+
+#ifndef __PJ_OS_H__
+#define __PJ_OS_H__
+
+/**
+ * @file os.h
+ * @brief OS dependent functions
+ */
+#include <pj/types.h>
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup PJ_OS Operating System Dependent Functionality.
+ * @ingroup PJ
+ */
+
+
+///////////////////////////////////////////////////////////////////////////////
+/**
+ * @defgroup PJ_THREAD Threads
+ * @ingroup PJ_OS
+ * @{
+ * This module provides multithreading API.
+ *
+ * \section pj_thread_examples_sec Examples
+ *
+ * For examples, please see:
+ * - \ref page_pjlib_thread_test
+ * - \ref page_pjlib_sleep_test
+ *
+ */
+
+/**
+ * Thread creation flags:
+ * - PJ_THREAD_SUSPENDED: specify that the thread should be created suspended.
+ */
+typedef enum pj_thread_create_flags
+{
+ PJ_THREAD_SUSPENDED = 1
+} pj_thread_create_flags;
+
+
+/**
+ * Specify this as \a stack_size argument in #pj_thread_create() to specify
+ * that thread should use default stack size for the current platform.
+ */
+#define PJ_THREAD_DEFAULT_STACK_SIZE 0
+
+/**
+ * Type of thread entry function.
+ */
+typedef int (PJ_THREAD_FUNC pj_thread_proc)(void*);
+
+/**
+ * Size of thread struct.
+ */
+#if !defined(PJ_THREAD_DESC_SIZE)
+# define PJ_THREAD_DESC_SIZE (16)
+#endif
+
+/**
+ * Thread structure, to thread's state when the thread is created by external
+ * or native API.
+ */
+typedef long pj_thread_desc[PJ_THREAD_DESC_SIZE];
+
+/**
+ * Get process ID.
+ * @return process ID.
+ */
+PJ_DECL(pj_uint32_t) pj_getpid(void);
+
+/**
+ * Create a new thread.
+ *
+ * @param pool The memory pool from which the thread record
+ * will be allocated from.
+ * @param thread_name The optional name to be assigned to the thread.
+ * @param proc Thread entry function.
+ * @param arg Argument to be passed to the thread entry function.
+ * @param stack_size The size of the stack for the new thread, or ZERO or
+ * PJ_THREAD_DEFAULT_STACK_SIZE to let the
+ * library choose the reasonable size for the stack.
+ * For some systems, the stack will be allocated from
+ * the pool, so the pool must have suitable capacity.
+ * @param flags Flags for thread creation, which is bitmask combination
+ * from enum pj_thread_create_flags.
+ * @param thread Pointer to hold the newly created thread.
+ *
+ * @return PJ_SUCCESS on success, or the error code.
+ */
+PJ_DECL(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 );
+
+/**
+ * Register a thread that was created by external or native API to PJLIB.
+ * This function must be called in the context of the thread being registered.
+ * When the thread is created by external function or API call,
+ * it must be 'registered' to PJLIB using pj_thread_register(), so that it can
+ * cooperate with PJLIB's framework. During registration, some data needs to
+ * be maintained, and this data must remain available during the thread's
+ * lifetime.
+ *
+ * @param thread_name The optional name to be assigned to the thread.
+ * @param desc Thread descriptor, which must be available throughout
+ * the lifetime of the thread.
+ * @param thread Pointer to hold the created thread handle.
+ *
+ * @return PJ_SUCCESS on success, or the error code.
+ */
+PJ_DECL(pj_status_t) pj_thread_register ( const char *thread_name,
+ pj_thread_desc desc,
+ pj_thread_t **thread);
+
+/**
+ * Get thread name.
+ *
+ * @param thread The thread handle.
+ *
+ * @return Thread name as null terminated string.
+ */
+PJ_DECL(const char*) pj_thread_get_name(pj_thread_t *thread);
+
+/**
+ * Resume a suspended thread.
+ *
+ * @param thread The thread handle.
+ *
+ * @return zero on success.
+ */
+PJ_DECL(pj_status_t) pj_thread_resume(pj_thread_t *thread);
+
+/**
+ * Get the current thread.
+ *
+ * @return Thread handle of current thread.
+ */
+PJ_DECL(pj_thread_t*) pj_thread_this(void);
+
+/**
+ * Join thread.
+ * This function will block the caller thread until the specified thread exits.
+ *
+ * @param thread The thread handle.
+ *
+ * @return zero on success.
+ */
+PJ_DECL(pj_status_t) pj_thread_join(pj_thread_t *thread);
+
+
+/**
+ * Destroy thread and release resources allocated for the thread.
+ * However, the memory allocated for the pj_thread_t itself will only be released
+ * when the pool used to create the thread is destroyed.
+ *
+ * @param thread The thread handle.
+ *
+ * @return zero on success.
+ */
+PJ_DECL(pj_status_t) pj_thread_destroy(pj_thread_t *thread);
+
+
+/**
+ * Put the current thread to sleep for the specified miliseconds.
+ *
+ * @param msec Miliseconds delay.
+ *
+ * @return zero if successfull.
+ */
+PJ_DECL(pj_status_t) pj_thread_sleep(unsigned msec);
+
+/**
+ * @def PJ_CHECK_STACK()
+ * PJ_CHECK_STACK() macro is used to check the sanity of the stack.
+ * The OS implementation may check that no stack overflow occurs, and
+ * it also may collect statistic about stack usage.
+ */
+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
+
+# define PJ_CHECK_STACK() pj_thread_check_stack(__FILE__, __LINE__)
+
+/** @internal
+ * The implementation of stack checking.
+ */
+PJ_DECL(void) pj_thread_check_stack(const char *file, int line);
+
+/** @internal
+ * Get maximum stack usage statistic.
+ */
+PJ_DECL(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread);
+
+/** @internal
+ * Dump thread stack status.
+ */
+PJ_DECL(pj_status_t) pj_thread_get_stack_info(pj_thread_t *thread,
+ const char **file,
+ int *line);
+#else
+
+# define PJ_CHECK_STACK()
+/** pj_thread_get_stack_max_usage() for the thread */
+# define pj_thread_get_stack_max_usage(thread) 0
+/** pj_thread_get_stack_info() for the thread */
+# define pj_thread_get_stack_info(thread,f,l) (*(f)="",*(l)=0)
+#endif /* PJ_OS_HAS_CHECK_STACK */
+
+/**
+ * @}
+ */
+
+///////////////////////////////////////////////////////////////////////////////
+/**
+ * @defgroup PJ_TLS Thread Local Storage.
+ * @ingroup PJ_OS
+ * @{
+ */
+
+/**
+ * Allocate thread local storage index. The initial value of the variable at
+ * the index is zero.
+ *
+ * @param index Pointer to hold the return value.
+ * @return PJ_SUCCESS on success, or the error code.
+ */
+PJ_DECL(pj_status_t) pj_thread_local_alloc(long *index);
+
+/**
+ * Deallocate thread local variable.
+ *
+ * @param index The variable index.
+ */
+PJ_DECL(void) pj_thread_local_free(long index);
+
+/**
+ * Set the value of thread local variable.
+ *
+ * @param index The index of the variable.
+ * @param value The value.
+ */
+PJ_DECL(pj_status_t) pj_thread_local_set(long index, void *value);
+
+/**
+ * Get the value of thread local variable.
+ *
+ * @param index The index of the variable.
+ * @return The value.
+ */
+PJ_DECL(void*) pj_thread_local_get(long index);
+
+
+/**
+ * @}
+ */
+
+
+///////////////////////////////////////////////////////////////////////////////
+/**
+ * @defgroup PJ_ATOMIC Atomic Variables
+ * @ingroup PJ_OS
+ * @{
+ *
+ * This module provides API to manipulate atomic variables.
+ *
+ * \section pj_atomic_examples_sec Examples
+ *
+ * For some example codes, please see:
+ * - @ref page_pjlib_atomic_test
+ */
+
+
+/**
+ * Create atomic variable.
+ *
+ * @param pool The pool.
+ * @param initial The initial value of the atomic variable.
+ * @param atomic Pointer to hold the atomic variable upon return.
+ *
+ * @return PJ_SUCCESS on success, or the error code.
+ */
+PJ_DECL(pj_status_t) pj_atomic_create( pj_pool_t *pool,
+ pj_atomic_value_t initial,
+ pj_atomic_t **atomic );
+
+/**
+ * Destroy atomic variable.
+ *
+ * @param atomic_var the atomic variable.
+ *
+ * @return PJ_SUCCESS if success.
+ */
+PJ_DECL(pj_status_t) pj_atomic_destroy( pj_atomic_t *atomic_var );
+
+/**
+ * Set the value of an atomic type, and return the previous value.
+ *
+ * @param atomic_var the atomic variable.
+ * @param value value to be set to the variable.
+ */
+PJ_DECL(void) pj_atomic_set( pj_atomic_t *atomic_var,
+ pj_atomic_value_t value);
+
+/**
+ * Get the value of an atomic type.
+ *
+ * @param atomic_var the atomic variable.
+ *
+ * @return the value of the atomic variable.
+ */
+PJ_DECL(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var);
+
+/**
+ * Increment the value of an atomic type.
+ *
+ * @param atomic_var the atomic variable.
+ */
+PJ_DECL(void) pj_atomic_inc(pj_atomic_t *atomic_var);
+
/**
* Increment the value of an atomic type and get the result.
*
@@ -333,12 +354,12 @@ PJ_DECL(void) pj_atomic_inc(pj_atomic_t *atomic_var); */
PJ_DECL(pj_atomic_value_t) pj_atomic_inc_and_get(pj_atomic_t *atomic_var);
-/** - * Decrement the value of an atomic type. - * - * @param atomic_var the atomic variable. - */ -PJ_DECL(void) pj_atomic_dec(pj_atomic_t *atomic_var); +/**
+ * Decrement the value of an atomic type.
+ *
+ * @param atomic_var the atomic variable.
+ */
+PJ_DECL(void) pj_atomic_dec(pj_atomic_t *atomic_var);
/**
* Decrement the value of an atomic type and get the result.
@@ -348,15 +369,15 @@ PJ_DECL(void) pj_atomic_dec(pj_atomic_t *atomic_var); * @return The decremented value.
*/
PJ_DECL(pj_atomic_value_t) pj_atomic_dec_and_get(pj_atomic_t *atomic_var);
- -/** - * Add a value to an atomic type. - * - * @param atomic_var The atomic variable. - * @param value Value to be added. - */ -PJ_DECL(void) pj_atomic_add( pj_atomic_t *atomic_var, - pj_atomic_value_t value); +
+/**
+ * Add a value to an atomic type.
+ *
+ * @param atomic_var The atomic variable.
+ * @param value Value to be added.
+ */
+PJ_DECL(void) pj_atomic_add( pj_atomic_t *atomic_var,
+ pj_atomic_value_t value);
/**
* Add a value to an atomic type and get the result.
@@ -368,576 +389,576 @@ PJ_DECL(void) pj_atomic_add( pj_atomic_t *atomic_var, */
PJ_DECL(pj_atomic_value_t) pj_atomic_add_and_get( pj_atomic_t *atomic_var,
pj_atomic_value_t value);
- -/** - * @} - */ - -/////////////////////////////////////////////////////////////////////////////// -/** - * @defgroup PJ_MUTEX Mutexes. - * @ingroup PJ_OS - * @{ - * - * Mutex manipulation. Alternatively, application can use higher abstraction - * for lock objects, which provides uniform API for all kinds of lock - * mechanisms, including mutex. See @ref PJ_LOCK for more information. - */ - -/** - * Mutex types: - * - PJ_MUTEX_DEFAULT: default mutex type, which is system dependent. - * - PJ_MUTEX_SIMPLE: non-recursive mutex. - * - PJ_MUTEX_RECURSIVE: recursive mutex. - */ -typedef enum pj_mutex_type_e -{ - PJ_MUTEX_DEFAULT, - PJ_MUTEX_SIMPLE, - PJ_MUTEX_RECURSE, -} pj_mutex_type_e; - - -/** - * Create mutex of the specified type. - * - * @param pool The pool. - * @param name Name to be associated with the mutex (for debugging). - * @param type The type of the mutex, of type #pj_mutex_type_e. - * @param mutex Pointer to hold the returned mutex instance. - * - * @return PJ_SUCCESS on success, or the error code. - */ -PJ_DECL(pj_status_t) pj_mutex_create(pj_pool_t *pool, - const char *name, - int type, - pj_mutex_t **mutex); - -/** - * Create simple, non-recursive mutex. - * This function is a simple wrapper for #pj_mutex_create to create - * non-recursive mutex. - * - * @param pool The pool. - * @param name Mutex name. - * @param mutex Pointer to hold the returned mutex instance. - * - * @return PJ_SUCCESS on success, or the error code. - */ -PJ_DECL(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool, const char *name, - pj_mutex_t **mutex ); - -/** - * Create recursive mutex. - * This function is a simple wrapper for #pj_mutex_create to create - * recursive mutex. - * - * @param pool The pool. - * @param name Mutex name. - * @param mutex Pointer to hold the returned mutex instance. - * - * @return PJ_SUCCESS on success, or the error code. - */ -PJ_DECL(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool, - const char *name, - pj_mutex_t **mutex ); - -/** - * Acquire mutex lock. - * - * @param mutex The mutex. - * @return PJ_SUCCESS on success, or the error code. - */ -PJ_DECL(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex); - -/** - * Release mutex lock. - * - * @param mutex The mutex. - * @return PJ_SUCCESS on success, or the error code. - */ -PJ_DECL(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex); - -/** - * Try to acquire mutex lock. - * - * @param mutex The mutex. - * @return PJ_SUCCESS on success, or the error code if the - * lock couldn't be acquired. - */ -PJ_DECL(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex); - -/** - * Destroy mutex. - * - * @param mutex Te mutex. - * @return PJ_SUCCESS on success, or the error code. - */ -PJ_DECL(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex); - -/** - * Determine whether calling thread is owning the mutex (only available when - * PJ_DEBUG is set). - * @param mutex The mutex. - * @return Non-zero if yes. - */ -#if defined(PJ_DEBUG) && PJ_DEBUG != 0 - PJ_DECL(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex); -#else -# define pj_mutex_is_locked(mutex) 1 -#endif - -/** - * @} - */ - -/////////////////////////////////////////////////////////////////////////////// -/** - * @defgroup PJ_CRIT_SEC Critical sections. - * @ingroup PJ_OS - * @{ - * Critical section protection can be used to protect regions where: - * - mutual exclusion protection is needed. - * - it's rather too expensive to create a mutex. - * - the time spent in the region is very very brief. - * - * Critical section is a global object, and it prevents any threads from - * entering any regions that are protected by critical section once a thread - * is already in the section. - * - * Critial section is \a not recursive! - * - * Application <b>MUST NOT</b> call any functions that may cause current - * thread to block (such as allocating memory, performing I/O, locking mutex, - * etc.) while holding the critical section. - */ -/** - * Enter critical section. - */ -PJ_DECL(void) pj_enter_critical_section(void); - -/** - * Leave critical section. - */ -PJ_DECL(void) pj_leave_critical_section(void); - -/** - * @} - */ - -/////////////////////////////////////////////////////////////////////////////// -#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0 -/** - * @defgroup PJ_SEM Semaphores. - * @ingroup PJ_OS - * @{ - * - * This module provides abstraction for semaphores, where available. - */ - -/** - * Create semaphore. - * - * @param pool The pool. - * @param name Name to be assigned to the semaphore (for logging purpose) - * @param initial The initial count of the semaphore. - * @param max The maximum count of the semaphore. - * @param sem Pointer to hold the semaphore created. - * - * @return PJ_SUCCESS on success, or the error code. - */ -PJ_DECL(pj_status_t) pj_sem_create( pj_pool_t *pool, - const char *name, - unsigned initial, - unsigned max, - pj_sem_t **sem); - -/** - * Wait for semaphore. - * - * @param sem The semaphore. - * - * @return PJ_SUCCESS on success, or the error code. - */ -PJ_DECL(pj_status_t) pj_sem_wait(pj_sem_t *sem); - -/** - * Try wait for semaphore. - * - * @param sem The semaphore. - * - * @return PJ_SUCCESS on success, or the error code. - */ -PJ_DECL(pj_status_t) pj_sem_trywait(pj_sem_t *sem); - -/** - * Release semaphore. - * - * @param sem The semaphore. - * - * @return PJ_SUCCESS on success, or the error code. - */ -PJ_DECL(pj_status_t) pj_sem_post(pj_sem_t *sem); - -/** - * Destroy semaphore. - * - * @param sem The semaphore. - * - * @return PJ_SUCCESS on success, or the error code. - */ -PJ_DECL(pj_status_t) pj_sem_destroy(pj_sem_t *sem); - -/** - * @} - */ -#endif /* PJ_HAS_SEMAPHORE */ - - -/////////////////////////////////////////////////////////////////////////////// -#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0 -/** - * @defgroup PJ_EVENT Event Object. - * @ingroup PJ_OS - * @{ - * - * This module provides abstraction to event object (e.g. Win32 Event) where - * available. Event objects can be used for synchronization among threads. - */ - -/** - * Create event object. - * - * @param pool The pool. - * @param name The name of the event object (for logging purpose). - * @param manual_reset Specify whether the event is manual-reset - * @param initial Specify the initial state of the event object. - * @param event Pointer to hold the returned event object. - * - * @return event handle, or NULL if failed. - */ -PJ_DECL(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); - -/** - * Wait for event to be signaled. - * - * @param event The event object. - * - * @return zero if successfull. - */ -PJ_DECL(pj_status_t) pj_event_wait(pj_event_t *event); - -/** - * Try wait for event object to be signalled. - * - * @param event The event object. - * - * @return zero if successfull. - */ -PJ_DECL(pj_status_t) pj_event_trywait(pj_event_t *event); - -/** - * Set the event object state to signaled. For auto-reset event, this - * will only release the first thread that are waiting on the event. For - * manual reset event, the state remains signaled until the event is reset. - * If there is no thread waiting on the event, the event object state - * remains signaled. - * - * @param event The event object. - * - * @return zero if successfull. - */ -PJ_DECL(pj_status_t) pj_event_set(pj_event_t *event); - -/** - * Set the event object to signaled state to release appropriate number of - * waiting threads and then reset the event object to non-signaled. For - * manual-reset event, this function will release all waiting threads. For - * auto-reset event, this function will only release one waiting thread. - * - * @param event The event object. - * - * @return zero if successfull. - */ -PJ_DECL(pj_status_t) pj_event_pulse(pj_event_t *event); - -/** - * Set the event object state to non-signaled. - * - * @param event The event object. - * - * @return zero if successfull. - */ -PJ_DECL(pj_status_t) pj_event_reset(pj_event_t *event); - -/** - * Destroy the event object. - * - * @param event The event object. - * - * @return zero if successfull. - */ -PJ_DECL(pj_status_t) pj_event_destroy(pj_event_t *event); - -/** - * @} - */ -#endif /* PJ_HAS_EVENT_OBJ */ - -/////////////////////////////////////////////////////////////////////////////// -/** - * @addtogroup PJ_TIME Time Data Type and Manipulation. - * @ingroup PJ_OS - * @{ - * This module provides API for manipulating time. - * - * \section pj_time_examples_sec Examples - * - * For examples, please see: - * - \ref page_pjlib_sleep_test - */ - -/** - * Get current time of day in local representation. - * - * @param tv Variable to store the result. - * - * @return zero if successfull. - */ -PJ_DECL(pj_status_t) pj_gettimeofday(pj_time_val *tv); - - -/** - * Parse time value into date/time representation. - * - * @param tv The time. - * @param pt Variable to store the date time result. - * - * @return zero if successfull. - */ -PJ_DECL(pj_status_t) pj_time_decode(const pj_time_val *tv, pj_parsed_time *pt); - -/** - * Encode date/time to time value. - * - * @param pt The date/time. - * @param tv Variable to store time value result. - * - * @return zero if successfull. - */ -PJ_DECL(pj_status_t) pj_time_encode(const pj_parsed_time *pt, pj_time_val *tv); - -/** - * Convert local time to GMT. - * - * @param tv Time to convert. - * - * @return zero if successfull. - */ -PJ_DECL(pj_status_t) pj_time_local_to_gmt(pj_time_val *tv); - -/** - * Convert GMT to local time. - * - * @param tv Time to convert. - * - * @return zero if successfull. - */ -PJ_DECL(pj_status_t) pj_time_gmt_to_local(pj_time_val *tv); - -/** - * @} - */ - -/////////////////////////////////////////////////////////////////////////////// -#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0 - -/** - * @defgroup PJ_TERM Terminal - * @ingroup PJ_OS - * @{ - */ - -/** - * Set current terminal color. - * - * @param color The RGB color. - * - * @return zero on success. - */ -PJ_DECL(pj_status_t) pj_term_set_color(pj_color_t color); - -/** - * Get current terminal foreground color. - * - * @return RGB color. - */ -PJ_DECL(pj_color_t) pj_term_get_color(void); - -/** - * @} - */ - -#endif /* PJ_TERM_HAS_COLOR */ - -/////////////////////////////////////////////////////////////////////////////// -/** - * @defgroup PJ_TIMESTAMP High Resolution Timestamp - * @ingroup PJ_OS - * @{ - * - * PJLIB provides <b>High Resolution Timestamp</b> API to access highest - * resolution timestamp value provided by the platform. The API is usefull - * to measure precise elapsed time, and can be used in applications such - * as profiling. - * - * The timestamp value is represented in cycles, and can be related to - * normal time (in seconds or sub-seconds) using various functions provided. - * - * \section pj_timestamp_examples_sec Examples - * - * For examples, please see: - * - \ref page_pjlib_sleep_test - * - \ref page_pjlib_timestamp_test - */ - -/* - * High resolution timer. - */ -#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0 - -/** - * This structure represents high resolution (64bit) time value. The time - * values represent time in cycles, which is retrieved by calling - * #pj_get_timestamp(). - */ -typedef union pj_timestamp -{ - struct - { -#if defined(PJ_IS_LITTLE_ENDIAN) && PJ_IS_LITTLE_ENDIAN!=0 - pj_uint32_t lo; /**< Low 32-bit value of the 64-bit value. */ - pj_uint32_t hi; /**< high 32-bit value of the 64-bit value. */ -#else - pj_uint32_t hi; /**< high 32-bit value of the 64-bit value. */ - pj_uint32_t lo; /**< Low 32-bit value of the 64-bit value. */ -#endif - } u32; /**< The 64-bit value as two 32-bit values. */ - -#if PJ_HAS_INT64 - pj_uint64_t u64; /**< The whole 64-bit value, where available. */ -#endif -} pj_timestamp; - - -/** - * Acquire high resolution timer value. The time value are stored - * in cycles. - * - * @param ts High resolution timer value. - * @return PJ_SUCCESS or the appropriate error code. - * - * @see pj_get_timestamp_freq(). - */ -PJ_DECL(pj_status_t) pj_get_timestamp(pj_timestamp *ts); - -/** - * Get high resolution timer frequency, in cycles per second. - * - * @param freq Timer frequency, in cycles per second. - * @return PJ_SUCCESS or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq); - -/** - * Calculate the elapsed time, and store it in pj_time_val. - * This function calculates the elapsed time using highest precision - * calculation that is available for current platform, considering - * whether floating point or 64-bit precision arithmetic is available. - * For maximum portability, application should prefer to use this function - * rather than calculating the elapsed time by itself. - * - * @param start The starting timestamp. - * @param stop The end timestamp. - * - * @return Elapsed time as #pj_time_val. - * - * @see pj_elapsed_usec(), pj_elapsed_cycle(), pj_elapsed_nanosec() - */ -PJ_DECL(pj_time_val) pj_elapsed_time( const pj_timestamp *start, - const pj_timestamp *stop ); - -/** - * Calculate the elapsed time in 32-bit microseconds. - * This function calculates the elapsed time using highest precision - * calculation that is available for current platform, considering - * whether floating point or 64-bit precision arithmetic is available. - * For maximum portability, application should prefer to use this function - * rather than calculating the elapsed time by itself. - * - * @param start The starting timestamp. - * @param stop The end timestamp. - * - * @return Elapsed time in microsecond. - * - * @see pj_elapsed_time(), pj_elapsed_cycle(), pj_elapsed_nanosec() - */ -PJ_DECL(pj_uint32_t) pj_elapsed_usec( const pj_timestamp *start, - const pj_timestamp *stop ); - -/** - * Calculate the elapsed time in 32-bit nanoseconds. - * This function calculates the elapsed time using highest precision - * calculation that is available for current platform, considering - * whether floating point or 64-bit precision arithmetic is available. - * For maximum portability, application should prefer to use this function - * rather than calculating the elapsed time by itself. - * - * @param start The starting timestamp. - * @param stop The end timestamp. - * - * @return Elapsed time in nanoseconds. - * - * @see pj_elapsed_time(), pj_elapsed_cycle(), pj_elapsed_usec() - */ -PJ_DECL(pj_uint32_t) pj_elapsed_nanosec( const pj_timestamp *start, - const pj_timestamp *stop ); - -/** - * Calculate the elapsed time in 32-bit cycles. - * This function calculates the elapsed time using highest precision - * calculation that is available for current platform, considering - * whether floating point or 64-bit precision arithmetic is available. - * For maximum portability, application should prefer to use this function - * rather than calculating the elapsed time by itself. - * - * @param start The starting timestamp. - * @param stop The end timestamp. - * - * @return Elapsed time in cycles. - * - * @see pj_elapsed_usec(), pj_elapsed_time(), pj_elapsed_nanosec() - */ -PJ_DECL(pj_uint32_t) pj_elapsed_cycle( const pj_timestamp *start, - const pj_timestamp *stop ); - - -#endif /* PJ_HAS_HIGH_RES_TIMER */ - -/** @} */ - - -/////////////////////////////////////////////////////////////////////////////// -/** - * Internal PJLIB function to initialize the threading subsystem. - * @return PJ_SUCCESS or the appropriate error code. - */ -pj_status_t pj_thread_init(void); - - -PJ_END_DECL - -#endif /* __PJ_OS_H__ */ - +
+/**
+ * @}
+ */
+
+///////////////////////////////////////////////////////////////////////////////
+/**
+ * @defgroup PJ_MUTEX Mutexes.
+ * @ingroup PJ_OS
+ * @{
+ *
+ * Mutex manipulation. Alternatively, application can use higher abstraction
+ * for lock objects, which provides uniform API for all kinds of lock
+ * mechanisms, including mutex. See @ref PJ_LOCK for more information.
+ */
+
+/**
+ * Mutex types:
+ * - PJ_MUTEX_DEFAULT: default mutex type, which is system dependent.
+ * - PJ_MUTEX_SIMPLE: non-recursive mutex.
+ * - PJ_MUTEX_RECURSIVE: recursive mutex.
+ */
+typedef enum pj_mutex_type_e
+{
+ PJ_MUTEX_DEFAULT,
+ PJ_MUTEX_SIMPLE,
+ PJ_MUTEX_RECURSE,
+} pj_mutex_type_e;
+
+
+/**
+ * Create mutex of the specified type.
+ *
+ * @param pool The pool.
+ * @param name Name to be associated with the mutex (for debugging).
+ * @param type The type of the mutex, of type #pj_mutex_type_e.
+ * @param mutex Pointer to hold the returned mutex instance.
+ *
+ * @return PJ_SUCCESS on success, or the error code.
+ */
+PJ_DECL(pj_status_t) pj_mutex_create(pj_pool_t *pool,
+ const char *name,
+ int type,
+ pj_mutex_t **mutex);
+
+/**
+ * Create simple, non-recursive mutex.
+ * This function is a simple wrapper for #pj_mutex_create to create
+ * non-recursive mutex.
+ *
+ * @param pool The pool.
+ * @param name Mutex name.
+ * @param mutex Pointer to hold the returned mutex instance.
+ *
+ * @return PJ_SUCCESS on success, or the error code.
+ */
+PJ_DECL(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool, const char *name,
+ pj_mutex_t **mutex );
+
+/**
+ * Create recursive mutex.
+ * This function is a simple wrapper for #pj_mutex_create to create
+ * recursive mutex.
+ *
+ * @param pool The pool.
+ * @param name Mutex name.
+ * @param mutex Pointer to hold the returned mutex instance.
+ *
+ * @return PJ_SUCCESS on success, or the error code.
+ */
+PJ_DECL(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool,
+ const char *name,
+ pj_mutex_t **mutex );
+
+/**
+ * Acquire mutex lock.
+ *
+ * @param mutex The mutex.
+ * @return PJ_SUCCESS on success, or the error code.
+ */
+PJ_DECL(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex);
+
+/**
+ * Release mutex lock.
+ *
+ * @param mutex The mutex.
+ * @return PJ_SUCCESS on success, or the error code.
+ */
+PJ_DECL(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex);
+
+/**
+ * Try to acquire mutex lock.
+ *
+ * @param mutex The mutex.
+ * @return PJ_SUCCESS on success, or the error code if the
+ * lock couldn't be acquired.
+ */
+PJ_DECL(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex);
+
+/**
+ * Destroy mutex.
+ *
+ * @param mutex Te mutex.
+ * @return PJ_SUCCESS on success, or the error code.
+ */
+PJ_DECL(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex);
+
+/**
+ * Determine whether calling thread is owning the mutex (only available when
+ * PJ_DEBUG is set).
+ * @param mutex The mutex.
+ * @return Non-zero if yes.
+ */
+#if defined(PJ_DEBUG) && PJ_DEBUG != 0
+ PJ_DECL(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex);
+#else
+# define pj_mutex_is_locked(mutex) 1
+#endif
+
+/**
+ * @}
+ */
+
+///////////////////////////////////////////////////////////////////////////////
+/**
+ * @defgroup PJ_CRIT_SEC Critical sections.
+ * @ingroup PJ_OS
+ * @{
+ * Critical section protection can be used to protect regions where:
+ * - mutual exclusion protection is needed.
+ * - it's rather too expensive to create a mutex.
+ * - the time spent in the region is very very brief.
+ *
+ * Critical section is a global object, and it prevents any threads from
+ * entering any regions that are protected by critical section once a thread
+ * is already in the section.
+ *
+ * Critial section is \a not recursive!
+ *
+ * Application <b>MUST NOT</b> call any functions that may cause current
+ * thread to block (such as allocating memory, performing I/O, locking mutex,
+ * etc.) while holding the critical section.
+ */
+/**
+ * Enter critical section.
+ */
+PJ_DECL(void) pj_enter_critical_section(void);
+
+/**
+ * Leave critical section.
+ */
+PJ_DECL(void) pj_leave_critical_section(void);
+
+/**
+ * @}
+ */
+
+///////////////////////////////////////////////////////////////////////////////
+#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
+/**
+ * @defgroup PJ_SEM Semaphores.
+ * @ingroup PJ_OS
+ * @{
+ *
+ * This module provides abstraction for semaphores, where available.
+ */
+
+/**
+ * Create semaphore.
+ *
+ * @param pool The pool.
+ * @param name Name to be assigned to the semaphore (for logging purpose)
+ * @param initial The initial count of the semaphore.
+ * @param max The maximum count of the semaphore.
+ * @param sem Pointer to hold the semaphore created.
+ *
+ * @return PJ_SUCCESS on success, or the error code.
+ */
+PJ_DECL(pj_status_t) pj_sem_create( pj_pool_t *pool,
+ const char *name,
+ unsigned initial,
+ unsigned max,
+ pj_sem_t **sem);
+
+/**
+ * Wait for semaphore.
+ *
+ * @param sem The semaphore.
+ *
+ * @return PJ_SUCCESS on success, or the error code.
+ */
+PJ_DECL(pj_status_t) pj_sem_wait(pj_sem_t *sem);
+
+/**
+ * Try wait for semaphore.
+ *
+ * @param sem The semaphore.
+ *
+ * @return PJ_SUCCESS on success, or the error code.
+ */
+PJ_DECL(pj_status_t) pj_sem_trywait(pj_sem_t *sem);
+
+/**
+ * Release semaphore.
+ *
+ * @param sem The semaphore.
+ *
+ * @return PJ_SUCCESS on success, or the error code.
+ */
+PJ_DECL(pj_status_t) pj_sem_post(pj_sem_t *sem);
+
+/**
+ * Destroy semaphore.
+ *
+ * @param sem The semaphore.
+ *
+ * @return PJ_SUCCESS on success, or the error code.
+ */
+PJ_DECL(pj_status_t) pj_sem_destroy(pj_sem_t *sem);
+
+/**
+ * @}
+ */
+#endif /* PJ_HAS_SEMAPHORE */
+
+
+///////////////////////////////////////////////////////////////////////////////
+#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0
+/**
+ * @defgroup PJ_EVENT Event Object.
+ * @ingroup PJ_OS
+ * @{
+ *
+ * This module provides abstraction to event object (e.g. Win32 Event) where
+ * available. Event objects can be used for synchronization among threads.
+ */
+
+/**
+ * Create event object.
+ *
+ * @param pool The pool.
+ * @param name The name of the event object (for logging purpose).
+ * @param manual_reset Specify whether the event is manual-reset
+ * @param initial Specify the initial state of the event object.
+ * @param event Pointer to hold the returned event object.
+ *
+ * @return event handle, or NULL if failed.
+ */
+PJ_DECL(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);
+
+/**
+ * Wait for event to be signaled.
+ *
+ * @param event The event object.
+ *
+ * @return zero if successfull.
+ */
+PJ_DECL(pj_status_t) pj_event_wait(pj_event_t *event);
+
+/**
+ * Try wait for event object to be signalled.
+ *
+ * @param event The event object.
+ *
+ * @return zero if successfull.
+ */
+PJ_DECL(pj_status_t) pj_event_trywait(pj_event_t *event);
+
+/**
+ * Set the event object state to signaled. For auto-reset event, this
+ * will only release the first thread that are waiting on the event. For
+ * manual reset event, the state remains signaled until the event is reset.
+ * If there is no thread waiting on the event, the event object state
+ * remains signaled.
+ *
+ * @param event The event object.
+ *
+ * @return zero if successfull.
+ */
+PJ_DECL(pj_status_t) pj_event_set(pj_event_t *event);
+
+/**
+ * Set the event object to signaled state to release appropriate number of
+ * waiting threads and then reset the event object to non-signaled. For
+ * manual-reset event, this function will release all waiting threads. For
+ * auto-reset event, this function will only release one waiting thread.
+ *
+ * @param event The event object.
+ *
+ * @return zero if successfull.
+ */
+PJ_DECL(pj_status_t) pj_event_pulse(pj_event_t *event);
+
+/**
+ * Set the event object state to non-signaled.
+ *
+ * @param event The event object.
+ *
+ * @return zero if successfull.
+ */
+PJ_DECL(pj_status_t) pj_event_reset(pj_event_t *event);
+
+/**
+ * Destroy the event object.
+ *
+ * @param event The event object.
+ *
+ * @return zero if successfull.
+ */
+PJ_DECL(pj_status_t) pj_event_destroy(pj_event_t *event);
+
+/**
+ * @}
+ */
+#endif /* PJ_HAS_EVENT_OBJ */
+
+///////////////////////////////////////////////////////////////////////////////
+/**
+ * @addtogroup PJ_TIME Time Data Type and Manipulation.
+ * @ingroup PJ_OS
+ * @{
+ * This module provides API for manipulating time.
+ *
+ * \section pj_time_examples_sec Examples
+ *
+ * For examples, please see:
+ * - \ref page_pjlib_sleep_test
+ */
+
+/**
+ * Get current time of day in local representation.
+ *
+ * @param tv Variable to store the result.
+ *
+ * @return zero if successfull.
+ */
+PJ_DECL(pj_status_t) pj_gettimeofday(pj_time_val *tv);
+
+
+/**
+ * Parse time value into date/time representation.
+ *
+ * @param tv The time.
+ * @param pt Variable to store the date time result.
+ *
+ * @return zero if successfull.
+ */
+PJ_DECL(pj_status_t) pj_time_decode(const pj_time_val *tv, pj_parsed_time *pt);
+
+/**
+ * Encode date/time to time value.
+ *
+ * @param pt The date/time.
+ * @param tv Variable to store time value result.
+ *
+ * @return zero if successfull.
+ */
+PJ_DECL(pj_status_t) pj_time_encode(const pj_parsed_time *pt, pj_time_val *tv);
+
+/**
+ * Convert local time to GMT.
+ *
+ * @param tv Time to convert.
+ *
+ * @return zero if successfull.
+ */
+PJ_DECL(pj_status_t) pj_time_local_to_gmt(pj_time_val *tv);
+
+/**
+ * Convert GMT to local time.
+ *
+ * @param tv Time to convert.
+ *
+ * @return zero if successfull.
+ */
+PJ_DECL(pj_status_t) pj_time_gmt_to_local(pj_time_val *tv);
+
+/**
+ * @}
+ */
+
+///////////////////////////////////////////////////////////////////////////////
+#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0
+
+/**
+ * @defgroup PJ_TERM Terminal
+ * @ingroup PJ_OS
+ * @{
+ */
+
+/**
+ * Set current terminal color.
+ *
+ * @param color The RGB color.
+ *
+ * @return zero on success.
+ */
+PJ_DECL(pj_status_t) pj_term_set_color(pj_color_t color);
+
+/**
+ * Get current terminal foreground color.
+ *
+ * @return RGB color.
+ */
+PJ_DECL(pj_color_t) pj_term_get_color(void);
+
+/**
+ * @}
+ */
+
+#endif /* PJ_TERM_HAS_COLOR */
+
+///////////////////////////////////////////////////////////////////////////////
+/**
+ * @defgroup PJ_TIMESTAMP High Resolution Timestamp
+ * @ingroup PJ_OS
+ * @{
+ *
+ * PJLIB provides <b>High Resolution Timestamp</b> API to access highest
+ * resolution timestamp value provided by the platform. The API is usefull
+ * to measure precise elapsed time, and can be used in applications such
+ * as profiling.
+ *
+ * The timestamp value is represented in cycles, and can be related to
+ * normal time (in seconds or sub-seconds) using various functions provided.
+ *
+ * \section pj_timestamp_examples_sec Examples
+ *
+ * For examples, please see:
+ * - \ref page_pjlib_sleep_test
+ * - \ref page_pjlib_timestamp_test
+ */
+
+/*
+ * High resolution timer.
+ */
+#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0
+
+/**
+ * This structure represents high resolution (64bit) time value. The time
+ * values represent time in cycles, which is retrieved by calling
+ * #pj_get_timestamp().
+ */
+typedef union pj_timestamp
+{
+ struct
+ {
+#if defined(PJ_IS_LITTLE_ENDIAN) && PJ_IS_LITTLE_ENDIAN!=0
+ pj_uint32_t lo; /**< Low 32-bit value of the 64-bit value. */
+ pj_uint32_t hi; /**< high 32-bit value of the 64-bit value. */
+#else
+ pj_uint32_t hi; /**< high 32-bit value of the 64-bit value. */
+ pj_uint32_t lo; /**< Low 32-bit value of the 64-bit value. */
+#endif
+ } u32; /**< The 64-bit value as two 32-bit values. */
+
+#if PJ_HAS_INT64
+ pj_uint64_t u64; /**< The whole 64-bit value, where available. */
+#endif
+} pj_timestamp;
+
+
+/**
+ * Acquire high resolution timer value. The time value are stored
+ * in cycles.
+ *
+ * @param ts High resolution timer value.
+ * @return PJ_SUCCESS or the appropriate error code.
+ *
+ * @see pj_get_timestamp_freq().
+ */
+PJ_DECL(pj_status_t) pj_get_timestamp(pj_timestamp *ts);
+
+/**
+ * Get high resolution timer frequency, in cycles per second.
+ *
+ * @param freq Timer frequency, in cycles per second.
+ * @return PJ_SUCCESS or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq);
+
+/**
+ * Calculate the elapsed time, and store it in pj_time_val.
+ * This function calculates the elapsed time using highest precision
+ * calculation that is available for current platform, considering
+ * whether floating point or 64-bit precision arithmetic is available.
+ * For maximum portability, application should prefer to use this function
+ * rather than calculating the elapsed time by itself.
+ *
+ * @param start The starting timestamp.
+ * @param stop The end timestamp.
+ *
+ * @return Elapsed time as #pj_time_val.
+ *
+ * @see pj_elapsed_usec(), pj_elapsed_cycle(), pj_elapsed_nanosec()
+ */
+PJ_DECL(pj_time_val) pj_elapsed_time( const pj_timestamp *start,
+ const pj_timestamp *stop );
+
+/**
+ * Calculate the elapsed time in 32-bit microseconds.
+ * This function calculates the elapsed time using highest precision
+ * calculation that is available for current platform, considering
+ * whether floating point or 64-bit precision arithmetic is available.
+ * For maximum portability, application should prefer to use this function
+ * rather than calculating the elapsed time by itself.
+ *
+ * @param start The starting timestamp.
+ * @param stop The end timestamp.
+ *
+ * @return Elapsed time in microsecond.
+ *
+ * @see pj_elapsed_time(), pj_elapsed_cycle(), pj_elapsed_nanosec()
+ */
+PJ_DECL(pj_uint32_t) pj_elapsed_usec( const pj_timestamp *start,
+ const pj_timestamp *stop );
+
+/**
+ * Calculate the elapsed time in 32-bit nanoseconds.
+ * This function calculates the elapsed time using highest precision
+ * calculation that is available for current platform, considering
+ * whether floating point or 64-bit precision arithmetic is available.
+ * For maximum portability, application should prefer to use this function
+ * rather than calculating the elapsed time by itself.
+ *
+ * @param start The starting timestamp.
+ * @param stop The end timestamp.
+ *
+ * @return Elapsed time in nanoseconds.
+ *
+ * @see pj_elapsed_time(), pj_elapsed_cycle(), pj_elapsed_usec()
+ */
+PJ_DECL(pj_uint32_t) pj_elapsed_nanosec( const pj_timestamp *start,
+ const pj_timestamp *stop );
+
+/**
+ * Calculate the elapsed time in 32-bit cycles.
+ * This function calculates the elapsed time using highest precision
+ * calculation that is available for current platform, considering
+ * whether floating point or 64-bit precision arithmetic is available.
+ * For maximum portability, application should prefer to use this function
+ * rather than calculating the elapsed time by itself.
+ *
+ * @param start The starting timestamp.
+ * @param stop The end timestamp.
+ *
+ * @return Elapsed time in cycles.
+ *
+ * @see pj_elapsed_usec(), pj_elapsed_time(), pj_elapsed_nanosec()
+ */
+PJ_DECL(pj_uint32_t) pj_elapsed_cycle( const pj_timestamp *start,
+ const pj_timestamp *stop );
+
+
+#endif /* PJ_HAS_HIGH_RES_TIMER */
+
+/** @} */
+
+
+///////////////////////////////////////////////////////////////////////////////
+/**
+ * Internal PJLIB function to initialize the threading subsystem.
+ * @return PJ_SUCCESS or the appropriate error code.
+ */
+pj_status_t pj_thread_init(void);
+
+
+PJ_END_DECL
+
+#endif /* __PJ_OS_H__ */
+
diff --git a/pjlib/include/pj/pool.h b/pjlib/include/pj/pool.h index 4be4d242..a8ad7e83 100644 --- a/pjlib/include/pj/pool.h +++ b/pjlib/include/pj/pool.h @@ -1,572 +1,593 @@ -/* $Id$ - * - */ - -#ifndef __PJ_POOL_H__ -#define __PJ_POOL_H__ - -/** - * @file pool.h - * @brief Memory Pool. - */ - -#include <pj/list.h> - -PJ_BEGIN_DECL - -/** - * @defgroup PJ_POOL_GROUP Memory Pool Management - * @ingroup PJ - * @brief - * Memory pool management provides API to allocate and deallocate memory from - * memory pool and to manage and establish policy for pool creation and - * destruction in pool factory. - * - * \section PJ_POOL_FACTORY_SEC Pool Factory - * See: \ref PJ_POOL_FACTORY "Pool Factory" - * - * A memory pool must be created through a factory. A factory not only provides - * generic interface functions to create and release pool, but also provides - * strategy to manage the life time of pools. One sample implementation, - * \a pj_caching_pool, can be set to keep the pools released by application for - * future use as long as the total memory is below the limit. - * - * The pool factory interface declared in PJLIB is designed to be extensible. - * Application can define its own strategy by creating it's own pool factory - * implementation, and this strategy can be used even by existing library - * without recompilation. - * - * - * \section PJ_POOL_POLICY_SEC Pool Factory Policy - * See: \ref PJ_POOL_FACTORY "Pool Factory Policy" - * - * A pool factory only defines functions to create and release pool and how - * to manage pools, but the rest of the functionalities are controlled by - * policy. A pool policy defines: - * - how memory block is allocated and deallocated (the default implementation - * allocates and deallocate memory by calling malloc() and free()). - * - callback to be called when memory allocation inside a pool fails (the - * default implementation will throw PJ_NO_MEMORY_EXCEPTION exception). - * - concurrency when creating and releasing pool from/to the factory. - * - * A pool factory can be given different policy during creation to make - * it behave differently. For example, caching pool factory can be configured - * to allocate and deallocate from a static/contiguous/preallocated memory - * instead of using malloc()/free(). - * - * What strategy/factory and what policy to use is not defined by PJLIB, but - * instead is left to application to make use whichever is most efficient for - * itself. - * - * - * \section PJ_POOL_POOL_SEC The Pool - * See: \ref PJ_POOL "Pool" - * - * The memory pool is an opaque object created by pool factory. - * Application uses this object to request a memory chunk, by calling - * #pj_pool_alloc or #pj_pool_calloc. When the application has finished using - * the pool, it must call #pj_pool_release to free all the chunks previously - * allocated and release the pool back to the factory. - * - * \section PJ_POOL_THREADING_SEC More on Threading Policies: - * - By design, memory allocation from a pool is not thread safe. We assumed - * that a pool will be owned by an object, and thread safety should be - * handled by that object. Thus these functions are not thread safe: - * - #pj_pool_alloc, - * - #pj_pool_calloc, - * - and other pool statistic functions. - * - Threading in the pool factory is decided by the policy set for the - * factory when it was created. - * - * \section PJ_POOL_EXAMPLES_SEC Examples - * - * For some sample codes on how to use the pool, please see: - * - @ref page_pjlib_pool_test - */ - -/** - * @defgroup PJ_POOL Memory Pool. - * @ingroup PJ_POOL_GROUP - * @brief - * A memory pool is initialized with an initial amount of memory, which is - * called a block. Pool can be configured to dynamically allocate more memory - * blocks when it runs out of memory. Subsequent memory allocations by user - * will use up portions of these block. - * The pool doesn't keep track of individual memory allocations - * by user, and the user doesn't have to free these indidual allocations. This - * makes memory allocation simple and very fast. All the memory allocated from - * the pool will be destroyed when the pool itself is destroyed. - * @{ - */ - -/** - * The type for function to receive callback from the pool when it is unable - * to allocate memory. The elegant way to handle this condition is to throw - * exception, and this is what is expected by most of this library - * components. - */ -typedef void pj_pool_callback(pj_pool_t *pool, pj_size_t size); - -/** - * This class, which is used internally by the pool, describes a single - * block of memory from which user memory allocations will be allocated from. - */ -typedef struct pj_pool_block -{ - PJ_DECL_LIST_MEMBER(struct pj_pool_block); /**< List's prev and next. */ - unsigned char *buf; /**< Start of buffer. */ - unsigned char *cur; /**< Current alloc ptr. */ - unsigned char *end; /**< End of buffer. */ -} pj_pool_block; - - -/** - * This structure describes the memory pool. Only implementors of pool factory - * need to care about the contents of this structure. - */ -struct pj_pool_t -{ - PJ_DECL_LIST_MEMBER(struct pj_pool_t); /**< Standard list elements. */ - - /** Pool name */ - char obj_name[PJ_MAX_OBJ_NAME]; - - /** Pool factory. */ - pj_pool_factory *factory; - - /** Current capacity allocated by the pool. */ - pj_size_t capacity; - - /** Number of memory used/allocated. */ - pj_size_t used_size; - - /** Size of memory block to be allocated when the pool runs out of memory */ - pj_size_t increment_size; - - /** List of memory blocks allcoated by the pool. */ - pj_pool_block block_list; - - /** The callback to be called when the pool is unable to allocate memory. */ - pj_pool_callback *callback; - -}; - - -/** - * Guidance on how much memory required for initial pool administrative data. - */ -#define PJ_POOL_SIZE (sizeof(struct pj_pool_t)) - -/** - * Pool memory alignment (must be power of 2). - */ -#ifndef PJ_POOL_ALIGNMENT -# define PJ_POOL_ALIGNMENT 4 -#endif - -/** - * Create a new pool from the pool factory. This wrapper will call create_pool - * member of the pool factory. - * - * @param factory The pool factory. - * @param name The name to be assigned to the pool. The name should - * not be longer than PJ_MAX_OBJ_NAME (32 chars), or - * otherwise it will be truncated. - * @param initial_size The size of initial memory blocks taken by the pool. - * Note that the pool will take 68+20 bytes for - * administrative area from this block. - * @param increment_size the size of each additional blocks to be allocated - * when the pool is running out of memory. If user - * requests memory which is larger than this size, then - * an error occurs. - * Note that each time a pool allocates additional block, - * it needs PJ_POOL_SIZE more to store some - * administrative info. - * @param callback Callback to be called when error occurs in the pool. - * If this value is NULL, then the callback from pool - * factory policy will be used. - * Note that when an error occurs during pool creation, - * the callback itself is not called. Instead, NULL - * will be returned. - * - * @return The memory pool, or NULL. - */ -PJ_IDECL(pj_pool_t*) pj_pool_create(pj_pool_factory *factory, - const char *name, - pj_size_t initial_size, - pj_size_t increment_size, - pj_pool_callback *callback); - -/** - * Release the pool back to pool factory. - * - * @param pool Memory pool. - */ -PJ_IDECL(void) pj_pool_release( pj_pool_t *pool ); - -/** - * Get pool object name. - * - * @param pool the pool. - * - * @return pool name as NULL terminated string. - */ -PJ_IDECL(const char *) pj_pool_getobjname( const pj_pool_t *pool ); - -/** - * Reset the pool to its state when it was initialized. - * This means that if additional blocks have been allocated during runtime, - * then they will be freed. Only the original block allocated during - * initialization is retained. This function will also reset the internal - * counters, such as pool capacity and used size. - * - * @param pool the pool. - */ -PJ_DECL(void) pj_pool_reset( pj_pool_t *pool ); - - -/** - * Get the pool capacity, that is, the system storage that have been allocated - * by the pool, and have been used/will be used to allocate user requests. - * There's no guarantee that the returned value represent a single - * contiguous block, because the capacity may be spread in several blocks. - * - * @param pool the pool. - * - * @return the capacity. - */ -PJ_IDECL(pj_size_t) pj_pool_get_capacity( pj_pool_t *pool ); - -/** - * Get the total size of user allocation request. - * - * @param pool the pool. - * - * @return the total size. - */ -PJ_IDECL(pj_size_t) pj_pool_get_used_size( pj_pool_t *pool ); - -/** - * Allocate storage with the specified size from the pool. - * If there's no storage available in the pool, then the pool can allocate more - * blocks if the increment size is larger than the requested size. - * - * @param pool the pool. - * @param size the requested size. - * - * @return pointer to the allocated memory. - */ -PJ_IDECL(void*) pj_pool_alloc( pj_pool_t *pool, pj_size_t size); - -/** - * Allocate storage from the pool, and initialize it to zero. - * This function behaves like pj_pool_alloc(), except that the storage will - * be initialized to zero. - * - * @param pool the pool. - * @param count the number of elements in the array. - * @param elem the size of individual element. - * - * @return pointer to the allocated memory. - */ -PJ_IDECL(void*) pj_pool_calloc( pj_pool_t *pool, pj_size_t count, - pj_size_t elem); - - -/** - * @def pj_pool_zalloc(pj_pool_t *pool, pj_size_t size) - * Allocate storage from the pool and initialize it to zero. - * - * @param pool The pool. - * @param size The size to be allocated. - * - * @return Pointer to the allocated memory. - */ -#define pj_pool_zalloc(pool, size) pj_pool_calloc(pool, 1, size) - - -/** - * @} // PJ_POOL - */ - -/////////////////////////////////////////////////////////////////////////////// -/** - * @defgroup PJ_POOL_FACTORY Pool Factory and Policy. - * @ingroup PJ_POOL_GROUP - * @brief - * Pool factory declares an interface to create and destroy pool. There may - * be several strategies for pool creation, and these strategies should - * implement the interface defined by pool factory. - * - * \section PJ_POOL_FACTORY_ITF Pool Factory Interface - * The pool factory defines the following interface: - * - \a policy: the memory pool factory policy. - * - \a create_pool(): create a new memory pool. - * - \a release_pool(): release memory pool back to factory. - * - * \section PJ_POOL_FACTORY_POL Pool Factory Policy. - * The pool factory policy controls the behaviour of memory factories, and - * defines the following interface: - * - \a block_alloc(): allocate memory block from backend memory mgmt/system. - * - \a block_free(): free memory block back to backend memory mgmt/system. - * @{ - */ - -/* We unfortunately don't have support for factory policy options as now, - so we keep this commented at the moment. -enum PJ_POOL_FACTORY_OPTION -{ - PJ_POOL_FACTORY_SERIALIZE = 1 -}; -*/ - -/** - * This structure declares pool factory interface. - */ -typedef struct pj_pool_factory_policy -{ - /** - * Allocate memory block (for use by pool). This function is called - * by memory pool to allocate memory block. - * - * @param factory Pool factory. - * @param size The size of memory block to allocate. - * - * @return Memory block. - */ - void* (*block_alloc)(pj_pool_factory *factory, pj_size_t size); - - /** - * Free memory block. - * - * @param factory Pool factory. - * @param mem Memory block previously allocated by block_alloc(). - * @param size The size of memory block. - */ - void (*block_free)(pj_pool_factory *factory, void *mem, pj_size_t size); - - /** - * Default callback to be called when memory allocation fails. - */ - pj_pool_callback *callback; - - /** - * Option flags. - */ - unsigned flags; - -} pj_pool_factory_policy; - -/** - * This constant denotes the exception number that will be thrown by default - * memory factory policy when memory allocation fails. - */ -extern int PJ_NO_MEMORY_EXCEPTION; - -/** - * This global variable points to default memory pool factory policy. - * The behaviour of the default policy is: - * - block allocation and deallocation use malloc() and free(). - * - callback will raise PJ_NO_MEMORY_EXCEPTION exception. - * - access to pool factory is not serialized (i.e. not thread safe). - */ -extern pj_pool_factory_policy pj_pool_factory_default_policy; - -/** - * This structure contains the declaration for pool factory interface. - */ -struct pj_pool_factory -{ - /** - * Memory pool policy. - */ - pj_pool_factory_policy policy; - - /** - * Create a new pool from the pool factory. - * - * @param factory The pool factory. - * @param name the name to be assigned to the pool. The name should - * not be longer than PJ_MAX_OBJ_NAME (32 chars), or - * otherwise it will be truncated. - * @param initial_size the size of initial memory blocks taken by the pool. - * Note that the pool will take 68+20 bytes for - * administrative area from this block. - * @param increment_size the size of each additional blocks to be allocated - * when the pool is running out of memory. If user - * requests memory which is larger than this size, then - * an error occurs. - * Note that each time a pool allocates additional block, - * it needs 20 bytes (equal to sizeof(pj_pool_block)) to - * store some administrative info. - * @param callback Cllback to be called when error occurs in the pool. - * Note that when an error occurs during pool creation, - * the callback itself is not called. Instead, NULL - * will be returned. - * - * @return the memory pool, or NULL. - */ - pj_pool_t* (*create_pool)( pj_pool_factory *factory, - const char *name, - pj_size_t initial_size, - pj_size_t increment_size, - pj_pool_callback *callback); - - /** - * Release the pool to the pool factory. - * - * @param factory The pool factory. - * @param pool The pool to be released. - */ - void (*release_pool)( pj_pool_factory *factory, pj_pool_t *pool ); - - /** - * Dump pool status to log. - * - * @param factory The pool factory. - */ - void (*dump_status)( pj_pool_factory *factory, pj_bool_t detail ); -}; - -/** - * This function is intended to be used by pool factory implementors. - * @param factory Pool factory. - * @param name Pool name. - * @param initial_size Initial size. - * @param increment_size Increment size. - * @param callback Callback. - * @return The pool object, or NULL. - */ -PJ_DECL(pj_pool_t*) pj_pool_create_int( pj_pool_factory *factory, - const char *name, - pj_size_t initial_size, - pj_size_t increment_size, - pj_pool_callback *callback); - -/** - * This function is intended to be used by pool factory implementors. - * @param pool The pool. - * @param name Pool name. - * @param increment_size Increment size. - * @param callback Callback function. - */ -PJ_DECL(void) pj_pool_init_int( pj_pool_t *pool, - const char *name, - pj_size_t increment_size, - pj_pool_callback *callback); - -/** - * This function is intended to be used by pool factory implementors. - * @param pool The memory pool. - */ -PJ_DECL(void) pj_pool_destroy_int( pj_pool_t *pool ); - - -/** - * @} // PJ_POOL_FACTORY - */ - -/////////////////////////////////////////////////////////////////////////////// - -/** - * @defgroup PJ_CACHING_POOL Caching Pool Factory. - * @ingroup PJ_POOL_GROUP - * @brief - * Caching pool is one sample implementation of pool factory where the - * factory can reuse memory to create a pool. Application defines what the - * maximum memory the factory can hold, and when a pool is released the - * factory decides whether to destroy the pool or to keep it for future use. - * If the total amount of memory in the internal cache is still within the - * limit, the factory will keep the pool in the internal cache, otherwise the - * pool will be destroyed, thus releasing the memory back to the system. - * - * @{ - */ - -/** - * Number of unique sizes, to be used as index to the free list. - * Each pool in the free list is organized by it's size. - */ -#define PJ_CACHING_POOL_ARRAY_SIZE 16 - -/** - * Declaration for caching pool. Application doesn't normally need to - * care about the contents of this struct, it is only provided here because - * application need to define an instance of this struct (we can not allocate - * the struct from a pool since there is no pool factory yet!). - */ -struct pj_caching_pool -{ - /** Pool factory interface, must be declared first. */ - pj_pool_factory factory; - - /** Current factory's capacity, i.e. number of bytes that are allocated - * and available for application in this factory. The factory's - * capacity represents the size of all pools kept by this factory - * in it's free list, which will be returned to application when it - * requests to create a new pool. - */ - pj_size_t capacity; - - /** Maximum size that can be held by this factory. Once the capacity - * has exceeded @a max_capacity, further #pj_pool_release() will - * flush the pool. If the capacity is still below the @a max_capacity, - * #pj_pool_release() will save the pool to the factory's free list. - */ - pj_size_t max_capacity; - - /** - * Number of pools currently held by applications. This number gets - * incremented everytime #pj_pool_create() is called, and gets - * decremented when #pj_pool_release() is called. - */ - pj_size_t used_count; - - /** - * Lists of pools in the cache, indexed by pool size. - */ - pj_list free_list[PJ_CACHING_POOL_ARRAY_SIZE]; - - /** - * List of pools currently allocated by applications. - */ - pj_list used_list; -}; - - - -/** - * Initialize caching pool. - * - * @param ch_pool The caching pool factory to be initialized. - * @param policy Pool factory policy. - * @param max_capacity The total capacity to be retained in the cache. When - * the pool is returned to the cache, it will be kept in - * recycling list if the total capacity of pools in this - * list plus the capacity of the pool is still below this - * value. - */ -PJ_DECL(void) pj_caching_pool_init( pj_caching_pool *ch_pool, - const pj_pool_factory_policy *policy, - pj_size_t max_capacity); - - -/** - * Destroy caching pool, and release all the pools in the recycling list. - * - * @param ch_pool The caching pool. - */ -PJ_DECL(void) pj_caching_pool_destroy( pj_caching_pool *ch_pool ); - -/** - * @} // PJ_CACHING_POOL - */ - -# if PJ_FUNCTIONS_ARE_INLINED -# include "pool_i.h" -# endif - -PJ_END_DECL - -#endif /* __PJ_POOL_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 __PJ_POOL_H__
+#define __PJ_POOL_H__
+
+/**
+ * @file pool.h
+ * @brief Memory Pool.
+ */
+
+#include <pj/list.h>
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup PJ_POOL_GROUP Memory Pool Management
+ * @ingroup PJ
+ * @brief
+ * Memory pool management provides API to allocate and deallocate memory from
+ * memory pool and to manage and establish policy for pool creation and
+ * destruction in pool factory.
+ *
+ * \section PJ_POOL_FACTORY_SEC Pool Factory
+ * See: \ref PJ_POOL_FACTORY "Pool Factory"
+ *
+ * A memory pool must be created through a factory. A factory not only provides
+ * generic interface functions to create and release pool, but also provides
+ * strategy to manage the life time of pools. One sample implementation,
+ * \a pj_caching_pool, can be set to keep the pools released by application for
+ * future use as long as the total memory is below the limit.
+ *
+ * The pool factory interface declared in PJLIB is designed to be extensible.
+ * Application can define its own strategy by creating it's own pool factory
+ * implementation, and this strategy can be used even by existing library
+ * without recompilation.
+ *
+ *
+ * \section PJ_POOL_POLICY_SEC Pool Factory Policy
+ * See: \ref PJ_POOL_FACTORY "Pool Factory Policy"
+ *
+ * A pool factory only defines functions to create and release pool and how
+ * to manage pools, but the rest of the functionalities are controlled by
+ * policy. A pool policy defines:
+ * - how memory block is allocated and deallocated (the default implementation
+ * allocates and deallocate memory by calling malloc() and free()).
+ * - callback to be called when memory allocation inside a pool fails (the
+ * default implementation will throw PJ_NO_MEMORY_EXCEPTION exception).
+ * - concurrency when creating and releasing pool from/to the factory.
+ *
+ * A pool factory can be given different policy during creation to make
+ * it behave differently. For example, caching pool factory can be configured
+ * to allocate and deallocate from a static/contiguous/preallocated memory
+ * instead of using malloc()/free().
+ *
+ * What strategy/factory and what policy to use is not defined by PJLIB, but
+ * instead is left to application to make use whichever is most efficient for
+ * itself.
+ *
+ *
+ * \section PJ_POOL_POOL_SEC The Pool
+ * See: \ref PJ_POOL "Pool"
+ *
+ * The memory pool is an opaque object created by pool factory.
+ * Application uses this object to request a memory chunk, by calling
+ * #pj_pool_alloc or #pj_pool_calloc. When the application has finished using
+ * the pool, it must call #pj_pool_release to free all the chunks previously
+ * allocated and release the pool back to the factory.
+ *
+ * \section PJ_POOL_THREADING_SEC More on Threading Policies:
+ * - By design, memory allocation from a pool is not thread safe. We assumed
+ * that a pool will be owned by an object, and thread safety should be
+ * handled by that object. Thus these functions are not thread safe:
+ * - #pj_pool_alloc,
+ * - #pj_pool_calloc,
+ * - and other pool statistic functions.
+ * - Threading in the pool factory is decided by the policy set for the
+ * factory when it was created.
+ *
+ * \section PJ_POOL_EXAMPLES_SEC Examples
+ *
+ * For some sample codes on how to use the pool, please see:
+ * - @ref page_pjlib_pool_test
+ */
+
+/**
+ * @defgroup PJ_POOL Memory Pool.
+ * @ingroup PJ_POOL_GROUP
+ * @brief
+ * A memory pool is initialized with an initial amount of memory, which is
+ * called a block. Pool can be configured to dynamically allocate more memory
+ * blocks when it runs out of memory. Subsequent memory allocations by user
+ * will use up portions of these block.
+ * The pool doesn't keep track of individual memory allocations
+ * by user, and the user doesn't have to free these indidual allocations. This
+ * makes memory allocation simple and very fast. All the memory allocated from
+ * the pool will be destroyed when the pool itself is destroyed.
+ * @{
+ */
+
+/**
+ * The type for function to receive callback from the pool when it is unable
+ * to allocate memory. The elegant way to handle this condition is to throw
+ * exception, and this is what is expected by most of this library
+ * components.
+ */
+typedef void pj_pool_callback(pj_pool_t *pool, pj_size_t size);
+
+/**
+ * This class, which is used internally by the pool, describes a single
+ * block of memory from which user memory allocations will be allocated from.
+ */
+typedef struct pj_pool_block
+{
+ PJ_DECL_LIST_MEMBER(struct pj_pool_block); /**< List's prev and next. */
+ unsigned char *buf; /**< Start of buffer. */
+ unsigned char *cur; /**< Current alloc ptr. */
+ unsigned char *end; /**< End of buffer. */
+} pj_pool_block;
+
+
+/**
+ * This structure describes the memory pool. Only implementors of pool factory
+ * need to care about the contents of this structure.
+ */
+struct pj_pool_t
+{
+ PJ_DECL_LIST_MEMBER(struct pj_pool_t); /**< Standard list elements. */
+
+ /** Pool name */
+ char obj_name[PJ_MAX_OBJ_NAME];
+
+ /** Pool factory. */
+ pj_pool_factory *factory;
+
+ /** Current capacity allocated by the pool. */
+ pj_size_t capacity;
+
+ /** Number of memory used/allocated. */
+ pj_size_t used_size;
+
+ /** Size of memory block to be allocated when the pool runs out of memory */
+ pj_size_t increment_size;
+
+ /** List of memory blocks allcoated by the pool. */
+ pj_pool_block block_list;
+
+ /** The callback to be called when the pool is unable to allocate memory. */
+ pj_pool_callback *callback;
+
+};
+
+
+/**
+ * Guidance on how much memory required for initial pool administrative data.
+ */
+#define PJ_POOL_SIZE (sizeof(struct pj_pool_t))
+
+/**
+ * Pool memory alignment (must be power of 2).
+ */
+#ifndef PJ_POOL_ALIGNMENT
+# define PJ_POOL_ALIGNMENT 4
+#endif
+
+/**
+ * Create a new pool from the pool factory. This wrapper will call create_pool
+ * member of the pool factory.
+ *
+ * @param factory The pool factory.
+ * @param name The name to be assigned to the pool. The name should
+ * not be longer than PJ_MAX_OBJ_NAME (32 chars), or
+ * otherwise it will be truncated.
+ * @param initial_size The size of initial memory blocks taken by the pool.
+ * Note that the pool will take 68+20 bytes for
+ * administrative area from this block.
+ * @param increment_size the size of each additional blocks to be allocated
+ * when the pool is running out of memory. If user
+ * requests memory which is larger than this size, then
+ * an error occurs.
+ * Note that each time a pool allocates additional block,
+ * it needs PJ_POOL_SIZE more to store some
+ * administrative info.
+ * @param callback Callback to be called when error occurs in the pool.
+ * If this value is NULL, then the callback from pool
+ * factory policy will be used.
+ * Note that when an error occurs during pool creation,
+ * the callback itself is not called. Instead, NULL
+ * will be returned.
+ *
+ * @return The memory pool, or NULL.
+ */
+PJ_IDECL(pj_pool_t*) pj_pool_create(pj_pool_factory *factory,
+ const char *name,
+ pj_size_t initial_size,
+ pj_size_t increment_size,
+ pj_pool_callback *callback);
+
+/**
+ * Release the pool back to pool factory.
+ *
+ * @param pool Memory pool.
+ */
+PJ_IDECL(void) pj_pool_release( pj_pool_t *pool );
+
+/**
+ * Get pool object name.
+ *
+ * @param pool the pool.
+ *
+ * @return pool name as NULL terminated string.
+ */
+PJ_IDECL(const char *) pj_pool_getobjname( const pj_pool_t *pool );
+
+/**
+ * Reset the pool to its state when it was initialized.
+ * This means that if additional blocks have been allocated during runtime,
+ * then they will be freed. Only the original block allocated during
+ * initialization is retained. This function will also reset the internal
+ * counters, such as pool capacity and used size.
+ *
+ * @param pool the pool.
+ */
+PJ_DECL(void) pj_pool_reset( pj_pool_t *pool );
+
+
+/**
+ * Get the pool capacity, that is, the system storage that have been allocated
+ * by the pool, and have been used/will be used to allocate user requests.
+ * There's no guarantee that the returned value represent a single
+ * contiguous block, because the capacity may be spread in several blocks.
+ *
+ * @param pool the pool.
+ *
+ * @return the capacity.
+ */
+PJ_IDECL(pj_size_t) pj_pool_get_capacity( pj_pool_t *pool );
+
+/**
+ * Get the total size of user allocation request.
+ *
+ * @param pool the pool.
+ *
+ * @return the total size.
+ */
+PJ_IDECL(pj_size_t) pj_pool_get_used_size( pj_pool_t *pool );
+
+/**
+ * Allocate storage with the specified size from the pool.
+ * If there's no storage available in the pool, then the pool can allocate more
+ * blocks if the increment size is larger than the requested size.
+ *
+ * @param pool the pool.
+ * @param size the requested size.
+ *
+ * @return pointer to the allocated memory.
+ */
+PJ_IDECL(void*) pj_pool_alloc( pj_pool_t *pool, pj_size_t size);
+
+/**
+ * Allocate storage from the pool, and initialize it to zero.
+ * This function behaves like pj_pool_alloc(), except that the storage will
+ * be initialized to zero.
+ *
+ * @param pool the pool.
+ * @param count the number of elements in the array.
+ * @param elem the size of individual element.
+ *
+ * @return pointer to the allocated memory.
+ */
+PJ_IDECL(void*) pj_pool_calloc( pj_pool_t *pool, pj_size_t count,
+ pj_size_t elem);
+
+
+/**
+ * @def pj_pool_zalloc(pj_pool_t *pool, pj_size_t size)
+ * Allocate storage from the pool and initialize it to zero.
+ *
+ * @param pool The pool.
+ * @param size The size to be allocated.
+ *
+ * @return Pointer to the allocated memory.
+ */
+#define pj_pool_zalloc(pool, size) pj_pool_calloc(pool, 1, size)
+
+
+/**
+ * @} // PJ_POOL
+ */
+
+///////////////////////////////////////////////////////////////////////////////
+/**
+ * @defgroup PJ_POOL_FACTORY Pool Factory and Policy.
+ * @ingroup PJ_POOL_GROUP
+ * @brief
+ * Pool factory declares an interface to create and destroy pool. There may
+ * be several strategies for pool creation, and these strategies should
+ * implement the interface defined by pool factory.
+ *
+ * \section PJ_POOL_FACTORY_ITF Pool Factory Interface
+ * The pool factory defines the following interface:
+ * - \a policy: the memory pool factory policy.
+ * - \a create_pool(): create a new memory pool.
+ * - \a release_pool(): release memory pool back to factory.
+ *
+ * \section PJ_POOL_FACTORY_POL Pool Factory Policy.
+ * The pool factory policy controls the behaviour of memory factories, and
+ * defines the following interface:
+ * - \a block_alloc(): allocate memory block from backend memory mgmt/system.
+ * - \a block_free(): free memory block back to backend memory mgmt/system.
+ * @{
+ */
+
+/* We unfortunately don't have support for factory policy options as now,
+ so we keep this commented at the moment.
+enum PJ_POOL_FACTORY_OPTION
+{
+ PJ_POOL_FACTORY_SERIALIZE = 1
+};
+*/
+
+/**
+ * This structure declares pool factory interface.
+ */
+typedef struct pj_pool_factory_policy
+{
+ /**
+ * Allocate memory block (for use by pool). This function is called
+ * by memory pool to allocate memory block.
+ *
+ * @param factory Pool factory.
+ * @param size The size of memory block to allocate.
+ *
+ * @return Memory block.
+ */
+ void* (*block_alloc)(pj_pool_factory *factory, pj_size_t size);
+
+ /**
+ * Free memory block.
+ *
+ * @param factory Pool factory.
+ * @param mem Memory block previously allocated by block_alloc().
+ * @param size The size of memory block.
+ */
+ void (*block_free)(pj_pool_factory *factory, void *mem, pj_size_t size);
+
+ /**
+ * Default callback to be called when memory allocation fails.
+ */
+ pj_pool_callback *callback;
+
+ /**
+ * Option flags.
+ */
+ unsigned flags;
+
+} pj_pool_factory_policy;
+
+/**
+ * This constant denotes the exception number that will be thrown by default
+ * memory factory policy when memory allocation fails.
+ */
+extern int PJ_NO_MEMORY_EXCEPTION;
+
+/**
+ * This global variable points to default memory pool factory policy.
+ * The behaviour of the default policy is:
+ * - block allocation and deallocation use malloc() and free().
+ * - callback will raise PJ_NO_MEMORY_EXCEPTION exception.
+ * - access to pool factory is not serialized (i.e. not thread safe).
+ */
+extern pj_pool_factory_policy pj_pool_factory_default_policy;
+
+/**
+ * This structure contains the declaration for pool factory interface.
+ */
+struct pj_pool_factory
+{
+ /**
+ * Memory pool policy.
+ */
+ pj_pool_factory_policy policy;
+
+ /**
+ * Create a new pool from the pool factory.
+ *
+ * @param factory The pool factory.
+ * @param name the name to be assigned to the pool. The name should
+ * not be longer than PJ_MAX_OBJ_NAME (32 chars), or
+ * otherwise it will be truncated.
+ * @param initial_size the size of initial memory blocks taken by the pool.
+ * Note that the pool will take 68+20 bytes for
+ * administrative area from this block.
+ * @param increment_size the size of each additional blocks to be allocated
+ * when the pool is running out of memory. If user
+ * requests memory which is larger than this size, then
+ * an error occurs.
+ * Note that each time a pool allocates additional block,
+ * it needs 20 bytes (equal to sizeof(pj_pool_block)) to
+ * store some administrative info.
+ * @param callback Cllback to be called when error occurs in the pool.
+ * Note that when an error occurs during pool creation,
+ * the callback itself is not called. Instead, NULL
+ * will be returned.
+ *
+ * @return the memory pool, or NULL.
+ */
+ pj_pool_t* (*create_pool)( pj_pool_factory *factory,
+ const char *name,
+ pj_size_t initial_size,
+ pj_size_t increment_size,
+ pj_pool_callback *callback);
+
+ /**
+ * Release the pool to the pool factory.
+ *
+ * @param factory The pool factory.
+ * @param pool The pool to be released.
+ */
+ void (*release_pool)( pj_pool_factory *factory, pj_pool_t *pool );
+
+ /**
+ * Dump pool status to log.
+ *
+ * @param factory The pool factory.
+ */
+ void (*dump_status)( pj_pool_factory *factory, pj_bool_t detail );
+};
+
+/**
+ * This function is intended to be used by pool factory implementors.
+ * @param factory Pool factory.
+ * @param name Pool name.
+ * @param initial_size Initial size.
+ * @param increment_size Increment size.
+ * @param callback Callback.
+ * @return The pool object, or NULL.
+ */
+PJ_DECL(pj_pool_t*) pj_pool_create_int( pj_pool_factory *factory,
+ const char *name,
+ pj_size_t initial_size,
+ pj_size_t increment_size,
+ pj_pool_callback *callback);
+
+/**
+ * This function is intended to be used by pool factory implementors.
+ * @param pool The pool.
+ * @param name Pool name.
+ * @param increment_size Increment size.
+ * @param callback Callback function.
+ */
+PJ_DECL(void) pj_pool_init_int( pj_pool_t *pool,
+ const char *name,
+ pj_size_t increment_size,
+ pj_pool_callback *callback);
+
+/**
+ * This function is intended to be used by pool factory implementors.
+ * @param pool The memory pool.
+ */
+PJ_DECL(void) pj_pool_destroy_int( pj_pool_t *pool );
+
+
+/**
+ * @} // PJ_POOL_FACTORY
+ */
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * @defgroup PJ_CACHING_POOL Caching Pool Factory.
+ * @ingroup PJ_POOL_GROUP
+ * @brief
+ * Caching pool is one sample implementation of pool factory where the
+ * factory can reuse memory to create a pool. Application defines what the
+ * maximum memory the factory can hold, and when a pool is released the
+ * factory decides whether to destroy the pool or to keep it for future use.
+ * If the total amount of memory in the internal cache is still within the
+ * limit, the factory will keep the pool in the internal cache, otherwise the
+ * pool will be destroyed, thus releasing the memory back to the system.
+ *
+ * @{
+ */
+
+/**
+ * Number of unique sizes, to be used as index to the free list.
+ * Each pool in the free list is organized by it's size.
+ */
+#define PJ_CACHING_POOL_ARRAY_SIZE 16
+
+/**
+ * Declaration for caching pool. Application doesn't normally need to
+ * care about the contents of this struct, it is only provided here because
+ * application need to define an instance of this struct (we can not allocate
+ * the struct from a pool since there is no pool factory yet!).
+ */
+struct pj_caching_pool
+{
+ /** Pool factory interface, must be declared first. */
+ pj_pool_factory factory;
+
+ /** Current factory's capacity, i.e. number of bytes that are allocated
+ * and available for application in this factory. The factory's
+ * capacity represents the size of all pools kept by this factory
+ * in it's free list, which will be returned to application when it
+ * requests to create a new pool.
+ */
+ pj_size_t capacity;
+
+ /** Maximum size that can be held by this factory. Once the capacity
+ * has exceeded @a max_capacity, further #pj_pool_release() will
+ * flush the pool. If the capacity is still below the @a max_capacity,
+ * #pj_pool_release() will save the pool to the factory's free list.
+ */
+ pj_size_t max_capacity;
+
+ /**
+ * Number of pools currently held by applications. This number gets
+ * incremented everytime #pj_pool_create() is called, and gets
+ * decremented when #pj_pool_release() is called.
+ */
+ pj_size_t used_count;
+
+ /**
+ * Lists of pools in the cache, indexed by pool size.
+ */
+ pj_list free_list[PJ_CACHING_POOL_ARRAY_SIZE];
+
+ /**
+ * List of pools currently allocated by applications.
+ */
+ pj_list used_list;
+};
+
+
+
+/**
+ * Initialize caching pool.
+ *
+ * @param ch_pool The caching pool factory to be initialized.
+ * @param policy Pool factory policy.
+ * @param max_capacity The total capacity to be retained in the cache. When
+ * the pool is returned to the cache, it will be kept in
+ * recycling list if the total capacity of pools in this
+ * list plus the capacity of the pool is still below this
+ * value.
+ */
+PJ_DECL(void) pj_caching_pool_init( pj_caching_pool *ch_pool,
+ const pj_pool_factory_policy *policy,
+ pj_size_t max_capacity);
+
+
+/**
+ * Destroy caching pool, and release all the pools in the recycling list.
+ *
+ * @param ch_pool The caching pool.
+ */
+PJ_DECL(void) pj_caching_pool_destroy( pj_caching_pool *ch_pool );
+
+/**
+ * @} // PJ_CACHING_POOL
+ */
+
+# if PJ_FUNCTIONS_ARE_INLINED
+# include "pool_i.h"
+# endif
+
+PJ_END_DECL
+
+#endif /* __PJ_POOL_H__ */
+
diff --git a/pjlib/include/pj/pool_i.h b/pjlib/include/pj/pool_i.h index 4a99908d..f23b52ae 100644 --- a/pjlib/include/pj/pool_i.h +++ b/pjlib/include/pj/pool_i.h @@ -1,76 +1,97 @@ -/* $Id$ - * - */ - - -#include <pj/string.h> - -PJ_DECL(void*) pj_pool_allocate_find(pj_pool_t *pool, unsigned size); - -PJ_IDEF(pj_size_t) pj_pool_get_capacity( pj_pool_t *pool ) -{ - return pool->capacity; -} - -PJ_IDEF(pj_size_t) pj_pool_get_used_size( pj_pool_t *pool ) -{ - return pool->used_size; -} - -PJ_IDEF(void*) pj_pool_alloc_from_block( pj_pool_t *pool, - pj_pool_block *block, pj_size_t size ) -{ - /* The operation below is valid for size==0. - * When size==0, the function will return the pointer to the pool - * memory address, but no memory will be allocated. - */ - if (size & (PJ_POOL_ALIGNMENT-1)) { - size &= ~(PJ_POOL_ALIGNMENT-1); - size += PJ_POOL_ALIGNMENT; - } - if ((unsigned)(block->end - block->cur) >= size) { - void *ptr = block->cur; - block->cur += size; - pool->used_size += size; - return ptr; - } - return NULL; -} - -PJ_IDEF(void*) pj_pool_alloc( pj_pool_t *pool, pj_size_t size) -{ - pj_pool_block *block = pool->block_list.next; - void *ptr = pj_pool_alloc_from_block(pool, block, size); - if (!ptr) - ptr = pj_pool_allocate_find(pool, size); - return ptr; -} - - -PJ_IDEF(void*) pj_pool_calloc( pj_pool_t *pool, pj_size_t count, pj_size_t size) -{ - void *buf = pj_pool_alloc( pool, size*count); - if (buf) - pj_memset(buf, 0, size * count); - return buf; -} - -PJ_IDEF(const char *) pj_pool_getobjname( const pj_pool_t *pool ) -{ - return pool->obj_name; -} - -PJ_IDEF(pj_pool_t*) pj_pool_create( pj_pool_factory *f, - const char *name, - pj_size_t initial_size, - pj_size_t increment_size, - pj_pool_callback *callback) -{ - return (*f->create_pool)(f, name, initial_size, increment_size, callback); -} - -PJ_IDEF(void) pj_pool_release( pj_pool_t *pool ) -{ - (*pool->factory->release_pool)(pool->factory, pool); -} - +/* $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>
+
+PJ_DECL(void*) pj_pool_allocate_find(pj_pool_t *pool, unsigned size);
+
+PJ_IDEF(pj_size_t) pj_pool_get_capacity( pj_pool_t *pool )
+{
+ return pool->capacity;
+}
+
+PJ_IDEF(pj_size_t) pj_pool_get_used_size( pj_pool_t *pool )
+{
+ return pool->used_size;
+}
+
+PJ_IDEF(void*) pj_pool_alloc_from_block( pj_pool_t *pool,
+ pj_pool_block *block, pj_size_t size )
+{
+ /* The operation below is valid for size==0.
+ * When size==0, the function will return the pointer to the pool
+ * memory address, but no memory will be allocated.
+ */
+ if (size & (PJ_POOL_ALIGNMENT-1)) {
+ size &= ~(PJ_POOL_ALIGNMENT-1);
+ size += PJ_POOL_ALIGNMENT;
+ }
+ if ((unsigned)(block->end - block->cur) >= size) {
+ void *ptr = block->cur;
+ block->cur += size;
+ pool->used_size += size;
+ return ptr;
+ }
+ return NULL;
+}
+
+PJ_IDEF(void*) pj_pool_alloc( pj_pool_t *pool, pj_size_t size)
+{
+ pj_pool_block *block = pool->block_list.next;
+ void *ptr = pj_pool_alloc_from_block(pool, block, size);
+ if (!ptr)
+ ptr = pj_pool_allocate_find(pool, size);
+ return ptr;
+}
+
+
+PJ_IDEF(void*) pj_pool_calloc( pj_pool_t *pool, pj_size_t count, pj_size_t size)
+{
+ void *buf = pj_pool_alloc( pool, size*count);
+ if (buf)
+ pj_memset(buf, 0, size * count);
+ return buf;
+}
+
+PJ_IDEF(const char *) pj_pool_getobjname( const pj_pool_t *pool )
+{
+ return pool->obj_name;
+}
+
+PJ_IDEF(pj_pool_t*) pj_pool_create( pj_pool_factory *f,
+ const char *name,
+ pj_size_t initial_size,
+ pj_size_t increment_size,
+ pj_pool_callback *callback)
+{
+ return (*f->create_pool)(f, name, initial_size, increment_size, callback);
+}
+
+PJ_IDEF(void) pj_pool_release( pj_pool_t *pool )
+{
+ (*pool->factory->release_pool)(pool->factory, pool);
+}
+
diff --git a/pjlib/include/pj/rand.h b/pjlib/include/pj/rand.h index 0549c72d..f431cd8c 100644 --- a/pjlib/include/pj/rand.h +++ b/pjlib/include/pj/rand.h @@ -1,62 +1,83 @@ -/* $Id$ - * - */ -/* $Log: /pjproject-0.3/pjlib/include/pj/rand.h $ - * - * 3 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 2 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - * 1 9/15/05 8:40p Bennylp - * Created. - */ -#ifndef __PJ_RAND_H__ -#define __PJ_RAND_H__ - -/** - * @file rand.h - * @brief Random Number Generator. - */ - -#include <pj/config.h> - -PJ_BEGIN_DECL - - -/** - * @defgroup PJ_RAND Random Number Generator - * @ingroup PJ_MISC - * @{ - * This module contains functions for generating random numbers. - * This abstraction is needed not only because not all platforms have - * \a rand() and \a srand(), but also on some platforms \a rand() - * only has 16-bit randomness, which is not good enough. - */ - -/** - * Put in seed to random number generator. - * - * @param seed Seed value. - */ -PJ_DECL(void) pj_srand(unsigned int seed); - - -/** - * Generate random integer with 32bit randomness. - * - * @return a random integer. - */ -PJ_DECL(int) pj_rand(void); - - -/** @} */ - - -PJ_END_DECL - - -#endif /* __PJ_RAND_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
+ */
+/* $Log: /pjproject-0.3/pjlib/include/pj/rand.h $
+ *
+ * 3 10/14/05 12:26a Bennylp
+ * Finished error code framework, some fixes in ioqueue, etc. Pretty
+ * major.
+ *
+ * 2 9/17/05 10:37a Bennylp
+ * Major reorganization towards version 0.3.
+ *
+ * 1 9/15/05 8:40p Bennylp
+ * Created.
+ */
+#ifndef __PJ_RAND_H__
+#define __PJ_RAND_H__
+
+/**
+ * @file rand.h
+ * @brief Random Number Generator.
+ */
+
+#include <pj/config.h>
+
+PJ_BEGIN_DECL
+
+
+/**
+ * @defgroup PJ_RAND Random Number Generator
+ * @ingroup PJ_MISC
+ * @{
+ * This module contains functions for generating random numbers.
+ * This abstraction is needed not only because not all platforms have
+ * \a rand() and \a srand(), but also on some platforms \a rand()
+ * only has 16-bit randomness, which is not good enough.
+ */
+
+/**
+ * Put in seed to random number generator.
+ *
+ * @param seed Seed value.
+ */
+PJ_DECL(void) pj_srand(unsigned int seed);
+
+
+/**
+ * Generate random integer with 32bit randomness.
+ *
+ * @return a random integer.
+ */
+PJ_DECL(int) pj_rand(void);
+
+
+/** @} */
+
+
+PJ_END_DECL
+
+
+#endif /* __PJ_RAND_H__ */
+
diff --git a/pjlib/include/pj/rbtree.h b/pjlib/include/pj/rbtree.h index 67efe2e0..06523a42 100644 --- a/pjlib/include/pj/rbtree.h +++ b/pjlib/include/pj/rbtree.h @@ -1,195 +1,216 @@ -/* $Id$ - * - */ - -#ifndef __PJ_RBTREE_H__ -#define __PJ_RBTREE_H__ - -/** - * @file rbtree.h - * @brief Red/Black Tree - */ - -#include <pj/types.h> - -PJ_BEGIN_DECL - -/** - * @defgroup PJ_RBTREE Red/Black Balanced Tree - * @ingroup PJ_DS - * @brief - * Red/Black tree is the variant of balanced tree, where the search, insert, - * and delete operation is \b guaranteed to take at most \a O( lg(n) ). - * @{ - */ -/** - * Color type for Red-Black tree. - */ -typedef enum pj_rbcolor_t -{ - PJ_RBCOLOR_BLACK, - PJ_RBCOLOR_RED -} pj_rbcolor_t; - -/** - * The type of the node of the R/B Tree. - */ -typedef struct pj_rbtree_node -{ - /** Pointers to the node's parent, and left and right siblings. */ - struct pj_rbtree_node *parent, *left, *right; - - /** Key associated with the node. */ - const void *key; - - /** User data associated with the node. */ - void *user_data; - - /** The R/B Tree node color. */ - pj_rbcolor_t color; - -} pj_rbtree_node; - - -/** - * The type of function use to compare key value of tree node. - * @return - * 0 if the keys are equal - * <0 if key1 is lower than key2 - * >0 if key1 is greater than key2. - */ -typedef int pj_rbtree_comp(const void *key1, const void *key2); - - -/** - * Declaration of a red-black tree. All elements in the tree must have UNIQUE - * key. - * A red black tree always maintains the balance of the tree, so that the - * tree height will not be greater than lg(N). Insert, search, and delete - * operation will take lg(N) on the worst case. But for insert and delete, - * there is additional time needed to maintain the balance of the tree. - */ -typedef struct pj_rbtree -{ - pj_rbtree_node null_node; /**< Constant to indicate NULL node. */ - pj_rbtree_node *null; /**< Constant to indicate NULL node. */ - pj_rbtree_node *root; /**< Root tree node. */ - unsigned size; /**< Number of elements in the tree. */ - pj_rbtree_comp *comp; /**< Key comparison function. */ -} pj_rbtree; - - -/** - * Guidance on how much memory required for each of the node. - */ -#define PJ_RBTREE_NODE_SIZE (sizeof(pj_rbtree_node)) - - -/** - * Guidance on memory required for the tree. - */ -#define PJ_RBTREE_SIZE (sizeof(pj_rbtree)) - - -/** - * Initialize the tree. - * @param tree the tree to be initialized. - * @param comp key comparison function to be used for this tree. - */ -PJ_DECL(void) pj_rbtree_init( pj_rbtree *tree, pj_rbtree_comp *comp); - -/** - * Get the first element in the tree. - * The first element always has the least value for the key, according to - * the comparison function. - * @param tree the tree. - * @return the tree node, or NULL if the tree has no element. - */ -PJ_DECL(pj_rbtree_node*) pj_rbtree_first( pj_rbtree *tree ); - -/** - * Get the last element in the tree. - * The last element always has the greatest key value, according to the - * comparison function defined for the tree. - * @param tree the tree. - * @return the tree node, or NULL if the tree has no element. - */ -PJ_DECL(pj_rbtree_node*) pj_rbtree_last( pj_rbtree *tree ); - -/** - * Get the successive element for the specified node. - * The successive element is an element with greater key value. - * @param tree the tree. - * @param node the node. - * @return the successive node, or NULL if the node has no successor. - */ -PJ_DECL(pj_rbtree_node*) pj_rbtree_next( pj_rbtree *tree, - pj_rbtree_node *node ); - -/** - * The the previous node for the specified node. - * The previous node is an element with less key value. - * @param tree the tree. - * @param node the node. - * @return the previous node, or NULL if the node has no previous node. - */ -PJ_DECL(pj_rbtree_node*) pj_rbtree_prev( pj_rbtree *tree, - pj_rbtree_node *node ); - -/** - * Insert a new node. - * The node will be inserted at sorted location. The key of the node must - * be UNIQUE, i.e. it hasn't existed in the tree. - * @param tree the tree. - * @param node the node to be inserted. - * @return zero on success, or -1 if the key already exist. - */ -PJ_DECL(int) pj_rbtree_insert( pj_rbtree *tree, - pj_rbtree_node *node ); - -/** - * Find a node which has the specified key. - * @param tree the tree. - * @param key the key to search. - * @return the tree node with the specified key, or NULL if the key can not - * be found. - */ -PJ_DECL(pj_rbtree_node*) pj_rbtree_find( pj_rbtree *tree, - const void *key ); - -/** - * Erase a node from the tree. - * @param tree the tree. - * @param node the node to be erased. - * @return the tree node itself. - */ -PJ_DECL(pj_rbtree_node*) pj_rbtree_erase( pj_rbtree *tree, - pj_rbtree_node *node ); - -/** - * Get the maximum tree height from the specified node. - * @param tree the tree. - * @param node the node, or NULL to get the root of the tree. - * @return the maximum height, which should be at most lg(N) - */ -PJ_DECL(unsigned) pj_rbtree_max_height( pj_rbtree *tree, - pj_rbtree_node *node ); - -/** - * Get the minumum tree height from the specified node. - * @param tree the tree. - * @param node the node, or NULL to get the root of the tree. - * @return the height - */ -PJ_DECL(unsigned) pj_rbtree_min_height( pj_rbtree *tree, - pj_rbtree_node *node ); - - -/** - * @} - */ - -PJ_END_DECL - -#endif /* __PJ_RBTREE_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 __PJ_RBTREE_H__
+#define __PJ_RBTREE_H__
+
+/**
+ * @file rbtree.h
+ * @brief Red/Black Tree
+ */
+
+#include <pj/types.h>
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup PJ_RBTREE Red/Black Balanced Tree
+ * @ingroup PJ_DS
+ * @brief
+ * Red/Black tree is the variant of balanced tree, where the search, insert,
+ * and delete operation is \b guaranteed to take at most \a O( lg(n) ).
+ * @{
+ */
+/**
+ * Color type for Red-Black tree.
+ */
+typedef enum pj_rbcolor_t
+{
+ PJ_RBCOLOR_BLACK,
+ PJ_RBCOLOR_RED
+} pj_rbcolor_t;
+
+/**
+ * The type of the node of the R/B Tree.
+ */
+typedef struct pj_rbtree_node
+{
+ /** Pointers to the node's parent, and left and right siblings. */
+ struct pj_rbtree_node *parent, *left, *right;
+
+ /** Key associated with the node. */
+ const void *key;
+
+ /** User data associated with the node. */
+ void *user_data;
+
+ /** The R/B Tree node color. */
+ pj_rbcolor_t color;
+
+} pj_rbtree_node;
+
+
+/**
+ * The type of function use to compare key value of tree node.
+ * @return
+ * 0 if the keys are equal
+ * <0 if key1 is lower than key2
+ * >0 if key1 is greater than key2.
+ */
+typedef int pj_rbtree_comp(const void *key1, const void *key2);
+
+
+/**
+ * Declaration of a red-black tree. All elements in the tree must have UNIQUE
+ * key.
+ * A red black tree always maintains the balance of the tree, so that the
+ * tree height will not be greater than lg(N). Insert, search, and delete
+ * operation will take lg(N) on the worst case. But for insert and delete,
+ * there is additional time needed to maintain the balance of the tree.
+ */
+typedef struct pj_rbtree
+{
+ pj_rbtree_node null_node; /**< Constant to indicate NULL node. */
+ pj_rbtree_node *null; /**< Constant to indicate NULL node. */
+ pj_rbtree_node *root; /**< Root tree node. */
+ unsigned size; /**< Number of elements in the tree. */
+ pj_rbtree_comp *comp; /**< Key comparison function. */
+} pj_rbtree;
+
+
+/**
+ * Guidance on how much memory required for each of the node.
+ */
+#define PJ_RBTREE_NODE_SIZE (sizeof(pj_rbtree_node))
+
+
+/**
+ * Guidance on memory required for the tree.
+ */
+#define PJ_RBTREE_SIZE (sizeof(pj_rbtree))
+
+
+/**
+ * Initialize the tree.
+ * @param tree the tree to be initialized.
+ * @param comp key comparison function to be used for this tree.
+ */
+PJ_DECL(void) pj_rbtree_init( pj_rbtree *tree, pj_rbtree_comp *comp);
+
+/**
+ * Get the first element in the tree.
+ * The first element always has the least value for the key, according to
+ * the comparison function.
+ * @param tree the tree.
+ * @return the tree node, or NULL if the tree has no element.
+ */
+PJ_DECL(pj_rbtree_node*) pj_rbtree_first( pj_rbtree *tree );
+
+/**
+ * Get the last element in the tree.
+ * The last element always has the greatest key value, according to the
+ * comparison function defined for the tree.
+ * @param tree the tree.
+ * @return the tree node, or NULL if the tree has no element.
+ */
+PJ_DECL(pj_rbtree_node*) pj_rbtree_last( pj_rbtree *tree );
+
+/**
+ * Get the successive element for the specified node.
+ * The successive element is an element with greater key value.
+ * @param tree the tree.
+ * @param node the node.
+ * @return the successive node, or NULL if the node has no successor.
+ */
+PJ_DECL(pj_rbtree_node*) pj_rbtree_next( pj_rbtree *tree,
+ pj_rbtree_node *node );
+
+/**
+ * The the previous node for the specified node.
+ * The previous node is an element with less key value.
+ * @param tree the tree.
+ * @param node the node.
+ * @return the previous node, or NULL if the node has no previous node.
+ */
+PJ_DECL(pj_rbtree_node*) pj_rbtree_prev( pj_rbtree *tree,
+ pj_rbtree_node *node );
+
+/**
+ * Insert a new node.
+ * The node will be inserted at sorted location. The key of the node must
+ * be UNIQUE, i.e. it hasn't existed in the tree.
+ * @param tree the tree.
+ * @param node the node to be inserted.
+ * @return zero on success, or -1 if the key already exist.
+ */
+PJ_DECL(int) pj_rbtree_insert( pj_rbtree *tree,
+ pj_rbtree_node *node );
+
+/**
+ * Find a node which has the specified key.
+ * @param tree the tree.
+ * @param key the key to search.
+ * @return the tree node with the specified key, or NULL if the key can not
+ * be found.
+ */
+PJ_DECL(pj_rbtree_node*) pj_rbtree_find( pj_rbtree *tree,
+ const void *key );
+
+/**
+ * Erase a node from the tree.
+ * @param tree the tree.
+ * @param node the node to be erased.
+ * @return the tree node itself.
+ */
+PJ_DECL(pj_rbtree_node*) pj_rbtree_erase( pj_rbtree *tree,
+ pj_rbtree_node *node );
+
+/**
+ * Get the maximum tree height from the specified node.
+ * @param tree the tree.
+ * @param node the node, or NULL to get the root of the tree.
+ * @return the maximum height, which should be at most lg(N)
+ */
+PJ_DECL(unsigned) pj_rbtree_max_height( pj_rbtree *tree,
+ pj_rbtree_node *node );
+
+/**
+ * Get the minumum tree height from the specified node.
+ * @param tree the tree.
+ * @param node the node, or NULL to get the root of the tree.
+ * @return the height
+ */
+PJ_DECL(unsigned) pj_rbtree_min_height( pj_rbtree *tree,
+ pj_rbtree_node *node );
+
+
+/**
+ * @}
+ */
+
+PJ_END_DECL
+
+#endif /* __PJ_RBTREE_H__ */
+
diff --git a/pjlib/include/pj/sock.h b/pjlib/include/pj/sock.h index 6dfbaf29..28d40b4e 100644 --- a/pjlib/include/pj/sock.h +++ b/pjlib/include/pj/sock.h @@ -1,83 +1,104 @@ -/* $Id$ - * - */ - -#ifndef __PJ_SOCK_H__ -#define __PJ_SOCK_H__ - -/** - * @file sock.h - * @brief Socket Abstraction. - */ - -#include <pj/types.h> - -PJ_BEGIN_DECL - - -/** - * @defgroup PJ_SOCK Socket Abstraction - * @ingroup PJ_IO - * @{ - * - * The PJLIB socket abstraction layer is a thin and very portable abstraction - * for socket API. It provides API similar to BSD socket API. The abstraction - * is needed because BSD socket API is not always available on all platforms, - * therefore it wouldn't be possible to create a trully portable network - * programs unless we provide such abstraction. - * - * Applications can use this API directly in their application, just - * as they would when using traditional BSD socket API, provided they - * call #pj_init() first. - * - * \section pj_sock_examples_sec Examples - * - * For some examples on how to use the socket API, please see: - * - * - \ref page_pjlib_sock_test - * - \ref page_pjlib_select_test - * - \ref page_pjlib_sock_perf_test - */ - - -/** - * Supported address families. - * APPLICATION MUST USE THESE VALUES INSTEAD OF NORMAL AF_*, BECAUSE - * THE LIBRARY WILL DO TRANSLATION TO THE NATIVE VALUE. - */ -extern const pj_uint16_t PJ_AF_UNIX; /**< Unix domain socket. */ -#define PJ_AF_LOCAL PJ_AF_UNIX; /**< POSIX name for AF_UNIX */ -extern const pj_uint16_t PJ_AF_INET; /**< Internet IP protocol. */ -extern const pj_uint16_t PJ_AF_INET6; /**< IP version 6. */ -extern const pj_uint16_t PJ_AF_PACKET; /**< Packet family. */ -extern const pj_uint16_t PJ_AF_IRDA; /**< IRDA sockets. */ - - -/** - * Supported types of sockets. - * APPLICATION MUST USE THESE VALUES INSTEAD OF NORMAL SOCK_*, BECAUSE - * THE LIBRARY WILL TRANSLATE THE VALUE TO THE NATIVE VALUE. - */ - -extern const pj_uint16_t PJ_SOCK_STREAM; /**< Sequenced, reliable, connection- - based byte streams. */ -extern const pj_uint16_t PJ_SOCK_DGRAM; /**< Connectionless, unreliable - datagrams of fixed maximum - lengths. */ -extern const pj_uint16_t PJ_SOCK_RAW; /**< Raw protocol interface. */ -extern const pj_uint16_t PJ_SOCK_RDM; /**< Reliably-delivered messages. */ - - -/** - * Socket level specified in #pj_sock_setsockopt() or #pj_sock_getsockopt(). - * APPLICATION MUST USE THESE VALUES INSTEAD OF NORMAL SOL_*, BECAUSE - * THE LIBRARY WILL TRANSLATE THE VALUE TO THE NATIVE VALUE. - */ -extern const pj_uint16_t PJ_SOL_SOCKET; /**< Socket level. */ -extern const pj_uint16_t PJ_SOL_IP; /**< IP level. */ -extern const pj_uint16_t PJ_SOL_TCP; /**< TCP level. */ -extern const pj_uint16_t PJ_SOL_UDP; /**< UDP level. */ -extern const pj_uint16_t PJ_SOL_IPV6; /**< IP version 6 */ +/* $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 __PJ_SOCK_H__
+#define __PJ_SOCK_H__
+
+/**
+ * @file sock.h
+ * @brief Socket Abstraction.
+ */
+
+#include <pj/types.h>
+
+PJ_BEGIN_DECL
+
+
+/**
+ * @defgroup PJ_SOCK Socket Abstraction
+ * @ingroup PJ_IO
+ * @{
+ *
+ * The PJLIB socket abstraction layer is a thin and very portable abstraction
+ * for socket API. It provides API similar to BSD socket API. The abstraction
+ * is needed because BSD socket API is not always available on all platforms,
+ * therefore it wouldn't be possible to create a trully portable network
+ * programs unless we provide such abstraction.
+ *
+ * Applications can use this API directly in their application, just
+ * as they would when using traditional BSD socket API, provided they
+ * call #pj_init() first.
+ *
+ * \section pj_sock_examples_sec Examples
+ *
+ * For some examples on how to use the socket API, please see:
+ *
+ * - \ref page_pjlib_sock_test
+ * - \ref page_pjlib_select_test
+ * - \ref page_pjlib_sock_perf_test
+ */
+
+
+/**
+ * Supported address families.
+ * APPLICATION MUST USE THESE VALUES INSTEAD OF NORMAL AF_*, BECAUSE
+ * THE LIBRARY WILL DO TRANSLATION TO THE NATIVE VALUE.
+ */
+extern const pj_uint16_t PJ_AF_UNIX; /**< Unix domain socket. */
+#define PJ_AF_LOCAL PJ_AF_UNIX; /**< POSIX name for AF_UNIX */
+extern const pj_uint16_t PJ_AF_INET; /**< Internet IP protocol. */
+extern const pj_uint16_t PJ_AF_INET6; /**< IP version 6. */
+extern const pj_uint16_t PJ_AF_PACKET; /**< Packet family. */
+extern const pj_uint16_t PJ_AF_IRDA; /**< IRDA sockets. */
+
+
+/**
+ * Supported types of sockets.
+ * APPLICATION MUST USE THESE VALUES INSTEAD OF NORMAL SOCK_*, BECAUSE
+ * THE LIBRARY WILL TRANSLATE THE VALUE TO THE NATIVE VALUE.
+ */
+
+extern const pj_uint16_t PJ_SOCK_STREAM; /**< Sequenced, reliable, connection-
+ based byte streams. */
+extern const pj_uint16_t PJ_SOCK_DGRAM; /**< Connectionless, unreliable
+ datagrams of fixed maximum
+ lengths. */
+extern const pj_uint16_t PJ_SOCK_RAW; /**< Raw protocol interface. */
+extern const pj_uint16_t PJ_SOCK_RDM; /**< Reliably-delivered messages. */
+
+
+/**
+ * Socket level specified in #pj_sock_setsockopt() or #pj_sock_getsockopt().
+ * APPLICATION MUST USE THESE VALUES INSTEAD OF NORMAL SOL_*, BECAUSE
+ * THE LIBRARY WILL TRANSLATE THE VALUE TO THE NATIVE VALUE.
+ */
+extern const pj_uint16_t PJ_SOL_SOCKET; /**< Socket level. */
+extern const pj_uint16_t PJ_SOL_IP; /**< IP level. */
+extern const pj_uint16_t PJ_SOL_TCP; /**< TCP level. */
+extern const pj_uint16_t PJ_SOL_UDP; /**< UDP level. */
+extern const pj_uint16_t PJ_SOL_IPV6; /**< IP version 6 */
/**
* Values to be specified as \c optname when calling #pj_sock_setsockopt()
@@ -87,600 +108,600 @@ extern const pj_uint16_t PJ_SO_TYPE; /**< Socket type. */ extern const pj_uint16_t PJ_SO_RCVBUF; /**< Buffer size for receive. */
extern const pj_uint16_t PJ_SO_SNDBUF; /**< Buffer size for send. */
- -/** - * Flags to be specified in #pj_sock_recv, #pj_sock_send, etc. - */ -typedef enum pj_sock_msg_flag -{ - PJ_MSG_OOB = 0x01, /**< Out-of-band messages. */ - PJ_MSG_PEEK = 0x02, /**< Peek, don't remove from buffer. */ - PJ_MSG_DONTROUTE = 0x04, /**< Don't route. */ -} pj_sock_msg_flag; - - -/** - * Flag to be specified in #pj_sock_shutdown. - */ -typedef enum pj_socket_sd_type -{ - PJ_SD_RECEIVE = 0, /**< No more receive. */ - PJ_SHUT_RD = 0, /**< Alias for SD_RECEIVE. */ - PJ_SD_SEND = 1, /**< No more sending. */ - PJ_SHUT_WR = 1, /**< Alias for SD_SEND. */ - PJ_SD_BOTH = 2, /**< No more send and receive. */ - PJ_SHUT_RDWR = 2, /**< Alias for SD_BOTH. */ -} pj_socket_sd_type; - - - -/** Address to accept any incoming messages. */ -#define PJ_INADDR_ANY ((pj_uint32_t)0) - -/** Address indicating an error return */ -#define PJ_INADDR_NONE ((pj_uint32_t)0xffffffff) - -/** Address to send to all hosts. */ -#define PJ_INADDR_BROADCAST ((pj_uint32_t)0xffffffff) - - -/** - * Maximum length specifiable by #pj_sock_listen(). - * If the build system doesn't override this value, then the lowest - * denominator (five, in Win32 systems) will be used. - */ -#if !defined(PJ_SOMAXCONN) -# define PJ_SOMAXCONN 5 -#endif - - -/** - * Constant for invalid socket returned by #pj_sock_socket() and - * #pj_sock_accept(). - */ -#define PJ_INVALID_SOCKET (-1) - -/** - * Structure describing a generic socket address. - */ -typedef struct pj_sockaddr -{ - pj_uint16_t sa_family; /**< Common data: address family. */ - char sa_data[14]; /**< Address data. */ -} pj_sockaddr; - - -/** - * This structure describes Internet address. - */ -typedef struct pj_in_addr -{ - pj_uint32_t s_addr; /**< The 32bit IP address. */ -} pj_in_addr; - - -/** - * This structure describes Internet socket address. - */ -typedef struct pj_sockaddr_in -{ - pj_uint16_t sin_family; /**< Address family. */ - pj_uint16_t sin_port; /**< Transport layer port number. */ - pj_in_addr sin_addr; /**< IP address. */ - char sin_zero[8]; /**< Padding. */ -} pj_sockaddr_in; - - -/** - * This structure describes IPv6 address. - */ -typedef struct pj_in6_addr -{ - /** Union of address formats. */ - union { - pj_uint8_t u6_addr8[16]; /**< u6_addr8 */ - pj_uint16_t u6_addr16[8]; /**< u6_addr16 */ - pj_uint32_t u6_addr32[4]; /**< u6_addr32 */ - } in6_u; -/** Shortcut to access in6_u.u6_addr8. */ -#define s6_addr in6_u.u6_addr8 -/** Shortcut to access in6_u.u6_addr16. */ -#define s6_addr16 in6_u.u6_addr16 -/** Shortcut to access in6_u.u6_addr32. */ -#define s6_addr32 in6_u.u6_addr32 -} pj_in6_addr; - -/** Initializer value for pj_in6_addr. */ -#define PJ_IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } } - -/** Initializer value for pj_in6_addr. */ -#define PJ_IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } } - -/** - * This structure describes IPv6 socket address. - */ -typedef struct pj_sockaddr_in6 -{ - pj_uint16_t sin6_family; /**< Address family */ - pj_uint16_t sin6_port; /**< Transport layer port number. */ - pj_uint32_t sin6_flowinfo; /**< IPv6 flow information */ - pj_in6_addr sin6_addr; /**< IPv6 address. */ - pj_uint32_t sin6_scope_id; /**< IPv6 scope-id */ -} pj_sockaddr_in6; - - -/***************************************************************************** - * - * SOCKET ADDRESS MANIPULATION. - * - ***************************************************************************** - */ - -/** - * Convert 16-bit value from network byte order to host byte order. - * - * @param netshort 16-bit network value. - * @return 16-bit host value. - */ -PJ_DECL(pj_uint16_t) pj_ntohs(pj_uint16_t netshort); - -/** - * Convert 16-bit value from host byte order to network byte order. - * - * @param hostshort 16-bit host value. - * @return 16-bit network value. - */ -PJ_DECL(pj_uint16_t) pj_htons(pj_uint16_t hostshort); - -/** - * Convert 32-bit value from network byte order to host byte order. - * - * @param netlong 32-bit network value. - * @return 32-bit host value. - */ -PJ_DECL(pj_uint32_t) pj_ntohl(pj_uint32_t netlong); - -/** - * Convert 32-bit value from host byte order to network byte order. - * - * @param hostlong 32-bit host value. - * @return 32-bit network value. - */ -PJ_DECL(pj_uint32_t) pj_htonl(pj_uint32_t hostlong); - -/** - * Convert an Internet host address given in network byte order - * to string in standard numbers and dots notation. - * - * @param inaddr The host address. - * @return The string address. - */ -PJ_DECL(char*) pj_inet_ntoa(pj_in_addr inaddr); - -/** - * 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. - * - * @param cp IP address in standard numbers-and-dots notation. - * @param inp Structure that holds the output of the conversion. - * - * @return nonzero if the address is valid, zero if not. - */ -PJ_DECL(int) pj_inet_aton(const pj_str_t *cp, struct pj_in_addr *inp); - -/** - * Convert address string with numbers and dots to binary IP address. - * - * @param cp The IP address in numbers and dots notation. - * @return If success, the IP address is returned in network - * byte order. If failed, PJ_INADDR_NONE will be - * returned. - * @remark - * This is an obsolete interface to #pj_inet_aton(); it is obsolete - * because -1 is a valid address (255.255.255.255), and #pj_inet_aton() - * provides a cleaner way to indicate error return. - */ -PJ_DECL(pj_in_addr) pj_inet_addr(const pj_str_t *cp); - - -/** - * Get the transport layer port number of an Internet socket address. - * The port is returned in host byte order. - * - * @param addr The IP socket address. - * @return Port number, in host byte order. - */ -PJ_INLINE(pj_uint16_t) pj_sockaddr_in_get_port(const pj_sockaddr_in *addr) -{ - return pj_ntohs(addr->sin_port); -} - -/** - * Set the port number of an Internet socket address. - * - * @param addr The IP socket address. - * @param hostport The port number, in host byte order. - */ -PJ_INLINE(void) pj_sockaddr_in_set_port(pj_sockaddr_in *addr, - pj_uint16_t hostport) -{ - addr->sin_port = pj_htons(hostport); -} - -/** - * Get the IP address of an Internet socket address. - * The address is returned as 32bit value in host byte order. - * - * @param addr The IP socket address. - * @return 32bit address, in host byte order. - */ -PJ_INLINE(pj_in_addr) pj_sockaddr_in_get_addr(const pj_sockaddr_in *addr) -{ - pj_in_addr in_addr; - in_addr.s_addr = pj_ntohl(addr->sin_addr.s_addr); - return in_addr; -}; - -/** - * Set the IP address of an Internet socket address. - * - * @param addr The IP socket address. - * @param hostaddr The host address, in host byte order. - */ -PJ_INLINE(void) pj_sockaddr_in_set_addr(pj_sockaddr_in *addr, - pj_uint32_t hostaddr) -{ - addr->sin_addr.s_addr = pj_htonl(hostaddr); -} - -/** - * 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. - * - * @param addr The IP socket address to be set. - * @param cp The address string, which can be in a standard - * dotted numbers or a hostname to be resolved. - * - * @return Zero on success. - */ -PJ_DECL(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr, - const pj_str_t *cp); - -/** - * 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. - * - * @param addr The IP socket address to be set. - * @param cp The address string, which can be in a standard - * dotted numbers or a hostname to be resolved. - * @param port The port number, in host byte order. - * - * @return Zero on success. - */ -PJ_DECL(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr, - const pj_str_t *cp, - pj_uint16_t port); - - -/***************************************************************************** - * - * HOST NAME AND ADDRESS. - * - ***************************************************************************** - */ - -/** - * Get system's host name. - * - * @return The hostname, or empty string if the hostname can not - * be identified. - */ -PJ_DECL(const pj_str_t*) pj_gethostname(void); - -/** - * Get host's IP address, which the the first IP address that is resolved - * from the hostname. - * - * @return The host's IP address, PJ_INADDR_NONE if the host - * IP address can not be identified. - */ -PJ_DECL(pj_in_addr) pj_gethostaddr(void); - - -/***************************************************************************** - * - * SOCKET API. - * - ***************************************************************************** - */ - -/** - * Create new socket/endpoint for communication. - * - * @param family Specifies a communication domain; this selects the - * protocol family which will be used for communication. - * @param type The socket has the indicated type, which specifies the - * communication semantics. - * @param protocol Specifies a particular protocol to be used with the - * socket. Normally only a single protocol exists to support - * a particular socket type within a given protocol family, - * in which a case protocol can be specified as 0. - * @param sock New socket descriptor, or PJ_INVALID_SOCKET on error. - * - * @return Zero on success. - */ -PJ_DECL(pj_status_t) pj_sock_socket(int family, - int type, - int protocol, - pj_sock_t *sock); - -/** - * Close the socket descriptor. - * - * @param sockfd The socket descriptor. - * - * @return Zero on success. - */ -PJ_DECL(pj_status_t) pj_sock_close(pj_sock_t sockfd); -
- -/** - * This function gives the socket sockfd the local address my_addr. my_addr is - * addrlen bytes long. Traditionally, this is called assigning a name to - * a socket. When a socket is created with #pj_sock_socket(), it exists in a - * name space (address family) but has no name assigned. - * - * @param sockfd The socket desriptor. - * @param my_addr The local address to bind the socket to. - * @param addrlen The length of the address. - * - * @return Zero on success. - */ -PJ_DECL(pj_status_t) pj_sock_bind( pj_sock_t sockfd, - const pj_sockaddr_t *my_addr, - int addrlen); - -/** - * Bind the IP socket sockfd to the given address and port. - * - * @param sockfd The socket descriptor. - * @param addr Local address to bind the socket to, in host byte order. - * @param port The local port to bind the socket to, in host byte order. - * - * @return Zero on success. - */ -PJ_DECL(pj_status_t) pj_sock_bind_in( pj_sock_t sockfd, - pj_uint32_t addr, - pj_uint16_t port); - -#if PJ_HAS_TCP -/** - * Listen for incoming connection. This function only applies to connection - * oriented sockets (such as PJ_SOCK_STREAM or PJ_SOCK_SEQPACKET), and it - * indicates the willingness to accept incoming connections. - * - * @param sockfd The socket descriptor. - * @param backlog Defines the maximum length the queue of pending - * connections may grow to. - * - * @return Zero on success. - */ -PJ_DECL(pj_status_t) pj_sock_listen( pj_sock_t sockfd, - int backlog ); - -/** - * Accept new connection on the specified connection oriented server socket. - * - * @param serverfd The server socket. - * @param newsock New socket on success, of PJ_INVALID_SOCKET if failed. - * @param addr A pointer to sockaddr type. If the argument is not NULL, - * it will be filled by the address of connecting entity. - * @param addrlen Initially specifies the length of the address, and upon - * return will be filled with the exact address length. - * - * @return Zero on success, or the error number. - */ -PJ_DECL(pj_status_t) pj_sock_accept( pj_sock_t serverfd, - pj_sock_t *newsock, - pj_sockaddr_t *addr, - int *addrlen); -#endif - -/** - * The file descriptor sockfd must refer to a socket. If the socket is of - * type PJ_SOCK_DGRAM then the serv_addr address is the address to which - * datagrams are sent by default, and the only address from which datagrams - * are received. If the socket is of type PJ_SOCK_STREAM or PJ_SOCK_SEQPACKET, - * this call attempts to make a connection to another socket. The - * other socket is specified by serv_addr, which is an address (of length - * addrlen) in the communications space of the socket. Each communications - * space interprets the serv_addr parameter in its own way. - * - * @param sockfd The socket descriptor. - * @param serv_addr Server address to connect to. - * @param addrlen The length of server address. - * - * @return Zero on success. - */ -PJ_DECL(pj_status_t) pj_sock_connect( pj_sock_t sockfd, - const pj_sockaddr_t *serv_addr, - int addrlen); - -/** - * Return the address of peer which is connected to socket sockfd. - * - * @param sockfd The socket descriptor. - * @param addr Pointer to sockaddr structure to which the address - * will be returned. - * @param namelen Initially the length of the addr. Upon return the value - * will be set to the actual length of the address. - * - * @return Zero on success. - */ -PJ_DECL(pj_status_t) pj_sock_getpeername(pj_sock_t sockfd, - pj_sockaddr_t *addr, - int *namelen); - -/** - * Return the current name of the specified socket. - * - * @param sockfd The socket descriptor. - * @param addr Pointer to sockaddr structure to which the address - * will be returned. - * @param namelen Initially the length of the addr. Upon return the value - * will be set to the actual length of the address. - * - * @return Zero on success. - */ -PJ_DECL(pj_status_t) pj_sock_getsockname( pj_sock_t sockfd, - pj_sockaddr_t *addr, - int *namelen); - -/** - * Get socket option associated with a socket. Options may exist at multiple - * protocol levels; they are always present at the uppermost socket level. - * - * @param sockfd The socket descriptor. - * @param level The level which to get the option from. - * @param optname The option name. - * @param optval Identifies the buffer which the value will be - * returned. - * @param optlen Initially contains the length of the buffer, upon - * return will be set to the actual size of the value. - * - * @return Zero on success. - */ -PJ_DECL(pj_status_t) pj_sock_getsockopt( pj_sock_t sockfd, - pj_uint16_t level, - pj_uint16_t optname, - void *optval, - int *optlen); -/** - * Manipulate the options associated with a socket. Options may exist at - * multiple protocol levels; they are always present at the uppermost socket - * level. - * - * @param sockfd The socket descriptor. - * @param level The level which to get the option from. - * @param optname The option name. - * @param optval Identifies the buffer which contain the value. - * @param optlen The length of the value. - * - * @return PJ_SUCCESS or the status code. - */ -PJ_DECL(pj_status_t) pj_sock_setsockopt( pj_sock_t sockfd, - pj_uint16_t level, - pj_uint16_t optname, - const void *optval, - int optlen); - - -/** - * Receives data stream or message coming to the specified socket. - * - * @param sockfd The socket descriptor. - * @param buf The buffer to receive the data or message. - * @param len On input, the length of the buffer. On return, - * contains the length of data received. - * @param flags Combination of #pj_sock_msg_flag. - * - * @return PJ_SUCCESS or the error code. - */ -PJ_DECL(pj_status_t) pj_sock_recv(pj_sock_t sockfd, - void *buf, - pj_ssize_t *len, - unsigned flags); - -/** - * Receives data stream or message coming to the specified socket. - * - * @param sockfd The socket descriptor. - * @param buf The buffer to receive the data or message. - * @param len On input, the length of the buffer. On return, - * contains the length of data received. - * @param flags Bitmask combination of #pj_sock_msg_flag. - * @param from If not NULL, it will be filled with the source - * address of the connection. - * @param fromlen Initially contains the length of from address, - * and upon return will be filled with the actual - * length of the address. - * - * @return PJ_SUCCESS or the error code. - */ -PJ_DECL(pj_status_t) pj_sock_recvfrom( pj_sock_t sockfd, - void *buf, - pj_ssize_t *len, - unsigned flags, - pj_sockaddr_t *from, - int *fromlen); - -/** - * Transmit data to the socket. - * - * @param sockfd Socket descriptor. - * @param buf Buffer containing data to be sent. - * @param len On input, the length of the data in the buffer. - * Upon return, it will be filled with the length - * of data sent. - * @param flags Bitmask combination of #pj_sock_msg_flag. - * - * @return PJ_SUCCESS or the status code. - */ -PJ_DECL(pj_status_t) pj_sock_send(pj_sock_t sockfd, - const void *buf, - pj_ssize_t *len, - unsigned flags); - -/** - * Transmit data to the socket to the specified address. - * - * @param sockfd Socket descriptor. - * @param buf Buffer containing data to be sent. - * @param len On input, the length of the data in the buffer. - * Upon return, it will be filled with the length - * of data sent. - * @param flags Bitmask combination of #pj_sock_msg_flag. - * @param to The address to send. - * @param tolen The length of the address in bytes. - * - * @return The length of data successfully sent. - */ -PJ_DECL(pj_status_t) pj_sock_sendto(pj_sock_t sockfd, - const void *buf, - pj_ssize_t *len, - unsigned flags, - const pj_sockaddr_t *to, - int tolen); - -#if PJ_HAS_TCP -/** - * The shutdown call causes all or part of a full-duplex connection on the - * socket associated with sockfd to be shut down. - * - * @param sockfd The socket descriptor. - * @param how If how is PJ_SHUT_RD, further receptions will be - * disallowed. If how is PJ_SHUT_WR, further transmissions - * will be disallowed. If how is PJ_SHUT_RDWR, further - * receptions andtransmissions will be disallowed. - * - * @return Zero on success. - */ -PJ_DECL(pj_status_t) pj_sock_shutdown( pj_sock_t sockfd, - int how); -#endif - -/** - * @} - */ - - -PJ_END_DECL - -#endif /* __PJ_SOCK_H__ */ - +
+/**
+ * Flags to be specified in #pj_sock_recv, #pj_sock_send, etc.
+ */
+typedef enum pj_sock_msg_flag
+{
+ PJ_MSG_OOB = 0x01, /**< Out-of-band messages. */
+ PJ_MSG_PEEK = 0x02, /**< Peek, don't remove from buffer. */
+ PJ_MSG_DONTROUTE = 0x04, /**< Don't route. */
+} pj_sock_msg_flag;
+
+
+/**
+ * Flag to be specified in #pj_sock_shutdown.
+ */
+typedef enum pj_socket_sd_type
+{
+ PJ_SD_RECEIVE = 0, /**< No more receive. */
+ PJ_SHUT_RD = 0, /**< Alias for SD_RECEIVE. */
+ PJ_SD_SEND = 1, /**< No more sending. */
+ PJ_SHUT_WR = 1, /**< Alias for SD_SEND. */
+ PJ_SD_BOTH = 2, /**< No more send and receive. */
+ PJ_SHUT_RDWR = 2, /**< Alias for SD_BOTH. */
+} pj_socket_sd_type;
+
+
+
+/** Address to accept any incoming messages. */
+#define PJ_INADDR_ANY ((pj_uint32_t)0)
+
+/** Address indicating an error return */
+#define PJ_INADDR_NONE ((pj_uint32_t)0xffffffff)
+
+/** Address to send to all hosts. */
+#define PJ_INADDR_BROADCAST ((pj_uint32_t)0xffffffff)
+
+
+/**
+ * Maximum length specifiable by #pj_sock_listen().
+ * If the build system doesn't override this value, then the lowest
+ * denominator (five, in Win32 systems) will be used.
+ */
+#if !defined(PJ_SOMAXCONN)
+# define PJ_SOMAXCONN 5
+#endif
+
+
+/**
+ * Constant for invalid socket returned by #pj_sock_socket() and
+ * #pj_sock_accept().
+ */
+#define PJ_INVALID_SOCKET (-1)
+
+/**
+ * Structure describing a generic socket address.
+ */
+typedef struct pj_sockaddr
+{
+ pj_uint16_t sa_family; /**< Common data: address family. */
+ char sa_data[14]; /**< Address data. */
+} pj_sockaddr;
+
+
+/**
+ * This structure describes Internet address.
+ */
+typedef struct pj_in_addr
+{
+ pj_uint32_t s_addr; /**< The 32bit IP address. */
+} pj_in_addr;
+
+
+/**
+ * This structure describes Internet socket address.
+ */
+typedef struct pj_sockaddr_in
+{
+ pj_uint16_t sin_family; /**< Address family. */
+ pj_uint16_t sin_port; /**< Transport layer port number. */
+ pj_in_addr sin_addr; /**< IP address. */
+ char sin_zero[8]; /**< Padding. */
+} pj_sockaddr_in;
+
+
+/**
+ * This structure describes IPv6 address.
+ */
+typedef struct pj_in6_addr
+{
+ /** Union of address formats. */
+ union {
+ pj_uint8_t u6_addr8[16]; /**< u6_addr8 */
+ pj_uint16_t u6_addr16[8]; /**< u6_addr16 */
+ pj_uint32_t u6_addr32[4]; /**< u6_addr32 */
+ } in6_u;
+/** Shortcut to access in6_u.u6_addr8. */
+#define s6_addr in6_u.u6_addr8
+/** Shortcut to access in6_u.u6_addr16. */
+#define s6_addr16 in6_u.u6_addr16
+/** Shortcut to access in6_u.u6_addr32. */
+#define s6_addr32 in6_u.u6_addr32
+} pj_in6_addr;
+
+/** Initializer value for pj_in6_addr. */
+#define PJ_IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }
+
+/** Initializer value for pj_in6_addr. */
+#define PJ_IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } }
+
+/**
+ * This structure describes IPv6 socket address.
+ */
+typedef struct pj_sockaddr_in6
+{
+ pj_uint16_t sin6_family; /**< Address family */
+ pj_uint16_t sin6_port; /**< Transport layer port number. */
+ pj_uint32_t sin6_flowinfo; /**< IPv6 flow information */
+ pj_in6_addr sin6_addr; /**< IPv6 address. */
+ pj_uint32_t sin6_scope_id; /**< IPv6 scope-id */
+} pj_sockaddr_in6;
+
+
+/*****************************************************************************
+ *
+ * SOCKET ADDRESS MANIPULATION.
+ *
+ *****************************************************************************
+ */
+
+/**
+ * Convert 16-bit value from network byte order to host byte order.
+ *
+ * @param netshort 16-bit network value.
+ * @return 16-bit host value.
+ */
+PJ_DECL(pj_uint16_t) pj_ntohs(pj_uint16_t netshort);
+
+/**
+ * Convert 16-bit value from host byte order to network byte order.
+ *
+ * @param hostshort 16-bit host value.
+ * @return 16-bit network value.
+ */
+PJ_DECL(pj_uint16_t) pj_htons(pj_uint16_t hostshort);
+
+/**
+ * Convert 32-bit value from network byte order to host byte order.
+ *
+ * @param netlong 32-bit network value.
+ * @return 32-bit host value.
+ */
+PJ_DECL(pj_uint32_t) pj_ntohl(pj_uint32_t netlong);
+
+/**
+ * Convert 32-bit value from host byte order to network byte order.
+ *
+ * @param hostlong 32-bit host value.
+ * @return 32-bit network value.
+ */
+PJ_DECL(pj_uint32_t) pj_htonl(pj_uint32_t hostlong);
+
+/**
+ * Convert an Internet host address given in network byte order
+ * to string in standard numbers and dots notation.
+ *
+ * @param inaddr The host address.
+ * @return The string address.
+ */
+PJ_DECL(char*) pj_inet_ntoa(pj_in_addr inaddr);
+
+/**
+ * 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.
+ *
+ * @param cp IP address in standard numbers-and-dots notation.
+ * @param inp Structure that holds the output of the conversion.
+ *
+ * @return nonzero if the address is valid, zero if not.
+ */
+PJ_DECL(int) pj_inet_aton(const pj_str_t *cp, struct pj_in_addr *inp);
+
+/**
+ * Convert address string with numbers and dots to binary IP address.
+ *
+ * @param cp The IP address in numbers and dots notation.
+ * @return If success, the IP address is returned in network
+ * byte order. If failed, PJ_INADDR_NONE will be
+ * returned.
+ * @remark
+ * This is an obsolete interface to #pj_inet_aton(); it is obsolete
+ * because -1 is a valid address (255.255.255.255), and #pj_inet_aton()
+ * provides a cleaner way to indicate error return.
+ */
+PJ_DECL(pj_in_addr) pj_inet_addr(const pj_str_t *cp);
+
+
+/**
+ * Get the transport layer port number of an Internet socket address.
+ * The port is returned in host byte order.
+ *
+ * @param addr The IP socket address.
+ * @return Port number, in host byte order.
+ */
+PJ_INLINE(pj_uint16_t) pj_sockaddr_in_get_port(const pj_sockaddr_in *addr)
+{
+ return pj_ntohs(addr->sin_port);
+}
+
+/**
+ * Set the port number of an Internet socket address.
+ *
+ * @param addr The IP socket address.
+ * @param hostport The port number, in host byte order.
+ */
+PJ_INLINE(void) pj_sockaddr_in_set_port(pj_sockaddr_in *addr,
+ pj_uint16_t hostport)
+{
+ addr->sin_port = pj_htons(hostport);
+}
+
+/**
+ * Get the IP address of an Internet socket address.
+ * The address is returned as 32bit value in host byte order.
+ *
+ * @param addr The IP socket address.
+ * @return 32bit address, in host byte order.
+ */
+PJ_INLINE(pj_in_addr) pj_sockaddr_in_get_addr(const pj_sockaddr_in *addr)
+{
+ pj_in_addr in_addr;
+ in_addr.s_addr = pj_ntohl(addr->sin_addr.s_addr);
+ return in_addr;
+};
+
+/**
+ * Set the IP address of an Internet socket address.
+ *
+ * @param addr The IP socket address.
+ * @param hostaddr The host address, in host byte order.
+ */
+PJ_INLINE(void) pj_sockaddr_in_set_addr(pj_sockaddr_in *addr,
+ pj_uint32_t hostaddr)
+{
+ addr->sin_addr.s_addr = pj_htonl(hostaddr);
+}
+
+/**
+ * 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.
+ *
+ * @param addr The IP socket address to be set.
+ * @param cp The address string, which can be in a standard
+ * dotted numbers or a hostname to be resolved.
+ *
+ * @return Zero on success.
+ */
+PJ_DECL(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr,
+ const pj_str_t *cp);
+
+/**
+ * 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.
+ *
+ * @param addr The IP socket address to be set.
+ * @param cp The address string, which can be in a standard
+ * dotted numbers or a hostname to be resolved.
+ * @param port The port number, in host byte order.
+ *
+ * @return Zero on success.
+ */
+PJ_DECL(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr,
+ const pj_str_t *cp,
+ pj_uint16_t port);
+
+
+/*****************************************************************************
+ *
+ * HOST NAME AND ADDRESS.
+ *
+ *****************************************************************************
+ */
+
+/**
+ * Get system's host name.
+ *
+ * @return The hostname, or empty string if the hostname can not
+ * be identified.
+ */
+PJ_DECL(const pj_str_t*) pj_gethostname(void);
+
+/**
+ * Get host's IP address, which the the first IP address that is resolved
+ * from the hostname.
+ *
+ * @return The host's IP address, PJ_INADDR_NONE if the host
+ * IP address can not be identified.
+ */
+PJ_DECL(pj_in_addr) pj_gethostaddr(void);
+
+
+/*****************************************************************************
+ *
+ * SOCKET API.
+ *
+ *****************************************************************************
+ */
+
+/**
+ * Create new socket/endpoint for communication.
+ *
+ * @param family Specifies a communication domain; this selects the
+ * protocol family which will be used for communication.
+ * @param type The socket has the indicated type, which specifies the
+ * communication semantics.
+ * @param protocol Specifies a particular protocol to be used with the
+ * socket. Normally only a single protocol exists to support
+ * a particular socket type within a given protocol family,
+ * in which a case protocol can be specified as 0.
+ * @param sock New socket descriptor, or PJ_INVALID_SOCKET on error.
+ *
+ * @return Zero on success.
+ */
+PJ_DECL(pj_status_t) pj_sock_socket(int family,
+ int type,
+ int protocol,
+ pj_sock_t *sock);
+
+/**
+ * Close the socket descriptor.
+ *
+ * @param sockfd The socket descriptor.
+ *
+ * @return Zero on success.
+ */
+PJ_DECL(pj_status_t) pj_sock_close(pj_sock_t sockfd);
+
+
+/**
+ * This function gives the socket sockfd the local address my_addr. my_addr is
+ * addrlen bytes long. Traditionally, this is called assigning a name to
+ * a socket. When a socket is created with #pj_sock_socket(), it exists in a
+ * name space (address family) but has no name assigned.
+ *
+ * @param sockfd The socket desriptor.
+ * @param my_addr The local address to bind the socket to.
+ * @param addrlen The length of the address.
+ *
+ * @return Zero on success.
+ */
+PJ_DECL(pj_status_t) pj_sock_bind( pj_sock_t sockfd,
+ const pj_sockaddr_t *my_addr,
+ int addrlen);
+
+/**
+ * Bind the IP socket sockfd to the given address and port.
+ *
+ * @param sockfd The socket descriptor.
+ * @param addr Local address to bind the socket to, in host byte order.
+ * @param port The local port to bind the socket to, in host byte order.
+ *
+ * @return Zero on success.
+ */
+PJ_DECL(pj_status_t) pj_sock_bind_in( pj_sock_t sockfd,
+ pj_uint32_t addr,
+ pj_uint16_t port);
+
+#if PJ_HAS_TCP
+/**
+ * Listen for incoming connection. This function only applies to connection
+ * oriented sockets (such as PJ_SOCK_STREAM or PJ_SOCK_SEQPACKET), and it
+ * indicates the willingness to accept incoming connections.
+ *
+ * @param sockfd The socket descriptor.
+ * @param backlog Defines the maximum length the queue of pending
+ * connections may grow to.
+ *
+ * @return Zero on success.
+ */
+PJ_DECL(pj_status_t) pj_sock_listen( pj_sock_t sockfd,
+ int backlog );
+
+/**
+ * Accept new connection on the specified connection oriented server socket.
+ *
+ * @param serverfd The server socket.
+ * @param newsock New socket on success, of PJ_INVALID_SOCKET if failed.
+ * @param addr A pointer to sockaddr type. If the argument is not NULL,
+ * it will be filled by the address of connecting entity.
+ * @param addrlen Initially specifies the length of the address, and upon
+ * return will be filled with the exact address length.
+ *
+ * @return Zero on success, or the error number.
+ */
+PJ_DECL(pj_status_t) pj_sock_accept( pj_sock_t serverfd,
+ pj_sock_t *newsock,
+ pj_sockaddr_t *addr,
+ int *addrlen);
+#endif
+
+/**
+ * The file descriptor sockfd must refer to a socket. If the socket is of
+ * type PJ_SOCK_DGRAM then the serv_addr address is the address to which
+ * datagrams are sent by default, and the only address from which datagrams
+ * are received. If the socket is of type PJ_SOCK_STREAM or PJ_SOCK_SEQPACKET,
+ * this call attempts to make a connection to another socket. The
+ * other socket is specified by serv_addr, which is an address (of length
+ * addrlen) in the communications space of the socket. Each communications
+ * space interprets the serv_addr parameter in its own way.
+ *
+ * @param sockfd The socket descriptor.
+ * @param serv_addr Server address to connect to.
+ * @param addrlen The length of server address.
+ *
+ * @return Zero on success.
+ */
+PJ_DECL(pj_status_t) pj_sock_connect( pj_sock_t sockfd,
+ const pj_sockaddr_t *serv_addr,
+ int addrlen);
+
+/**
+ * Return the address of peer which is connected to socket sockfd.
+ *
+ * @param sockfd The socket descriptor.
+ * @param addr Pointer to sockaddr structure to which the address
+ * will be returned.
+ * @param namelen Initially the length of the addr. Upon return the value
+ * will be set to the actual length of the address.
+ *
+ * @return Zero on success.
+ */
+PJ_DECL(pj_status_t) pj_sock_getpeername(pj_sock_t sockfd,
+ pj_sockaddr_t *addr,
+ int *namelen);
+
+/**
+ * Return the current name of the specified socket.
+ *
+ * @param sockfd The socket descriptor.
+ * @param addr Pointer to sockaddr structure to which the address
+ * will be returned.
+ * @param namelen Initially the length of the addr. Upon return the value
+ * will be set to the actual length of the address.
+ *
+ * @return Zero on success.
+ */
+PJ_DECL(pj_status_t) pj_sock_getsockname( pj_sock_t sockfd,
+ pj_sockaddr_t *addr,
+ int *namelen);
+
+/**
+ * Get socket option associated with a socket. Options may exist at multiple
+ * protocol levels; they are always present at the uppermost socket level.
+ *
+ * @param sockfd The socket descriptor.
+ * @param level The level which to get the option from.
+ * @param optname The option name.
+ * @param optval Identifies the buffer which the value will be
+ * returned.
+ * @param optlen Initially contains the length of the buffer, upon
+ * return will be set to the actual size of the value.
+ *
+ * @return Zero on success.
+ */
+PJ_DECL(pj_status_t) pj_sock_getsockopt( pj_sock_t sockfd,
+ pj_uint16_t level,
+ pj_uint16_t optname,
+ void *optval,
+ int *optlen);
+/**
+ * Manipulate the options associated with a socket. Options may exist at
+ * multiple protocol levels; they are always present at the uppermost socket
+ * level.
+ *
+ * @param sockfd The socket descriptor.
+ * @param level The level which to get the option from.
+ * @param optname The option name.
+ * @param optval Identifies the buffer which contain the value.
+ * @param optlen The length of the value.
+ *
+ * @return PJ_SUCCESS or the status code.
+ */
+PJ_DECL(pj_status_t) pj_sock_setsockopt( pj_sock_t sockfd,
+ pj_uint16_t level,
+ pj_uint16_t optname,
+ const void *optval,
+ int optlen);
+
+
+/**
+ * Receives data stream or message coming to the specified socket.
+ *
+ * @param sockfd The socket descriptor.
+ * @param buf The buffer to receive the data or message.
+ * @param len On input, the length of the buffer. On return,
+ * contains the length of data received.
+ * @param flags Combination of #pj_sock_msg_flag.
+ *
+ * @return PJ_SUCCESS or the error code.
+ */
+PJ_DECL(pj_status_t) pj_sock_recv(pj_sock_t sockfd,
+ void *buf,
+ pj_ssize_t *len,
+ unsigned flags);
+
+/**
+ * Receives data stream or message coming to the specified socket.
+ *
+ * @param sockfd The socket descriptor.
+ * @param buf The buffer to receive the data or message.
+ * @param len On input, the length of the buffer. On return,
+ * contains the length of data received.
+ * @param flags Bitmask combination of #pj_sock_msg_flag.
+ * @param from If not NULL, it will be filled with the source
+ * address of the connection.
+ * @param fromlen Initially contains the length of from address,
+ * and upon return will be filled with the actual
+ * length of the address.
+ *
+ * @return PJ_SUCCESS or the error code.
+ */
+PJ_DECL(pj_status_t) pj_sock_recvfrom( pj_sock_t sockfd,
+ void *buf,
+ pj_ssize_t *len,
+ unsigned flags,
+ pj_sockaddr_t *from,
+ int *fromlen);
+
+/**
+ * Transmit data to the socket.
+ *
+ * @param sockfd Socket descriptor.
+ * @param buf Buffer containing data to be sent.
+ * @param len On input, the length of the data in the buffer.
+ * Upon return, it will be filled with the length
+ * of data sent.
+ * @param flags Bitmask combination of #pj_sock_msg_flag.
+ *
+ * @return PJ_SUCCESS or the status code.
+ */
+PJ_DECL(pj_status_t) pj_sock_send(pj_sock_t sockfd,
+ const void *buf,
+ pj_ssize_t *len,
+ unsigned flags);
+
+/**
+ * Transmit data to the socket to the specified address.
+ *
+ * @param sockfd Socket descriptor.
+ * @param buf Buffer containing data to be sent.
+ * @param len On input, the length of the data in the buffer.
+ * Upon return, it will be filled with the length
+ * of data sent.
+ * @param flags Bitmask combination of #pj_sock_msg_flag.
+ * @param to The address to send.
+ * @param tolen The length of the address in bytes.
+ *
+ * @return The length of data successfully sent.
+ */
+PJ_DECL(pj_status_t) pj_sock_sendto(pj_sock_t sockfd,
+ const void *buf,
+ pj_ssize_t *len,
+ unsigned flags,
+ const pj_sockaddr_t *to,
+ int tolen);
+
+#if PJ_HAS_TCP
+/**
+ * The shutdown call causes all or part of a full-duplex connection on the
+ * socket associated with sockfd to be shut down.
+ *
+ * @param sockfd The socket descriptor.
+ * @param how If how is PJ_SHUT_RD, further receptions will be
+ * disallowed. If how is PJ_SHUT_WR, further transmissions
+ * will be disallowed. If how is PJ_SHUT_RDWR, further
+ * receptions andtransmissions will be disallowed.
+ *
+ * @return Zero on success.
+ */
+PJ_DECL(pj_status_t) pj_sock_shutdown( pj_sock_t sockfd,
+ int how);
+#endif
+
+/**
+ * @}
+ */
+
+
+PJ_END_DECL
+
+#endif /* __PJ_SOCK_H__ */
+
diff --git a/pjlib/include/pj/sock_select.h b/pjlib/include/pj/sock_select.h index 5b0c7002..e515984f 100644 --- a/pjlib/include/pj/sock_select.h +++ b/pjlib/include/pj/sock_select.h @@ -1,133 +1,154 @@ -/* $Id$ - * - */ -/* $Log: /pjproject-0.3/pjlib/include/pj/sock_select.h $ - * - * 3 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 2 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 1 9/15/05 8:40p Bennylp - * Created. - */ -#ifndef __PJ_SELECT_H__ -#define __PJ_SELECT_H__ - -/** - * @file sock_select.h - * @brief Socket select(). - */ - -#include <pj/types.h> - -PJ_BEGIN_DECL - -/** - * @defgroup PJ_SOCK_SELECT Socket select() API. - * @ingroup PJ_IO - * @{ - * This module provides portable abstraction for \a select() like API. - * The abstraction is needed so that it can utilize various event - * dispatching mechanisms that are available across platforms. - * - * The API is very similar to normal \a select() usage. - * - * \section pj_sock_select_examples_sec Examples - * - * For some examples on how to use the select API, please see: - * - * - \ref page_pjlib_select_test - */ - -/** - * Portable structure declarations for pj_fd_set. - * The implementation of pj_sock_select() does not use this structure - * per-se, but instead it will use the native fd_set structure. However, - * we must make sure that the size of pj_fd_set_t can accomodate the - * native fd_set structure. - */ -typedef struct pj_fd_set_t -{ - pj_sock_t data[FD_SETSIZE + 4]; /**< Opaque buffer for fd_set */ -} pj_fd_set_t; - - -/** - * Initialize the descriptor set pointed to by fdsetp to the null set. - * - * @param fdsetp The descriptor set. - */ -PJ_DECL(void) PJ_FD_ZERO(pj_fd_set_t *fdsetp); - - -/** - * Add the file descriptor fd to the set pointed to by fdsetp. - * If the file descriptor fd is already in this set, there shall be no effect - * on the set, nor will an error be returned. - * - * @param fd The socket descriptor. - * @param fdsetp The descriptor set. - */ -PJ_DECL(void) PJ_FD_SET(pj_sock_t fd, pj_fd_set_t *fdsetp); - -/** - * Remove the file descriptor fd from the set pointed to by fdsetp. - * If fd is not a member of this set, there shall be no effect on the set, - * nor will an error be returned. - * - * @param fd The socket descriptor. - * @param fdsetp The descriptor set. - */ -PJ_DECL(void) PJ_FD_CLR(pj_sock_t fd, pj_fd_set_t *fdsetp); - - -/** - * Evaluate to non-zero if the file descriptor fd is a member of the set - * pointed to by fdsetp, and shall evaluate to zero otherwise. - * - * @param fd The socket descriptor. - * @param fdsetp The descriptor set. - * - * @return Nonzero if fd is member of the descriptor set. - */ -PJ_DECL(pj_bool_t) PJ_FD_ISSET(pj_sock_t fd, const pj_fd_set_t *fdsetp); - - -/** - * This function wait for a number of file descriptors to change status. - * The behaviour is the same as select() function call which appear in - * standard BSD socket libraries. - * - * @param n On Unices, this specifies the highest-numbered - * descriptor in any of the three set, plus 1. On Windows, - * the value is ignored. - * @param readfds Optional pointer to a set of sockets to be checked for - * readability. - * @param writefds Optional pointer to a set of sockets to be checked for - * writability. - * @param exceptfds Optional pointer to a set of sockets to be checked for - * errors. - * @param timeout Maximum time for select to wait, or null for blocking - * operations. - * - * @return The total number of socket handles that are ready, or - * zero if the time limit expired, or -1 if an error occurred. - */ -PJ_DECL(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); - - -/** - * @} - */ - - -PJ_END_DECL - -#endif /* __PJ_SELECT_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
+ */
+/* $Log: /pjproject-0.3/pjlib/include/pj/sock_select.h $
+ *
+ * 3 10/14/05 12:26a Bennylp
+ * Finished error code framework, some fixes in ioqueue, etc. Pretty
+ * major.
+ *
+ * 2 9/21/05 1:39p Bennylp
+ * Periodic checkin for backup.
+ *
+ * 1 9/15/05 8:40p Bennylp
+ * Created.
+ */
+#ifndef __PJ_SELECT_H__
+#define __PJ_SELECT_H__
+
+/**
+ * @file sock_select.h
+ * @brief Socket select().
+ */
+
+#include <pj/types.h>
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup PJ_SOCK_SELECT Socket select() API.
+ * @ingroup PJ_IO
+ * @{
+ * This module provides portable abstraction for \a select() like API.
+ * The abstraction is needed so that it can utilize various event
+ * dispatching mechanisms that are available across platforms.
+ *
+ * The API is very similar to normal \a select() usage.
+ *
+ * \section pj_sock_select_examples_sec Examples
+ *
+ * For some examples on how to use the select API, please see:
+ *
+ * - \ref page_pjlib_select_test
+ */
+
+/**
+ * Portable structure declarations for pj_fd_set.
+ * The implementation of pj_sock_select() does not use this structure
+ * per-se, but instead it will use the native fd_set structure. However,
+ * we must make sure that the size of pj_fd_set_t can accomodate the
+ * native fd_set structure.
+ */
+typedef struct pj_fd_set_t
+{
+ pj_sock_t data[FD_SETSIZE + 4]; /**< Opaque buffer for fd_set */
+} pj_fd_set_t;
+
+
+/**
+ * Initialize the descriptor set pointed to by fdsetp to the null set.
+ *
+ * @param fdsetp The descriptor set.
+ */
+PJ_DECL(void) PJ_FD_ZERO(pj_fd_set_t *fdsetp);
+
+
+/**
+ * Add the file descriptor fd to the set pointed to by fdsetp.
+ * If the file descriptor fd is already in this set, there shall be no effect
+ * on the set, nor will an error be returned.
+ *
+ * @param fd The socket descriptor.
+ * @param fdsetp The descriptor set.
+ */
+PJ_DECL(void) PJ_FD_SET(pj_sock_t fd, pj_fd_set_t *fdsetp);
+
+/**
+ * Remove the file descriptor fd from the set pointed to by fdsetp.
+ * If fd is not a member of this set, there shall be no effect on the set,
+ * nor will an error be returned.
+ *
+ * @param fd The socket descriptor.
+ * @param fdsetp The descriptor set.
+ */
+PJ_DECL(void) PJ_FD_CLR(pj_sock_t fd, pj_fd_set_t *fdsetp);
+
+
+/**
+ * Evaluate to non-zero if the file descriptor fd is a member of the set
+ * pointed to by fdsetp, and shall evaluate to zero otherwise.
+ *
+ * @param fd The socket descriptor.
+ * @param fdsetp The descriptor set.
+ *
+ * @return Nonzero if fd is member of the descriptor set.
+ */
+PJ_DECL(pj_bool_t) PJ_FD_ISSET(pj_sock_t fd, const pj_fd_set_t *fdsetp);
+
+
+/**
+ * This function wait for a number of file descriptors to change status.
+ * The behaviour is the same as select() function call which appear in
+ * standard BSD socket libraries.
+ *
+ * @param n On Unices, this specifies the highest-numbered
+ * descriptor in any of the three set, plus 1. On Windows,
+ * the value is ignored.
+ * @param readfds Optional pointer to a set of sockets to be checked for
+ * readability.
+ * @param writefds Optional pointer to a set of sockets to be checked for
+ * writability.
+ * @param exceptfds Optional pointer to a set of sockets to be checked for
+ * errors.
+ * @param timeout Maximum time for select to wait, or null for blocking
+ * operations.
+ *
+ * @return The total number of socket handles that are ready, or
+ * zero if the time limit expired, or -1 if an error occurred.
+ */
+PJ_DECL(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);
+
+
+/**
+ * @}
+ */
+
+
+PJ_END_DECL
+
+#endif /* __PJ_SELECT_H__ */
diff --git a/pjlib/include/pj/string.h b/pjlib/include/pj/string.h index 5b7ac130..22f107bb 100644 --- a/pjlib/include/pj/string.h +++ b/pjlib/include/pj/string.h @@ -1,520 +1,541 @@ -/* $Id$ - * - */ - -#ifndef __PJ_STRING_H__ -#define __PJ_STRING_H__ - -/** - * @file string.h - * @brief PJLIB String Operations. - */ - -#include <pj/types.h> -#include <pj/compat/string.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 __PJ_STRING_H__
+#define __PJ_STRING_H__
+
+/**
+ * @file string.h
+ * @brief PJLIB String Operations.
+ */
+
+#include <pj/types.h>
+#include <pj/compat/string.h>
#include <pj/compat/sprintf.h>
#include <pj/compat/vsprintf.h>
- -PJ_BEGIN_DECL - -/** - * @defgroup PJ_PSTR String Operations - * @ingroup PJ_DS - * @{ - * This module provides string manipulation API. - * - * \section pj_pstr_not_null_sec PJLIB String is NOT Null Terminated! - * - * That is the first information that developers need to know. Instead - * of using normal C string, strings in PJLIB are represented as - * pj_str_t structure below: - * - * <pre> - * typedef struct pj_str_t - * { - * char *ptr; - * pj_size_t slen; - * } pj_str_t; - * </pre> - * - * There are some advantages of using this approach: - * - the string can point to arbitrary location in memory even - * if the string in that location is not null terminated. This is - * most usefull for text parsing, where the parsed text can just - * point to the original text in the input. If we use C string, - * then we will have to copy the text portion from the input - * to a string variable. - * - because the length of the string is known, string copy operation - * can be made more efficient. - * - * Most of APIs in PJLIB that expect or return string will represent - * the string as pj_str_t instead of normal C string. - * - * \section pj_pstr_examples_sec Examples - * - * For some examples, please see: - * - @ref page_pjlib_string_test - */ - -/** - * Create string initializer from a normal C string. - * - * @param str Null terminated string to be stored. - * - * @return pj_str_t. - */ -PJ_IDECL(pj_str_t) pj_str(char *str); - -/** - * Create constant string from normal C string. - * - * @param str The string to be initialized. - * @param s Null terminated string. - * - * @return pj_str_t. - */ -PJ_INLINE(const pj_str_t*) pj_cstr(pj_str_t *str, const char *s) -{ - str->ptr = (char*)s; - str->slen = s ? strlen(s) : 0; - return str; -} - -/** - * Set the pointer and length to the specified value. - * - * @param str the string. - * @param ptr pointer to set. - * @param length length to set. - * - * @return the string. - */ -PJ_INLINE(pj_str_t*) pj_strset( pj_str_t *str, char *ptr, pj_size_t length) -{ - str->ptr = ptr; - str->slen = length; - return str; -} - -/** - * Set the pointer and length of the string to the source string, which - * must be NULL terminated. - * - * @param str the string. - * @param src pointer to set. - * - * @return the string. - */ -PJ_INLINE(pj_str_t*) pj_strset2( pj_str_t *str, char *src) -{ - str->ptr = src; - str->slen = src ? strlen(src) : 0; - return str; -} - -/** - * Set the pointer and the length of the string. - * - * @param str The target string. - * @param begin The start of the string. - * @param end The end of the string. - * - * @return the target string. - */ -PJ_INLINE(pj_str_t*) pj_strset3( pj_str_t *str, char *begin, char *end ) -{ - str->ptr = begin; - str->slen = end-begin; - return str; -} - -/** - * Assign string. - * - * @param dst The target string. - * @param src The source string. - * - * @return the target string. - */ -PJ_IDECL(pj_str_t*) pj_strassign( pj_str_t *dst, pj_str_t *src ); - -/** - * Copy string contents. - * - * @param dst The target string. - * @param src The source string. - * - * @return the target string. - */ -PJ_IDECL(pj_str_t*) pj_strcpy(pj_str_t *dst, const pj_str_t *src); - -/** - * Copy string contents. - * - * @param dst The target string. - * @param src The source string. - * - * @return the target string. - */ -PJ_IDECL(pj_str_t*) pj_strcpy2(pj_str_t *dst, const char *src); - -/** - * Duplicate string. - * - * @param pool The pool. - * @param dst The string result. - * @param src The string to duplicate. - * - * @return the string result. - */ -PJ_IDECL(pj_str_t*) pj_strdup(pj_pool_t *pool, - pj_str_t *dst, - const pj_str_t *src); - -/** - * Duplicate string and NULL terminate the destination string. - * - * @param pool - * @param dst - * @param src - */ -PJ_IDECL(pj_str_t*) pj_strdup_with_null(pj_pool_t *pool, - pj_str_t *dst, - const pj_str_t *src); - -/** - * Duplicate string. - * - * @param pool The pool. - * @param dst The string result. - * @param src The string to duplicate. - * - * @return the string result. - */ -PJ_IDECL(pj_str_t*) pj_strdup2(pj_pool_t *pool, - pj_str_t *dst, - const char *src); - -/** - * Duplicate string. - * - * @param pool The pool. - * @param src The string to duplicate. - * - * @return the string result. - */ -PJ_IDECL(pj_str_t) pj_strdup3(pj_pool_t *pool, const char *src); - -/** - * Return the length of the string. - * - * @param str The string. - * - * @return the length of the string. - */ -PJ_INLINE(pj_size_t) pj_strlen( const pj_str_t *str ) -{ - return str->slen; -} - -/** - * Return the pointer to the string data. - * - * @param str The string. - * - * @return the pointer to the string buffer. - */ -PJ_INLINE(const char*) pj_strbuf( const pj_str_t *str ) -{ - return str->ptr; -} - -/** - * Compare strings. - * - * @param str1 The string to compare. - * @param str2 The string to compare. - * - * @return - * - < 0 if str1 is less than str2 - * - 0 if str1 is identical to str2 - * - > 0 if str1 is greater than str2 - */ -PJ_IDECL(int) pj_strcmp( const pj_str_t *str1, const pj_str_t *str2); - -/** - * Compare strings. - * - * @param str1 The string to compare. - * @param str2 The string to compare. - * - * @return - * - < 0 if str1 is less than str2 - * - 0 if str1 is identical to str2 - * - > 0 if str1 is greater than str2 - */ -PJ_IDECL(int) pj_strcmp2( const pj_str_t *str1, const char *str2 ); - -/** - * Compare strings. - * - * @param str1 The string to compare. - * @param str2 The string to compare. - * @param len The maximum number of characters to compare. - * - * @return - * - < 0 if str1 is less than str2 - * - 0 if str1 is identical to str2 - * - > 0 if str1 is greater than str2 - */ -PJ_IDECL(int) pj_strncmp( const pj_str_t *str1, const pj_str_t *str2, - pj_size_t len); - -/** - * Compare strings. - * - * @param str1 The string to compare. - * @param str2 The string to compare. - * @param len The maximum number of characters to compare. - * - * @return - * - < 0 if str1 is less than str2 - * - 0 if str1 is identical to str2 - * - > 0 if str1 is greater than str2 - */ -PJ_IDECL(int) pj_strncmp2( const pj_str_t *str1, const char *str2, - pj_size_t len); - -/** - * Perform lowercase comparison to the strings. - * - * @param str1 The string to compare. - * @param str2 The string to compare. - * - * @return - * - < 0 if str1 is less than str2 - * - 0 if str1 is identical to str2 - * - > 0 if str1 is greater than str2 - */ -PJ_IDECL(int) pj_stricmp( const pj_str_t *str1, const pj_str_t *str2); - -/** - * Perform lowercase comparison to the strings. - * - * @param str1 The string to compare. - * @param str2 The string to compare. - * - * @return - * - < 0 if str1 is less than str2 - * - 0 if str1 is identical to str2 - * - > 0 if str1 is greater than str2 - */ -PJ_IDECL(int) pj_stricmp2( const pj_str_t *str1, const char *str2); - -/** - * Perform lowercase comparison to the strings. - * - * @param str1 The string to compare. - * @param str2 The string to compare. - * @param len The maximum number of characters to compare. - * - * @return - * - < 0 if str1 is less than str2 - * - 0 if str1 is identical to str2 - * - > 0 if str1 is greater than str2 - */ -PJ_IDECL(int) pj_strnicmp( const pj_str_t *str1, const pj_str_t *str2, - pj_size_t len); - -/** - * Perform lowercase comparison to the strings. - * - * @param str1 The string to compare. - * @param str2 The string to compare. - * @param len The maximum number of characters to compare. - * - * @return - * - < 0 if str1 is less than str2 - * - 0 if str1 is identical to str2 - * - > 0 if str1 is greater than str2 - */ -PJ_IDECL(int) pj_strnicmp2( const pj_str_t *str1, const char *str2, - pj_size_t len); - -/** - * Concatenate strings. - * - * @param dst The destination string. - * @param src The source string. - */ -PJ_IDECL(void) pj_strcat(pj_str_t *dst, const pj_str_t *src); - -/** - * Finds a character in a string. - * - * @param str The string. - * @param chr The character to find. - * - * @return the pointer to first character found, or NULL. - */ -PJ_INLINE(char*) pj_strchr( pj_str_t *str, int chr) -{ - return (char*) memchr(str->ptr, chr, str->slen); -} - -/** - * Remove (trim) leading whitespaces from the string. - * - * @param str The string. - * - * @return the string. - */ -PJ_DECL(pj_str_t*) pj_strltrim( pj_str_t *str ); - -/** - * Remove (trim) the trailing whitespaces from the string. - * - * @param str The string. - * - * @return the string. - */ -PJ_DECL(pj_str_t*) pj_strrtrim( pj_str_t *str ); - -/** - * Remove (trim) leading and trailing whitespaces from the string. - * - * @param str The string. - * - * @return the string. - */ -PJ_IDECL(pj_str_t*) pj_strtrim( pj_str_t *str ); - -/** - * Initialize the buffer with some random string. - * - * @param str the string to store the result. - * @param length the length of the random string to generate. - * - * @return the string. - */ -PJ_DECL(char*) pj_create_random_string(char *str, pj_size_t length); - -/** - * Convert string to unsigned integer. - * - * @param str the string. - * - * @return the unsigned integer. - */ -PJ_DECL(unsigned long) pj_strtoul(const pj_str_t *str); - -/** - * Utility to convert unsigned integer to string. Note that the - * string will be NULL terminated. - * - * @param val the unsigned integer value. - * @param buf the buffer - * - * @return the number of characters written - */ -PJ_DECL(int) pj_utoa(unsigned long val, char *buf); - -/** - * Convert unsigned integer to string with minimum digits. Note that the - * string will be NULL terminated. - * - * @param val The unsigned integer value. - * @param buf The buffer. - * @param min_dig Minimum digits to be printed, or zero to specify no - * minimum digit. - * @param pad The padding character to be put in front of the string - * when the digits is less than minimum. - * - * @return the number of characters written. - */ -PJ_DECL(int) pj_utoa_pad( unsigned long val, char *buf, int min_dig, int pad); - -/** - * Fill the memory location with value. - * - * @param dst The destination buffer. - * @param c Character to set. - * @param size The number of characters. - * - * @return the value of dst. - */ -PJ_INLINE(void*) pj_memset(void *dst, int c, pj_size_t size) -{ - return memset(dst, c, size); -} - -/** - * Copy buffer. - * - * @param dst The destination buffer. - * @param src The source buffer. - * @param size The size to copy. - * - * @return the destination buffer. - */ -PJ_INLINE(void*) pj_memcpy(void *dst, const void *src, pj_size_t size) -{ - return memcpy(dst, src, size); -} - -/** - * Move memory. - * - * @param dst The destination buffer. - * @param src The source buffer. - * @param size The size to copy. - * - * @return the destination buffer. - */ -PJ_INLINE(void*) pj_memmove(void *dst, const void *src, pj_size_t size) -{ - return memmove(dst, src, size); -} - -/** - * Compare buffers. - * - * @param buf1 The first buffer. - * @param buf2 The second buffer. - * @param size The size to compare. - * - * @return negative, zero, or positive value. - */ -PJ_INLINE(int) pj_memcmp(const void *buf1, const void *buf2, pj_size_t size) -{ - return memcmp(buf1, buf2, size); -} - -/** - * Find character in the buffer. - * - * @param buf The buffer. - * @param c The character to find. - * @param size The size to check. - * - * @return the pointer to location where the character is found, or NULL if - * not found. - */ -PJ_INLINE(void*) pj_memchr(const void *buf, int c, pj_size_t size) -{ - return memchr(buf, c, size); -} - -/** - * @} - */ - -#if PJ_FUNCTIONS_ARE_INLINED -# include <pj/string_i.h> -#endif - -PJ_END_DECL - -#endif /* __PJ_STRING_H__ */ - +
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup PJ_PSTR String Operations
+ * @ingroup PJ_DS
+ * @{
+ * This module provides string manipulation API.
+ *
+ * \section pj_pstr_not_null_sec PJLIB String is NOT Null Terminated!
+ *
+ * That is the first information that developers need to know. Instead
+ * of using normal C string, strings in PJLIB are represented as
+ * pj_str_t structure below:
+ *
+ * <pre>
+ * typedef struct pj_str_t
+ * {
+ * char *ptr;
+ * pj_size_t slen;
+ * } pj_str_t;
+ * </pre>
+ *
+ * There are some advantages of using this approach:
+ * - the string can point to arbitrary location in memory even
+ * if the string in that location is not null terminated. This is
+ * most usefull for text parsing, where the parsed text can just
+ * point to the original text in the input. If we use C string,
+ * then we will have to copy the text portion from the input
+ * to a string variable.
+ * - because the length of the string is known, string copy operation
+ * can be made more efficient.
+ *
+ * Most of APIs in PJLIB that expect or return string will represent
+ * the string as pj_str_t instead of normal C string.
+ *
+ * \section pj_pstr_examples_sec Examples
+ *
+ * For some examples, please see:
+ * - @ref page_pjlib_string_test
+ */
+
+/**
+ * Create string initializer from a normal C string.
+ *
+ * @param str Null terminated string to be stored.
+ *
+ * @return pj_str_t.
+ */
+PJ_IDECL(pj_str_t) pj_str(char *str);
+
+/**
+ * Create constant string from normal C string.
+ *
+ * @param str The string to be initialized.
+ * @param s Null terminated string.
+ *
+ * @return pj_str_t.
+ */
+PJ_INLINE(const pj_str_t*) pj_cstr(pj_str_t *str, const char *s)
+{
+ str->ptr = (char*)s;
+ str->slen = s ? strlen(s) : 0;
+ return str;
+}
+
+/**
+ * Set the pointer and length to the specified value.
+ *
+ * @param str the string.
+ * @param ptr pointer to set.
+ * @param length length to set.
+ *
+ * @return the string.
+ */
+PJ_INLINE(pj_str_t*) pj_strset( pj_str_t *str, char *ptr, pj_size_t length)
+{
+ str->ptr = ptr;
+ str->slen = length;
+ return str;
+}
+
+/**
+ * Set the pointer and length of the string to the source string, which
+ * must be NULL terminated.
+ *
+ * @param str the string.
+ * @param src pointer to set.
+ *
+ * @return the string.
+ */
+PJ_INLINE(pj_str_t*) pj_strset2( pj_str_t *str, char *src)
+{
+ str->ptr = src;
+ str->slen = src ? strlen(src) : 0;
+ return str;
+}
+
+/**
+ * Set the pointer and the length of the string.
+ *
+ * @param str The target string.
+ * @param begin The start of the string.
+ * @param end The end of the string.
+ *
+ * @return the target string.
+ */
+PJ_INLINE(pj_str_t*) pj_strset3( pj_str_t *str, char *begin, char *end )
+{
+ str->ptr = begin;
+ str->slen = end-begin;
+ return str;
+}
+
+/**
+ * Assign string.
+ *
+ * @param dst The target string.
+ * @param src The source string.
+ *
+ * @return the target string.
+ */
+PJ_IDECL(pj_str_t*) pj_strassign( pj_str_t *dst, pj_str_t *src );
+
+/**
+ * Copy string contents.
+ *
+ * @param dst The target string.
+ * @param src The source string.
+ *
+ * @return the target string.
+ */
+PJ_IDECL(pj_str_t*) pj_strcpy(pj_str_t *dst, const pj_str_t *src);
+
+/**
+ * Copy string contents.
+ *
+ * @param dst The target string.
+ * @param src The source string.
+ *
+ * @return the target string.
+ */
+PJ_IDECL(pj_str_t*) pj_strcpy2(pj_str_t *dst, const char *src);
+
+/**
+ * Duplicate string.
+ *
+ * @param pool The pool.
+ * @param dst The string result.
+ * @param src The string to duplicate.
+ *
+ * @return the string result.
+ */
+PJ_IDECL(pj_str_t*) pj_strdup(pj_pool_t *pool,
+ pj_str_t *dst,
+ const pj_str_t *src);
+
+/**
+ * Duplicate string and NULL terminate the destination string.
+ *
+ * @param pool
+ * @param dst
+ * @param src
+ */
+PJ_IDECL(pj_str_t*) pj_strdup_with_null(pj_pool_t *pool,
+ pj_str_t *dst,
+ const pj_str_t *src);
+
+/**
+ * Duplicate string.
+ *
+ * @param pool The pool.
+ * @param dst The string result.
+ * @param src The string to duplicate.
+ *
+ * @return the string result.
+ */
+PJ_IDECL(pj_str_t*) pj_strdup2(pj_pool_t *pool,
+ pj_str_t *dst,
+ const char *src);
+
+/**
+ * Duplicate string.
+ *
+ * @param pool The pool.
+ * @param src The string to duplicate.
+ *
+ * @return the string result.
+ */
+PJ_IDECL(pj_str_t) pj_strdup3(pj_pool_t *pool, const char *src);
+
+/**
+ * Return the length of the string.
+ *
+ * @param str The string.
+ *
+ * @return the length of the string.
+ */
+PJ_INLINE(pj_size_t) pj_strlen( const pj_str_t *str )
+{
+ return str->slen;
+}
+
+/**
+ * Return the pointer to the string data.
+ *
+ * @param str The string.
+ *
+ * @return the pointer to the string buffer.
+ */
+PJ_INLINE(const char*) pj_strbuf( const pj_str_t *str )
+{
+ return str->ptr;
+}
+
+/**
+ * Compare strings.
+ *
+ * @param str1 The string to compare.
+ * @param str2 The string to compare.
+ *
+ * @return
+ * - < 0 if str1 is less than str2
+ * - 0 if str1 is identical to str2
+ * - > 0 if str1 is greater than str2
+ */
+PJ_IDECL(int) pj_strcmp( const pj_str_t *str1, const pj_str_t *str2);
+
+/**
+ * Compare strings.
+ *
+ * @param str1 The string to compare.
+ * @param str2 The string to compare.
+ *
+ * @return
+ * - < 0 if str1 is less than str2
+ * - 0 if str1 is identical to str2
+ * - > 0 if str1 is greater than str2
+ */
+PJ_IDECL(int) pj_strcmp2( const pj_str_t *str1, const char *str2 );
+
+/**
+ * Compare strings.
+ *
+ * @param str1 The string to compare.
+ * @param str2 The string to compare.
+ * @param len The maximum number of characters to compare.
+ *
+ * @return
+ * - < 0 if str1 is less than str2
+ * - 0 if str1 is identical to str2
+ * - > 0 if str1 is greater than str2
+ */
+PJ_IDECL(int) pj_strncmp( const pj_str_t *str1, const pj_str_t *str2,
+ pj_size_t len);
+
+/**
+ * Compare strings.
+ *
+ * @param str1 The string to compare.
+ * @param str2 The string to compare.
+ * @param len The maximum number of characters to compare.
+ *
+ * @return
+ * - < 0 if str1 is less than str2
+ * - 0 if str1 is identical to str2
+ * - > 0 if str1 is greater than str2
+ */
+PJ_IDECL(int) pj_strncmp2( const pj_str_t *str1, const char *str2,
+ pj_size_t len);
+
+/**
+ * Perform lowercase comparison to the strings.
+ *
+ * @param str1 The string to compare.
+ * @param str2 The string to compare.
+ *
+ * @return
+ * - < 0 if str1 is less than str2
+ * - 0 if str1 is identical to str2
+ * - > 0 if str1 is greater than str2
+ */
+PJ_IDECL(int) pj_stricmp( const pj_str_t *str1, const pj_str_t *str2);
+
+/**
+ * Perform lowercase comparison to the strings.
+ *
+ * @param str1 The string to compare.
+ * @param str2 The string to compare.
+ *
+ * @return
+ * - < 0 if str1 is less than str2
+ * - 0 if str1 is identical to str2
+ * - > 0 if str1 is greater than str2
+ */
+PJ_IDECL(int) pj_stricmp2( const pj_str_t *str1, const char *str2);
+
+/**
+ * Perform lowercase comparison to the strings.
+ *
+ * @param str1 The string to compare.
+ * @param str2 The string to compare.
+ * @param len The maximum number of characters to compare.
+ *
+ * @return
+ * - < 0 if str1 is less than str2
+ * - 0 if str1 is identical to str2
+ * - > 0 if str1 is greater than str2
+ */
+PJ_IDECL(int) pj_strnicmp( const pj_str_t *str1, const pj_str_t *str2,
+ pj_size_t len);
+
+/**
+ * Perform lowercase comparison to the strings.
+ *
+ * @param str1 The string to compare.
+ * @param str2 The string to compare.
+ * @param len The maximum number of characters to compare.
+ *
+ * @return
+ * - < 0 if str1 is less than str2
+ * - 0 if str1 is identical to str2
+ * - > 0 if str1 is greater than str2
+ */
+PJ_IDECL(int) pj_strnicmp2( const pj_str_t *str1, const char *str2,
+ pj_size_t len);
+
+/**
+ * Concatenate strings.
+ *
+ * @param dst The destination string.
+ * @param src The source string.
+ */
+PJ_IDECL(void) pj_strcat(pj_str_t *dst, const pj_str_t *src);
+
+/**
+ * Finds a character in a string.
+ *
+ * @param str The string.
+ * @param chr The character to find.
+ *
+ * @return the pointer to first character found, or NULL.
+ */
+PJ_INLINE(char*) pj_strchr( pj_str_t *str, int chr)
+{
+ return (char*) memchr(str->ptr, chr, str->slen);
+}
+
+/**
+ * Remove (trim) leading whitespaces from the string.
+ *
+ * @param str The string.
+ *
+ * @return the string.
+ */
+PJ_DECL(pj_str_t*) pj_strltrim( pj_str_t *str );
+
+/**
+ * Remove (trim) the trailing whitespaces from the string.
+ *
+ * @param str The string.
+ *
+ * @return the string.
+ */
+PJ_DECL(pj_str_t*) pj_strrtrim( pj_str_t *str );
+
+/**
+ * Remove (trim) leading and trailing whitespaces from the string.
+ *
+ * @param str The string.
+ *
+ * @return the string.
+ */
+PJ_IDECL(pj_str_t*) pj_strtrim( pj_str_t *str );
+
+/**
+ * Initialize the buffer with some random string.
+ *
+ * @param str the string to store the result.
+ * @param length the length of the random string to generate.
+ *
+ * @return the string.
+ */
+PJ_DECL(char*) pj_create_random_string(char *str, pj_size_t length);
+
+/**
+ * Convert string to unsigned integer.
+ *
+ * @param str the string.
+ *
+ * @return the unsigned integer.
+ */
+PJ_DECL(unsigned long) pj_strtoul(const pj_str_t *str);
+
+/**
+ * Utility to convert unsigned integer to string. Note that the
+ * string will be NULL terminated.
+ *
+ * @param val the unsigned integer value.
+ * @param buf the buffer
+ *
+ * @return the number of characters written
+ */
+PJ_DECL(int) pj_utoa(unsigned long val, char *buf);
+
+/**
+ * Convert unsigned integer to string with minimum digits. Note that the
+ * string will be NULL terminated.
+ *
+ * @param val The unsigned integer value.
+ * @param buf The buffer.
+ * @param min_dig Minimum digits to be printed, or zero to specify no
+ * minimum digit.
+ * @param pad The padding character to be put in front of the string
+ * when the digits is less than minimum.
+ *
+ * @return the number of characters written.
+ */
+PJ_DECL(int) pj_utoa_pad( unsigned long val, char *buf, int min_dig, int pad);
+
+/**
+ * Fill the memory location with value.
+ *
+ * @param dst The destination buffer.
+ * @param c Character to set.
+ * @param size The number of characters.
+ *
+ * @return the value of dst.
+ */
+PJ_INLINE(void*) pj_memset(void *dst, int c, pj_size_t size)
+{
+ return memset(dst, c, size);
+}
+
+/**
+ * Copy buffer.
+ *
+ * @param dst The destination buffer.
+ * @param src The source buffer.
+ * @param size The size to copy.
+ *
+ * @return the destination buffer.
+ */
+PJ_INLINE(void*) pj_memcpy(void *dst, const void *src, pj_size_t size)
+{
+ return memcpy(dst, src, size);
+}
+
+/**
+ * Move memory.
+ *
+ * @param dst The destination buffer.
+ * @param src The source buffer.
+ * @param size The size to copy.
+ *
+ * @return the destination buffer.
+ */
+PJ_INLINE(void*) pj_memmove(void *dst, const void *src, pj_size_t size)
+{
+ return memmove(dst, src, size);
+}
+
+/**
+ * Compare buffers.
+ *
+ * @param buf1 The first buffer.
+ * @param buf2 The second buffer.
+ * @param size The size to compare.
+ *
+ * @return negative, zero, or positive value.
+ */
+PJ_INLINE(int) pj_memcmp(const void *buf1, const void *buf2, pj_size_t size)
+{
+ return memcmp(buf1, buf2, size);
+}
+
+/**
+ * Find character in the buffer.
+ *
+ * @param buf The buffer.
+ * @param c The character to find.
+ * @param size The size to check.
+ *
+ * @return the pointer to location where the character is found, or NULL if
+ * not found.
+ */
+PJ_INLINE(void*) pj_memchr(const void *buf, int c, pj_size_t size)
+{
+ return memchr(buf, c, size);
+}
+
+/**
+ * @}
+ */
+
+#if PJ_FUNCTIONS_ARE_INLINED
+# include <pj/string_i.h>
+#endif
+
+PJ_END_DECL
+
+#endif /* __PJ_STRING_H__ */
+
diff --git a/pjlib/include/pj/string_i.h b/pjlib/include/pj/string_i.h index 46408b34..1d93c18d 100644 --- a/pjlib/include/pj/string_i.h +++ b/pjlib/include/pj/string_i.h @@ -1,164 +1,185 @@ -/* $Id$ - * - */ - -PJ_IDEF(pj_str_t) pj_str(char *str) -{ - pj_str_t dst; - dst.ptr = str; - dst.slen = str ? strlen(str) : 0; - return dst; -} - -PJ_IDEF(pj_str_t*) pj_strdup(pj_pool_t *pool, - pj_str_t *dst, - const pj_str_t *src) -{ - if (src->slen) { - dst->ptr = (char*)pj_pool_alloc(pool, src->slen); - pj_memcpy(dst->ptr, src->ptr, src->slen); - } - dst->slen = src->slen; - return dst; -} - -PJ_IDEF(pj_str_t*) pj_strdup_with_null( pj_pool_t *pool, - pj_str_t *dst, - const pj_str_t *src) -{ - if (src->slen) { - dst->ptr = (char*)pj_pool_alloc(pool, src->slen+1); - pj_memcpy(dst->ptr, src->ptr, src->slen); - } else { - dst->ptr = (char*)pj_pool_alloc(pool, 1); - } - dst->slen = src->slen; - dst->ptr[dst->slen] = '\0'; - return dst; -} - -PJ_IDEF(pj_str_t*) pj_strdup2(pj_pool_t *pool, - pj_str_t *dst, - const char *src) -{ - dst->slen = src ? strlen(src) : 0; - if (dst->slen) { - dst->ptr = (char*)pj_pool_alloc(pool, dst->slen); - pj_memcpy(dst->ptr, src, dst->slen); - } else { - dst->ptr = NULL; - } - return dst; -} - - -PJ_IDEF(pj_str_t) pj_strdup3(pj_pool_t *pool, const char *src) -{ - pj_str_t temp; - pj_strdup2(pool, &temp, src); - return temp; -} - -PJ_IDEF(pj_str_t*) pj_strassign( pj_str_t *dst, pj_str_t *src ) -{ - dst->ptr = src->ptr; - dst->slen = src->slen; - return dst; -} - -PJ_IDEF(pj_str_t*) pj_strcpy(pj_str_t *dst, const pj_str_t *src) -{ - dst->slen = src->slen; - if (src->slen > 0) - pj_memcpy(dst->ptr, src->ptr, src->slen); - return dst; -} - -PJ_IDEF(pj_str_t*) pj_strcpy2(pj_str_t *dst, const char *src) -{ - dst->slen = src ? strlen(src) : 0; - if (dst->slen > 0) - pj_memcpy(dst->ptr, src, dst->slen); - return dst; -} - -PJ_IDEF(int) pj_strcmp( const pj_str_t *str1, const pj_str_t *str2) -{ - pj_ssize_t diff; - - diff = str1->slen - str2->slen; - if (diff) { - return (int)diff; - } else if (str1->ptr) { - return strncmp(str1->ptr, str2->ptr, str1->slen); - } else { - return 0; - } -} - -PJ_IDEF(int) pj_strncmp( const pj_str_t *str1, const pj_str_t *str2, - pj_size_t len) -{ - return (str1->ptr && str2->ptr) ? strncmp(str1->ptr, str2->ptr, len) : - (str1->ptr == str2->ptr ? 0 : 1); -} - -PJ_IDEF(int) pj_strncmp2( const pj_str_t *str1, const char *str2, - pj_size_t len) -{ - return (str1->ptr && str2) ? strncmp(str1->ptr, str2, len) : - (str1->ptr==str2 ? 0 : 1); -} - -PJ_IDEF(int) pj_strcmp2( const pj_str_t *str1, const char *str2 ) -{ - return pj_strncmp2( str1, str2, str1->slen); -} - -PJ_IDEF(int) pj_stricmp( const pj_str_t *str1, const pj_str_t *str2) -{ - pj_ssize_t diff; - - diff = str1->slen - str2->slen; - if (diff) { - return (int)diff; - } else { - return strnicmp(str1->ptr, str2->ptr, str1->slen); - } -} - -PJ_IDEF(int) pj_stricmp2( const pj_str_t *str1, const char *str2) -{ - return (str1->ptr && str2) ? strnicmp(str1->ptr, str2, str1->slen) : - (str1->ptr==str2 ? 0 : 1); -} - -PJ_IDEF(int) pj_strnicmp( const pj_str_t *str1, const pj_str_t *str2, - pj_size_t len) -{ - return (str1->ptr && str2->ptr) ? strnicmp(str1->ptr, str2->ptr, len) : - (str1->ptr == str2->ptr ? 0 : 1); -} - -PJ_IDEF(int) pj_strnicmp2( const pj_str_t *str1, const char *str2, - pj_size_t len) -{ - return (str1->ptr && str2) ? strnicmp(str1->ptr, str2, len) : - (str1->ptr == str2 ? 0 : 1); -} - -PJ_IDEF(void) pj_strcat(pj_str_t *dst, const pj_str_t *src) -{ - if (src->slen) { - pj_memcpy(dst->ptr + dst->slen, src->ptr, src->slen); - dst->slen += src->slen; - } -} - -PJ_IDEF(pj_str_t*) pj_strtrim( pj_str_t *str ) -{ - pj_strltrim(str); - pj_strrtrim(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
+ */
+
+PJ_IDEF(pj_str_t) pj_str(char *str)
+{
+ pj_str_t dst;
+ dst.ptr = str;
+ dst.slen = str ? strlen(str) : 0;
+ return dst;
+}
+
+PJ_IDEF(pj_str_t*) pj_strdup(pj_pool_t *pool,
+ pj_str_t *dst,
+ const pj_str_t *src)
+{
+ if (src->slen) {
+ dst->ptr = (char*)pj_pool_alloc(pool, src->slen);
+ pj_memcpy(dst->ptr, src->ptr, src->slen);
+ }
+ dst->slen = src->slen;
+ return dst;
+}
+
+PJ_IDEF(pj_str_t*) pj_strdup_with_null( pj_pool_t *pool,
+ pj_str_t *dst,
+ const pj_str_t *src)
+{
+ if (src->slen) {
+ dst->ptr = (char*)pj_pool_alloc(pool, src->slen+1);
+ pj_memcpy(dst->ptr, src->ptr, src->slen);
+ } else {
+ dst->ptr = (char*)pj_pool_alloc(pool, 1);
+ }
+ dst->slen = src->slen;
+ dst->ptr[dst->slen] = '\0';
+ return dst;
+}
+
+PJ_IDEF(pj_str_t*) pj_strdup2(pj_pool_t *pool,
+ pj_str_t *dst,
+ const char *src)
+{
+ dst->slen = src ? strlen(src) : 0;
+ if (dst->slen) {
+ dst->ptr = (char*)pj_pool_alloc(pool, dst->slen);
+ pj_memcpy(dst->ptr, src, dst->slen);
+ } else {
+ dst->ptr = NULL;
+ }
+ return dst;
+}
+
+
+PJ_IDEF(pj_str_t) pj_strdup3(pj_pool_t *pool, const char *src)
+{
+ pj_str_t temp;
+ pj_strdup2(pool, &temp, src);
+ return temp;
+}
+
+PJ_IDEF(pj_str_t*) pj_strassign( pj_str_t *dst, pj_str_t *src )
+{
+ dst->ptr = src->ptr;
+ dst->slen = src->slen;
+ return dst;
+}
+
+PJ_IDEF(pj_str_t*) pj_strcpy(pj_str_t *dst, const pj_str_t *src)
+{
+ dst->slen = src->slen;
+ if (src->slen > 0)
+ pj_memcpy(dst->ptr, src->ptr, src->slen);
+ return dst;
+}
+
+PJ_IDEF(pj_str_t*) pj_strcpy2(pj_str_t *dst, const char *src)
+{
+ dst->slen = src ? strlen(src) : 0;
+ if (dst->slen > 0)
+ pj_memcpy(dst->ptr, src, dst->slen);
+ return dst;
+}
+
+PJ_IDEF(int) pj_strcmp( const pj_str_t *str1, const pj_str_t *str2)
+{
+ pj_ssize_t diff;
+
+ diff = str1->slen - str2->slen;
+ if (diff) {
+ return (int)diff;
+ } else if (str1->ptr) {
+ return strncmp(str1->ptr, str2->ptr, str1->slen);
+ } else {
+ return 0;
+ }
+}
+
+PJ_IDEF(int) pj_strncmp( const pj_str_t *str1, const pj_str_t *str2,
+ pj_size_t len)
+{
+ return (str1->ptr && str2->ptr) ? strncmp(str1->ptr, str2->ptr, len) :
+ (str1->ptr == str2->ptr ? 0 : 1);
+}
+
+PJ_IDEF(int) pj_strncmp2( const pj_str_t *str1, const char *str2,
+ pj_size_t len)
+{
+ return (str1->ptr && str2) ? strncmp(str1->ptr, str2, len) :
+ (str1->ptr==str2 ? 0 : 1);
+}
+
+PJ_IDEF(int) pj_strcmp2( const pj_str_t *str1, const char *str2 )
+{
+ return pj_strncmp2( str1, str2, str1->slen);
+}
+
+PJ_IDEF(int) pj_stricmp( const pj_str_t *str1, const pj_str_t *str2)
+{
+ pj_ssize_t diff;
+
+ diff = str1->slen - str2->slen;
+ if (diff) {
+ return (int)diff;
+ } else {
+ return strnicmp(str1->ptr, str2->ptr, str1->slen);
+ }
+}
+
+PJ_IDEF(int) pj_stricmp2( const pj_str_t *str1, const char *str2)
+{
+ return (str1->ptr && str2) ? strnicmp(str1->ptr, str2, str1->slen) :
+ (str1->ptr==str2 ? 0 : 1);
+}
+
+PJ_IDEF(int) pj_strnicmp( const pj_str_t *str1, const pj_str_t *str2,
+ pj_size_t len)
+{
+ return (str1->ptr && str2->ptr) ? strnicmp(str1->ptr, str2->ptr, len) :
+ (str1->ptr == str2->ptr ? 0 : 1);
+}
+
+PJ_IDEF(int) pj_strnicmp2( const pj_str_t *str1, const char *str2,
+ pj_size_t len)
+{
+ return (str1->ptr && str2) ? strnicmp(str1->ptr, str2, len) :
+ (str1->ptr == str2 ? 0 : 1);
+}
+
+PJ_IDEF(void) pj_strcat(pj_str_t *dst, const pj_str_t *src)
+{
+ if (src->slen) {
+ pj_memcpy(dst->ptr + dst->slen, src->ptr, src->slen);
+ dst->slen += src->slen;
+ }
+}
+
+PJ_IDEF(pj_str_t*) pj_strtrim( pj_str_t *str )
+{
+ pj_strltrim(str);
+ pj_strrtrim(str);
+ return str;
+}
+
diff --git a/pjlib/include/pj/timer.h b/pjlib/include/pj/timer.h index e8772f22..7ad5e4f2 100644 --- a/pjlib/include/pj/timer.h +++ b/pjlib/include/pj/timer.h @@ -1,140 +1,161 @@ -/* $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. - * - */ - -#ifndef __PJ_TIMER_H__ -#define __PJ_TIMER_H__ - -/** - * @file timer.h - * @brief Timer Heap - */ - -#include <pj/types.h> - -PJ_BEGIN_DECL - -/** - * @defgroup PJ_TIMER Timer Heap Management. - * @ingroup PJ_MISC - * @brief - * The timer scheduling implementation here is based on ACE library's - * ACE_Timer_Heap, with only little modification to suit our library's style - * (I even left most of the comments in the original source). - * - * To quote the original quote in ACE_Timer_Heap_T class: - * - * This implementation uses a heap-based callout queue of - * absolute times. Therefore, in the average and worst case, - * scheduling, canceling, and expiring timers is O(log N) (where - * N is the total number of timers). In addition, we can also - * preallocate as many \a ACE_Timer_Nodes as there are slots in - * the heap. This allows us to completely remove the need for - * dynamic memory allocation, which is important for real-time - * systems. - * @{ - * - * \section pj_timer_examples_sec Examples - * - * For some examples on how to use the timer heap, please see the link below. - * - * - \ref page_pjlib_timer_test - */ - - -/** - * The type for internal timer ID. - */ -typedef int pj_timer_id_t; - -/** - * Forward declaration for pj_timer_entry. - */ -struct pj_timer_entry; - -/** - * The type of callback function to be called by timer scheduler when a timer - * has expired. - * - * @param timer_heap The timer heap. - * @param entry Timer entry which timer's has expired. - */ -typedef void pj_timer_heap_callback(pj_timer_heap_t *timer_heap, - struct pj_timer_entry *entry); - - -/** - * This structure represents an entry to the timer. - */ -struct pj_timer_entry -{ - /** - * User data to be associated with this entry. - * Applications normally will put the instance of object that - * owns the timer entry in this field. - */ - void *user_data; - - /** - * Arbitrary ID assigned by the user/owner of this entry. - * Applications can use this ID to distinguish multiple - * timer entries that share the same callback and user_data. - */ - int id; - - /** - * Callback to be called when the timer expires. - */ - pj_timer_heap_callback *cb; - - /** - * Internal unique timer ID, which is assigned by the timer heap. - * Application should not touch this ID. - */ - pj_timer_id_t _timer_id; - - /** - * The future time when the timer expires, which the value is updated - * by timer heap when the timer is scheduled. - */ - pj_time_val _timer_value; -}; - - -/** - * Calculate memory size required to create a timer heap. - * - * @param count Number of timer entries to be supported. - * @return Memory size requirement in bytes. - */ -PJ_DECL(pj_size_t) pj_timer_heap_mem_size(pj_size_t count); - -/** - * Create a timer heap. - * - * @param pool The pool where allocations in the timer heap will be - * allocated. The timer heap will dynamicly allocate - * more storate from the pool if the number of timer - * entries registered is more than the size originally - * requested when calling this function. - * @param count The maximum number of timer entries to be supported - * initially. If the application registers more entries - * during runtime, then the timer heap will resize. - * @param ht Pointer to receive the created timer heap. - * - * @return PJ_SUCCESS, or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_timer_heap_create( pj_pool_t *pool, - pj_size_t count, - pj_timer_heap_t **ht); +/* $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.
+ *
+ */
+
+#ifndef __PJ_TIMER_H__
+#define __PJ_TIMER_H__
+
+/**
+ * @file timer.h
+ * @brief Timer Heap
+ */
+
+#include <pj/types.h>
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup PJ_TIMER Timer Heap Management.
+ * @ingroup PJ_MISC
+ * @brief
+ * The timer scheduling implementation here is based on ACE library's
+ * ACE_Timer_Heap, with only little modification to suit our library's style
+ * (I even left most of the comments in the original source).
+ *
+ * To quote the original quote in ACE_Timer_Heap_T class:
+ *
+ * This implementation uses a heap-based callout queue of
+ * absolute times. Therefore, in the average and worst case,
+ * scheduling, canceling, and expiring timers is O(log N) (where
+ * N is the total number of timers). In addition, we can also
+ * preallocate as many \a ACE_Timer_Nodes as there are slots in
+ * the heap. This allows us to completely remove the need for
+ * dynamic memory allocation, which is important for real-time
+ * systems.
+ * @{
+ *
+ * \section pj_timer_examples_sec Examples
+ *
+ * For some examples on how to use the timer heap, please see the link below.
+ *
+ * - \ref page_pjlib_timer_test
+ */
+
+
+/**
+ * The type for internal timer ID.
+ */
+typedef int pj_timer_id_t;
+
+/**
+ * Forward declaration for pj_timer_entry.
+ */
+struct pj_timer_entry;
+
+/**
+ * The type of callback function to be called by timer scheduler when a timer
+ * has expired.
+ *
+ * @param timer_heap The timer heap.
+ * @param entry Timer entry which timer's has expired.
+ */
+typedef void pj_timer_heap_callback(pj_timer_heap_t *timer_heap,
+ struct pj_timer_entry *entry);
+
+
+/**
+ * This structure represents an entry to the timer.
+ */
+struct pj_timer_entry
+{
+ /**
+ * User data to be associated with this entry.
+ * Applications normally will put the instance of object that
+ * owns the timer entry in this field.
+ */
+ void *user_data;
+
+ /**
+ * Arbitrary ID assigned by the user/owner of this entry.
+ * Applications can use this ID to distinguish multiple
+ * timer entries that share the same callback and user_data.
+ */
+ int id;
+
+ /**
+ * Callback to be called when the timer expires.
+ */
+ pj_timer_heap_callback *cb;
+
+ /**
+ * Internal unique timer ID, which is assigned by the timer heap.
+ * Application should not touch this ID.
+ */
+ pj_timer_id_t _timer_id;
+
+ /**
+ * The future time when the timer expires, which the value is updated
+ * by timer heap when the timer is scheduled.
+ */
+ pj_time_val _timer_value;
+};
+
+
+/**
+ * Calculate memory size required to create a timer heap.
+ *
+ * @param count Number of timer entries to be supported.
+ * @return Memory size requirement in bytes.
+ */
+PJ_DECL(pj_size_t) pj_timer_heap_mem_size(pj_size_t count);
+
+/**
+ * Create a timer heap.
+ *
+ * @param pool The pool where allocations in the timer heap will be
+ * allocated. The timer heap will dynamicly allocate
+ * more storate from the pool if the number of timer
+ * entries registered is more than the size originally
+ * requested when calling this function.
+ * @param count The maximum number of timer entries to be supported
+ * initially. If the application registers more entries
+ * during runtime, then the timer heap will resize.
+ * @param ht Pointer to receive the created timer heap.
+ *
+ * @return PJ_SUCCESS, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_timer_heap_create( pj_pool_t *pool,
+ pj_size_t count,
+ pj_timer_heap_t **ht);
/**
* Destroy the timer heap.
@@ -167,92 +188,92 @@ PJ_DECL(void) pj_timer_heap_set_lock( pj_timer_heap_t *ht, */
PJ_DECL(unsigned) pj_timer_heap_set_max_timed_out_per_poll(pj_timer_heap_t *ht,
unsigned count );
- -/** - * Initialize a timer entry. Application should call this function at least - * once before scheduling the entry to the timer heap, to properly initialize - * the timer entry. - * - * @param entry The timer entry to be initialized. - * @param id Arbitrary ID assigned by the user/owner of this entry. - * Applications can use this ID to distinguish multiple - * timer entries that share the same callback and user_data. - * @param user_data User data to be associated with this entry. - * Applications normally will put the instance of object that - * owns the timer entry in this field. - * @param cb Callback function to be called when the timer elapses. - * - * @return The timer entry itself. - */ -PJ_DECL(pj_timer_entry*) pj_timer_entry_init( pj_timer_entry *entry, - int id, - void *user_data, - pj_timer_heap_callback *cb ); - -/** - * Schedule a timer entry which will expire AFTER the specified delay. - * - * @param ht The timer heap. - * @param entry The entry to be registered. - * @param delay The interval to expire. - * @return PJ_SUCCESS, or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_timer_heap_schedule( pj_timer_heap_t *ht, - pj_timer_entry *entry, - const pj_time_val *delay); - -/** - * Cancel a previously registered timer. - * - * @param ht The timer heap. - * @param entry The entry to be cancelled. - * @return The number of timer cancelled, which should be one if the - * entry has really been registered, or zero if no timer was - * cancelled. - */ -PJ_DECL(int) pj_timer_heap_cancel( pj_timer_heap_t *ht, - pj_timer_entry *entry); - -/** - * Get the number of timer entries. - * - * @param ht The timer heap. - * @return The number of timer entries. - */ -PJ_DECL(pj_size_t) pj_timer_heap_count( pj_timer_heap_t *ht ); - -/** - * Get the earliest time registered in the timer heap. The timer heap - * MUST have at least one timer being scheduled (application should use - * #pj_timer_heap_count() before calling this function). - * - * @param ht The timer heap. - * @param timeval The time deadline of the earliest timer entry. - * - * @return PJ_SUCCESS, or PJ_ENOTFOUND if no entry is scheduled. - */ -PJ_DECL(pj_status_t) pj_timer_heap_earliest_time( pj_timer_heap_t *ht, - pj_time_val *timeval); - -/** - * Poll the timer heap, check for expired timers and call the callback for - * each of the expired timers. - * - * @param ht The timer heap. - * @param next_delay If this parameter is not NULL, it will be filled up with - * the time delay until the next timer elapsed, or -1 in +
+/**
+ * Initialize a timer entry. Application should call this function at least
+ * once before scheduling the entry to the timer heap, to properly initialize
+ * the timer entry.
+ *
+ * @param entry The timer entry to be initialized.
+ * @param id Arbitrary ID assigned by the user/owner of this entry.
+ * Applications can use this ID to distinguish multiple
+ * timer entries that share the same callback and user_data.
+ * @param user_data User data to be associated with this entry.
+ * Applications normally will put the instance of object that
+ * owns the timer entry in this field.
+ * @param cb Callback function to be called when the timer elapses.
+ *
+ * @return The timer entry itself.
+ */
+PJ_DECL(pj_timer_entry*) pj_timer_entry_init( pj_timer_entry *entry,
+ int id,
+ void *user_data,
+ pj_timer_heap_callback *cb );
+
+/**
+ * Schedule a timer entry which will expire AFTER the specified delay.
+ *
+ * @param ht The timer heap.
+ * @param entry The entry to be registered.
+ * @param delay The interval to expire.
+ * @return PJ_SUCCESS, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_timer_heap_schedule( pj_timer_heap_t *ht,
+ pj_timer_entry *entry,
+ const pj_time_val *delay);
+
+/**
+ * Cancel a previously registered timer.
+ *
+ * @param ht The timer heap.
+ * @param entry The entry to be cancelled.
+ * @return The number of timer cancelled, which should be one if the
+ * entry has really been registered, or zero if no timer was
+ * cancelled.
+ */
+PJ_DECL(int) pj_timer_heap_cancel( pj_timer_heap_t *ht,
+ pj_timer_entry *entry);
+
+/**
+ * Get the number of timer entries.
+ *
+ * @param ht The timer heap.
+ * @return The number of timer entries.
+ */
+PJ_DECL(pj_size_t) pj_timer_heap_count( pj_timer_heap_t *ht );
+
+/**
+ * Get the earliest time registered in the timer heap. The timer heap
+ * MUST have at least one timer being scheduled (application should use
+ * #pj_timer_heap_count() before calling this function).
+ *
+ * @param ht The timer heap.
+ * @param timeval The time deadline of the earliest timer entry.
+ *
+ * @return PJ_SUCCESS, or PJ_ENOTFOUND if no entry is scheduled.
+ */
+PJ_DECL(pj_status_t) pj_timer_heap_earliest_time( pj_timer_heap_t *ht,
+ pj_time_val *timeval);
+
+/**
+ * Poll the timer heap, check for expired timers and call the callback for
+ * each of the expired timers.
+ *
+ * @param ht The timer heap.
+ * @param next_delay If this parameter is not NULL, it will be filled up with
+ * the time delay until the next timer elapsed, or -1 in
* the sec part if no entry exist.
- * - * @return The number of timers expired. - */ + *
+ * @return The number of timers expired.
+ */
PJ_DECL(unsigned) pj_timer_heap_poll( pj_timer_heap_t *ht,
- pj_time_val *next_delay); - -/** - * @} - */ - -PJ_END_DECL - -#endif /* __PJ_TIMER_H__ */ - + pj_time_val *next_delay);
+
+/**
+ * @}
+ */
+
+PJ_END_DECL
+
+#endif /* __PJ_TIMER_H__ */
+
diff --git a/pjlib/include/pj/types.h b/pjlib/include/pj/types.h index ec3df2c1..acdfbd28 100644 --- a/pjlib/include/pj/types.h +++ b/pjlib/include/pj/types.h @@ -1,68 +1,87 @@ -/* $Id$ - * - */ - -#ifndef __PJ_TYPES_H__ -#define __PJ_TYPES_H__ - - -/** - * @defgroup PJ PJ Library - */ -/** - * @file types.h - * @brief Declaration of basic types and utility. - */ -/** - * @defgroup PJ_BASIC Basic Data Types and Library Functionality. - * @ingroup PJ_DS - * @{ - */ -#include <pj/config.h> - -PJ_BEGIN_DECL - -/////////////////////////////////////////////////////////////////////////////// - -/** Unsigned 32bit integer. */ -typedef int pj_int32_t; - -/** Signed 32bit integer. */ -typedef unsigned int pj_uint32_t; - -/** Unsigned 16bit integer. */ -typedef short pj_int16_t; - -/** Signed 16bit integer. */ -typedef unsigned short pj_uint16_t; - -/** Unsigned 8bit integer. */ -typedef signed char pj_int8_t; - -/** Signed 16bit integer. */ -typedef unsigned char pj_uint8_t; - -/** Large unsigned integer. */ -typedef size_t pj_size_t; - -/** Large signed integer. */ -typedef long pj_ssize_t; - -/** Status code. */ -typedef int pj_status_t; - -/** Boolean. */ -typedef int pj_bool_t; - -/** Status is OK. */ -#define PJ_SUCCESS 0 - -/** True value. */ -#define PJ_TRUE 1 - -/** False value. */ -#define PJ_FALSE 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
+ */
+
+#ifndef __PJ_TYPES_H__
+#define __PJ_TYPES_H__
+
+
+/**
+ * @defgroup PJ PJ Library
+ */
+/**
+ * @file types.h
+ * @brief Declaration of basic types and utility.
+ */
+/**
+ * @defgroup PJ_BASIC Basic Data Types and Library Functionality.
+ * @ingroup PJ_DS
+ * @{
+ */
+#include <pj/config.h>
+
+PJ_BEGIN_DECL
+
+///////////////////////////////////////////////////////////////////////////////
+
+/** Unsigned 32bit integer. */
+typedef int pj_int32_t;
+
+/** Signed 32bit integer. */
+typedef unsigned int pj_uint32_t;
+
+/** Unsigned 16bit integer. */
+typedef short pj_int16_t;
+
+/** Signed 16bit integer. */
+typedef unsigned short pj_uint16_t;
+
+/** Unsigned 8bit integer. */
+typedef signed char pj_int8_t;
+
+/** Signed 16bit integer. */
+typedef unsigned char pj_uint8_t;
+
+/** Large unsigned integer. */
+typedef size_t pj_size_t;
+
+/** Large signed integer. */
+typedef long pj_ssize_t;
+
+/** Status code. */
+typedef int pj_status_t;
+
+/** Boolean. */
+typedef int pj_bool_t;
+
+/** Status is OK. */
+#define PJ_SUCCESS 0
+
+/** True value. */
+#define PJ_TRUE 1
+
+/** False value. */
+#define PJ_FALSE 0
+
/**
* File offset type.
*/
@@ -71,358 +90,358 @@ typedef pj_int64_t pj_off_t; #else
typedef pj_ssize_t pj_off_t;
#endif
- -/////////////////////////////////////////////////////////////////////////////// -/* - * Data structure types. - */ -/** - * This type is used as replacement to legacy C string, and used throughout - * the library. By convention, the string is NOT null terminated. - */ -struct pj_str_t -{ - /** Buffer pointer, which is by convention NOT null terminated. */ - char *ptr; - - /** The length of the string. */ - pj_ssize_t slen; -}; - - -/** - * The opaque data type for linked list, which is used as arguments throughout - * the linked list operations. - */ -typedef void pj_list_type; - -/** - * List. - */ -typedef struct pj_list pj_list; - -/** - * Opaque data type for hash tables. - */ -typedef struct pj_hash_table_t pj_hash_table_t; - -/** - * Opaque data type for hash entry (only used internally by hash table). - */ -typedef struct pj_hash_entry pj_hash_entry; - -/** - * Data type for hash search iterator. - * This structure should be opaque, however applications need to declare - * concrete variable of this type, that's why the declaration is visible here. - */ -typedef struct pj_hash_iterator_t -{ - pj_uint32_t index; /**< Internal index. */ - pj_hash_entry *entry; /**< Internal entry. */ -} pj_hash_iterator_t; - - -/** - * Forward declaration for memory pool factory. - */ -typedef struct pj_pool_factory pj_pool_factory; - -/** - * Opaque data type for memory pool. - */ -typedef struct pj_pool_t pj_pool_t; - -/** - * Forward declaration for caching pool, a pool factory implementation. - */ -typedef struct pj_caching_pool pj_caching_pool; - -/** - * This type is used as replacement to legacy C string, and used throughout - * the library. - */ -typedef struct pj_str_t pj_str_t; - -/** - * Opaque data type for I/O Queue structure. - */ -typedef struct pj_ioqueue_t pj_ioqueue_t; - -/** - * Opaque data type for key that identifies a handle registered to the - * I/O queue framework. - */ -typedef struct pj_ioqueue_key_t pj_ioqueue_key_t; - -/** - * Opaque data to identify timer heap. - */ -typedef struct pj_timer_heap_t pj_timer_heap_t; - -/** - * Forward declaration for timer entry. - */ -typedef struct pj_timer_entry pj_timer_entry; - -/** - * Opaque data type for atomic operations. - */ -typedef struct pj_atomic_t pj_atomic_t; - -/** - * Value type of an atomic variable. - */ -typedef PJ_ATOMIC_VALUE_TYPE pj_atomic_value_t; - -/////////////////////////////////////////////////////////////////////////////// - -/** Thread handle. */ -typedef struct pj_thread_t pj_thread_t; - -/** Lock object. */ -typedef struct pj_lock_t pj_lock_t; - -/** Mutex handle. */ -typedef struct pj_mutex_t pj_mutex_t; - -/** Semaphore handle. */ -typedef struct pj_sem_t pj_sem_t; - -/** Event object. */ -typedef struct pj_event_t pj_event_t; - -/** Unidirectional stream pipe object. */ -typedef struct pj_pipe_t pj_pipe_t; - -/** Operating system handle. */ -typedef void *pj_oshandle_t; - -/** Socket handle. */ -typedef long pj_sock_t; - -/** Generic socket address. */ -typedef void pj_sockaddr_t; - -/** Color type. */ -typedef unsigned int pj_color_t; - -/** Exception id. */ -typedef int pj_exception_id_t; - -/////////////////////////////////////////////////////////////////////////////// - -/** Utility macro to compute the number of elements in static array. */ -#define PJ_ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) - -/** Maximum value for signed 32-bit integer. */ -#define PJ_MAXINT32 0x7FFFFFFFL - -/** - * Length of object names. - */ -#define PJ_MAX_OBJ_NAME 16 - -/////////////////////////////////////////////////////////////////////////////// -/* - * General. - */ -/** - * Initialize the PJ Library. - * This function must be called before using the library. The purpose of this - * function is to initialize static library data, such as character table used - * in random string generation, and to initialize operating system dependent - * functionality (such as WSAStartup() in Windows). - */ -PJ_DECL(pj_status_t) pj_init(void); - - -/** - * @} - */ -/** - * @addtogroup PJ_TIME Time Data Type and Manipulation. - * @ingroup PJ_MISC - * @{ - */ - -/** - * Representation of time value in this library. - * This type can be used to represent either an interval or a specific time - * or date. - */ -typedef struct pj_time_val -{ - /** The seconds part of the time. */ - long sec; - - /** The miliseconds fraction of the time. */ - long msec; - -} pj_time_val; - -/** - * Normalize the value in time value. - * @param t Time value to be normalized. - */ -PJ_DECL(void) pj_time_val_normalize(pj_time_val *t); - -/** - * Get the total time value in miliseconds. This is the same as - * multiplying the second part with 1000 and then add the miliseconds - * part to the result. - * - * @param t The time value. - * @return Total time in miliseconds. - * @hideinitializer - */ -#define PJ_TIME_VAL_MSEC(t) ((t).sec * 1000 + (t).msec) - -/** - * This macro will check if \a t1 is equal to \a t2. - * - * @param t1 The first time value to compare. - * @param t2 The second time value to compare. - * @return Non-zero if both time values are equal. - * @hideinitializer - */ -#define PJ_TIME_VAL_EQ(t1, t2) ((t1).sec==(t2).sec && (t1).msec==(t2).msec) - -/** - * This macro will check if \a t1 is greater than \a t2 - * - * @param t1 The first time value to compare. - * @param t2 The second time value to compare. - * @return Non-zero if t1 is greater than t2. - * @hideinitializer - */ -#define PJ_TIME_VAL_GT(t1, t2) ((t1).sec>(t2).sec || \ - ((t1).sec==(t2).sec && (t1).msec>(t2).msec)) - -/** - * This macro will check if \a t1 is greater than or equal to \a t2 - * - * @param t1 The first time value to compare. - * @param t2 The second time value to compare. - * @return Non-zero if t1 is greater than or equal to t2. - * @hideinitializer - */ -#define PJ_TIME_VAL_GTE(t1, t2) (PJ_TIME_VAL_GT(t1,t2) || \ - PJ_TIME_VAL_EQ(t1,t2)) - -/** - * This macro will check if \a t1 is less than \a t2 - * - * @param t1 The first time value to compare. - * @param t2 The second time value to compare. - * @return Non-zero if t1 is less than t2. - * @hideinitializer - */ -#define PJ_TIME_VAL_LT(t1, t2) (!(PJ_TIME_VAL_GTE(t1,t2))) - -/** - * This macro will check if \a t1 is less than or equal to \a t2. - * - * @param t1 The first time value to compare. - * @param t2 The second time value to compare. - * @return Non-zero if t1 is less than or equal to t2. - * @hideinitializer - */ -#define PJ_TIME_VAL_LTE(t1, t2) (!PJ_TIME_VAL_GT(t1, t2)) - -/** - * Add \a t2 to \a t1 and store the result in \a t1. Effectively - * - * this macro will expand as: (\a t1 += \a t2). - * @param t1 The time value to add. - * @param t2 The time value to be added to \a t1. - * @hideinitializer - */ -#define PJ_TIME_VAL_ADD(t1, t2) do { \ - (t1).sec += (t2).sec; \ - (t1).msec += (t2).msec; \ - pj_time_val_normalize(&(t1)); \ - } while (0) - - -/** - * Substract \a t2 from \a t1 and store the result in \a t1. Effectively - * this macro will expand as (\a t1 -= \a t2). - * - * @param t1 The time value to subsctract. - * @param t2 The time value to be substracted from \a t1. - * @hideinitializer - */ -#define PJ_TIME_VAL_SUB(t1, t2) do { \ - (t1).sec -= (t2).sec; \ - (t1).msec -= (t2).msec; \ - pj_time_val_normalize(&(t1)); \ - } while (0) - - -/** - * This structure represent the parsed representation of time. - * It is acquired by calling #pj_time_decode(). - */ -typedef struct pj_parsed_time -{ - /** This represents day of week where value zero means Sunday */ - int wday; - - /** This represents day of the year, 0-365, where zero means - * 1st of January. - */ - int yday; - - /** This represents day of month: 1-31 */ - int day; - - /** This represents month, with the value is 0 - 11 (zero is January) */ - int mon; - - /** This represent the actual year (unlike in ANSI libc where - * the value must be added by 1900). - */ - int year; - - /** This represents the second part, with the value is 0-59 */ - int sec; - - /** This represents the minute part, with the value is: 0-59 */ - int min; - - /** This represents the hour part, with the value is 0-23 */ - int hour; - - /** This represents the milisecond part, with the value is 0-999 */ - int msec; - -} pj_parsed_time; - - -/** - * @} // Time Management - */ - -/////////////////////////////////////////////////////////////////////////////// -/* - * Terminal. - */ -/** - * Color code combination. - */ -enum { - PJ_TERM_COLOR_R = 2, /**< Red */ - PJ_TERM_COLOR_G = 4, /**< Green */ - PJ_TERM_COLOR_B = 1, /**< Blue. */ - PJ_TERM_COLOR_BRIGHT = 8 /**< Bright mask. */ -}; - - - - -PJ_END_DECL - - -#endif /* __PJ_TYPES_H__ */ - +
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * Data structure types.
+ */
+/**
+ * This type is used as replacement to legacy C string, and used throughout
+ * the library. By convention, the string is NOT null terminated.
+ */
+struct pj_str_t
+{
+ /** Buffer pointer, which is by convention NOT null terminated. */
+ char *ptr;
+
+ /** The length of the string. */
+ pj_ssize_t slen;
+};
+
+
+/**
+ * The opaque data type for linked list, which is used as arguments throughout
+ * the linked list operations.
+ */
+typedef void pj_list_type;
+
+/**
+ * List.
+ */
+typedef struct pj_list pj_list;
+
+/**
+ * Opaque data type for hash tables.
+ */
+typedef struct pj_hash_table_t pj_hash_table_t;
+
+/**
+ * Opaque data type for hash entry (only used internally by hash table).
+ */
+typedef struct pj_hash_entry pj_hash_entry;
+
+/**
+ * Data type for hash search iterator.
+ * This structure should be opaque, however applications need to declare
+ * concrete variable of this type, that's why the declaration is visible here.
+ */
+typedef struct pj_hash_iterator_t
+{
+ pj_uint32_t index; /**< Internal index. */
+ pj_hash_entry *entry; /**< Internal entry. */
+} pj_hash_iterator_t;
+
+
+/**
+ * Forward declaration for memory pool factory.
+ */
+typedef struct pj_pool_factory pj_pool_factory;
+
+/**
+ * Opaque data type for memory pool.
+ */
+typedef struct pj_pool_t pj_pool_t;
+
+/**
+ * Forward declaration for caching pool, a pool factory implementation.
+ */
+typedef struct pj_caching_pool pj_caching_pool;
+
+/**
+ * This type is used as replacement to legacy C string, and used throughout
+ * the library.
+ */
+typedef struct pj_str_t pj_str_t;
+
+/**
+ * Opaque data type for I/O Queue structure.
+ */
+typedef struct pj_ioqueue_t pj_ioqueue_t;
+
+/**
+ * Opaque data type for key that identifies a handle registered to the
+ * I/O queue framework.
+ */
+typedef struct pj_ioqueue_key_t pj_ioqueue_key_t;
+
+/**
+ * Opaque data to identify timer heap.
+ */
+typedef struct pj_timer_heap_t pj_timer_heap_t;
+
+/**
+ * Forward declaration for timer entry.
+ */
+typedef struct pj_timer_entry pj_timer_entry;
+
+/**
+ * Opaque data type for atomic operations.
+ */
+typedef struct pj_atomic_t pj_atomic_t;
+
+/**
+ * Value type of an atomic variable.
+ */
+typedef PJ_ATOMIC_VALUE_TYPE pj_atomic_value_t;
+
+///////////////////////////////////////////////////////////////////////////////
+
+/** Thread handle. */
+typedef struct pj_thread_t pj_thread_t;
+
+/** Lock object. */
+typedef struct pj_lock_t pj_lock_t;
+
+/** Mutex handle. */
+typedef struct pj_mutex_t pj_mutex_t;
+
+/** Semaphore handle. */
+typedef struct pj_sem_t pj_sem_t;
+
+/** Event object. */
+typedef struct pj_event_t pj_event_t;
+
+/** Unidirectional stream pipe object. */
+typedef struct pj_pipe_t pj_pipe_t;
+
+/** Operating system handle. */
+typedef void *pj_oshandle_t;
+
+/** Socket handle. */
+typedef long pj_sock_t;
+
+/** Generic socket address. */
+typedef void pj_sockaddr_t;
+
+/** Color type. */
+typedef unsigned int pj_color_t;
+
+/** Exception id. */
+typedef int pj_exception_id_t;
+
+///////////////////////////////////////////////////////////////////////////////
+
+/** Utility macro to compute the number of elements in static array. */
+#define PJ_ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
+
+/** Maximum value for signed 32-bit integer. */
+#define PJ_MAXINT32 0x7FFFFFFFL
+
+/**
+ * Length of object names.
+ */
+#define PJ_MAX_OBJ_NAME 16
+
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * General.
+ */
+/**
+ * Initialize the PJ Library.
+ * This function must be called before using the library. The purpose of this
+ * function is to initialize static library data, such as character table used
+ * in random string generation, and to initialize operating system dependent
+ * functionality (such as WSAStartup() in Windows).
+ */
+PJ_DECL(pj_status_t) pj_init(void);
+
+
+/**
+ * @}
+ */
+/**
+ * @addtogroup PJ_TIME Time Data Type and Manipulation.
+ * @ingroup PJ_MISC
+ * @{
+ */
+
+/**
+ * Representation of time value in this library.
+ * This type can be used to represent either an interval or a specific time
+ * or date.
+ */
+typedef struct pj_time_val
+{
+ /** The seconds part of the time. */
+ long sec;
+
+ /** The miliseconds fraction of the time. */
+ long msec;
+
+} pj_time_val;
+
+/**
+ * Normalize the value in time value.
+ * @param t Time value to be normalized.
+ */
+PJ_DECL(void) pj_time_val_normalize(pj_time_val *t);
+
+/**
+ * Get the total time value in miliseconds. This is the same as
+ * multiplying the second part with 1000 and then add the miliseconds
+ * part to the result.
+ *
+ * @param t The time value.
+ * @return Total time in miliseconds.
+ * @hideinitializer
+ */
+#define PJ_TIME_VAL_MSEC(t) ((t).sec * 1000 + (t).msec)
+
+/**
+ * This macro will check if \a t1 is equal to \a t2.
+ *
+ * @param t1 The first time value to compare.
+ * @param t2 The second time value to compare.
+ * @return Non-zero if both time values are equal.
+ * @hideinitializer
+ */
+#define PJ_TIME_VAL_EQ(t1, t2) ((t1).sec==(t2).sec && (t1).msec==(t2).msec)
+
+/**
+ * This macro will check if \a t1 is greater than \a t2
+ *
+ * @param t1 The first time value to compare.
+ * @param t2 The second time value to compare.
+ * @return Non-zero if t1 is greater than t2.
+ * @hideinitializer
+ */
+#define PJ_TIME_VAL_GT(t1, t2) ((t1).sec>(t2).sec || \
+ ((t1).sec==(t2).sec && (t1).msec>(t2).msec))
+
+/**
+ * This macro will check if \a t1 is greater than or equal to \a t2
+ *
+ * @param t1 The first time value to compare.
+ * @param t2 The second time value to compare.
+ * @return Non-zero if t1 is greater than or equal to t2.
+ * @hideinitializer
+ */
+#define PJ_TIME_VAL_GTE(t1, t2) (PJ_TIME_VAL_GT(t1,t2) || \
+ PJ_TIME_VAL_EQ(t1,t2))
+
+/**
+ * This macro will check if \a t1 is less than \a t2
+ *
+ * @param t1 The first time value to compare.
+ * @param t2 The second time value to compare.
+ * @return Non-zero if t1 is less than t2.
+ * @hideinitializer
+ */
+#define PJ_TIME_VAL_LT(t1, t2) (!(PJ_TIME_VAL_GTE(t1,t2)))
+
+/**
+ * This macro will check if \a t1 is less than or equal to \a t2.
+ *
+ * @param t1 The first time value to compare.
+ * @param t2 The second time value to compare.
+ * @return Non-zero if t1 is less than or equal to t2.
+ * @hideinitializer
+ */
+#define PJ_TIME_VAL_LTE(t1, t2) (!PJ_TIME_VAL_GT(t1, t2))
+
+/**
+ * Add \a t2 to \a t1 and store the result in \a t1. Effectively
+ *
+ * this macro will expand as: (\a t1 += \a t2).
+ * @param t1 The time value to add.
+ * @param t2 The time value to be added to \a t1.
+ * @hideinitializer
+ */
+#define PJ_TIME_VAL_ADD(t1, t2) do { \
+ (t1).sec += (t2).sec; \
+ (t1).msec += (t2).msec; \
+ pj_time_val_normalize(&(t1)); \
+ } while (0)
+
+
+/**
+ * Substract \a t2 from \a t1 and store the result in \a t1. Effectively
+ * this macro will expand as (\a t1 -= \a t2).
+ *
+ * @param t1 The time value to subsctract.
+ * @param t2 The time value to be substracted from \a t1.
+ * @hideinitializer
+ */
+#define PJ_TIME_VAL_SUB(t1, t2) do { \
+ (t1).sec -= (t2).sec; \
+ (t1).msec -= (t2).msec; \
+ pj_time_val_normalize(&(t1)); \
+ } while (0)
+
+
+/**
+ * This structure represent the parsed representation of time.
+ * It is acquired by calling #pj_time_decode().
+ */
+typedef struct pj_parsed_time
+{
+ /** This represents day of week where value zero means Sunday */
+ int wday;
+
+ /** This represents day of the year, 0-365, where zero means
+ * 1st of January.
+ */
+ int yday;
+
+ /** This represents day of month: 1-31 */
+ int day;
+
+ /** This represents month, with the value is 0 - 11 (zero is January) */
+ int mon;
+
+ /** This represent the actual year (unlike in ANSI libc where
+ * the value must be added by 1900).
+ */
+ int year;
+
+ /** This represents the second part, with the value is 0-59 */
+ int sec;
+
+ /** This represents the minute part, with the value is: 0-59 */
+ int min;
+
+ /** This represents the hour part, with the value is 0-23 */
+ int hour;
+
+ /** This represents the milisecond part, with the value is 0-999 */
+ int msec;
+
+} pj_parsed_time;
+
+
+/**
+ * @} // Time Management
+ */
+
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * Terminal.
+ */
+/**
+ * Color code combination.
+ */
+enum {
+ PJ_TERM_COLOR_R = 2, /**< Red */
+ PJ_TERM_COLOR_G = 4, /**< Green */
+ PJ_TERM_COLOR_B = 1, /**< Blue. */
+ PJ_TERM_COLOR_BRIGHT = 8 /**< Bright mask. */
+};
+
+
+
+
+PJ_END_DECL
+
+
+#endif /* __PJ_TYPES_H__ */
+
diff --git a/pjlib/include/pjlib++.hpp b/pjlib/include/pjlib++.hpp index fefd3d0d..81db2202 100644 --- a/pjlib/include/pjlib++.hpp +++ b/pjlib/include/pjlib++.hpp @@ -1,5 +1,26 @@ -/* $Id$ - * +/* $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 __PJLIBPP_H__
#define __PJLIBPP_H__
diff --git a/pjlib/include/pjlib.h b/pjlib/include/pjlib.h index 7e4bf362..63af44bf 100644 --- a/pjlib/include/pjlib.h +++ b/pjlib/include/pjlib.h @@ -1,39 +1,60 @@ -/* $Id$ - * - */ -#ifndef __PJLIB_H__ -#define __PJLIB_H__ - -/** - * @file pjlib.h - * @brief Include all PJLIB header files. - */ - -#include <pj/addr_resolv.h> -#include <pj/array.h> -#include <pj/assert.h> -#include <pj/ctype.h> -#include <pj/errno.h> -#include <pj/except.h> -#include <pj/fifobuf.h> -#include <pj/file_access.h> -#include <pj/file_io.h> -#include <pj/guid.h> -#include <pj/hash.h> -#include <pj/ioqueue.h> -#include <pj/list.h> -#include <pj/lock.h> -#include <pj/log.h> -#include <pj/os.h> -#include <pj/pool.h> -#include <pj/rand.h> -#include <pj/rbtree.h> -#include <pj/sock.h> -#include <pj/sock_select.h> -#include <pj/string.h> -#include <pj/timer.h> - -#include <pj/compat/high_precision.h> - -#endif /* __PJLIB_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_H__
+#define __PJLIB_H__
+
+/**
+ * @file pjlib.h
+ * @brief Include all PJLIB header files.
+ */
+
+#include <pj/addr_resolv.h>
+#include <pj/array.h>
+#include <pj/assert.h>
+#include <pj/ctype.h>
+#include <pj/errno.h>
+#include <pj/except.h>
+#include <pj/fifobuf.h>
+#include <pj/file_access.h>
+#include <pj/file_io.h>
+#include <pj/guid.h>
+#include <pj/hash.h>
+#include <pj/ioqueue.h>
+#include <pj/list.h>
+#include <pj/lock.h>
+#include <pj/log.h>
+#include <pj/os.h>
+#include <pj/pool.h>
+#include <pj/rand.h>
+#include <pj/rbtree.h>
+#include <pj/sock.h>
+#include <pj/sock_select.h>
+#include <pj/string.h>
+#include <pj/timer.h>
+
+#include <pj/compat/high_precision.h>
+
+#endif /* __PJLIB_H__ */
+
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(¤t->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(¤t->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 *)∈ - 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 *)∈
+ 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;
+}
|