diff options
author | David Robillard <d@drobilla.net> | 2007-01-06 19:39:56 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2007-01-06 19:39:56 +0000 |
commit | 4014067a1668d94000b059d72832482a06cf8369 (patch) | |
tree | 7617295999221d85fb5fdf6ac92f30beba4141da | |
parent | 1a2962681ff62598f6cbe9aed9c5d4c69c0020a6 (diff) | |
download | raul-4014067a1668d94000b059d72832482a06cf8369.tar.gz raul-4014067a1668d94000b059d72832482a06cf8369.tar.bz2 raul-4014067a1668d94000b059d72832482a06cf8369.zip |
Added ability to get Raul Thread for current calling context.
Strong threading assertions.
Flowcanvas port removal fixes.
Patch port destruction.
Code cleanups, bug fixes.
git-svn-id: http://svn.drobilla.net/lad/raul@234 a436a847-0d15-0410-975c-d299462d15a1
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | README | 5 | ||||
-rwxr-xr-x | autogen.sh | 2 | ||||
-rw-r--r-- | configure.ac | 3 | ||||
-rw-r--r-- | raul.pc.in | 2 | ||||
-rw-r--r-- | raul/Thread.h | 60 | ||||
-rw-r--r-- | src/Makefile.am | 10 | ||||
-rw-r--r-- | src/Thread.cpp | 21 | ||||
-rw-r--r-- | tests/Makefile.am | 8 | ||||
-rw-r--r-- | tests/queue_test.cpp | 47 | ||||
-rw-r--r-- | tests/thread_test.cpp | 16 |
11 files changed, 163 insertions, 13 deletions
diff --git a/Makefile.am b/Makefile.am index ce16387..29de7fc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = raul doc +SUBDIRS = raul src doc if BUILD_TESTS SUBDIRS += tests @@ -1,5 +1,6 @@ RAUL - Realtime Audio Utility Library -Raul is a lightweight header-only C++ convenience library for realtime -programming, with a (slight) bias towards audio applications. +Raul is a lightweight C++ convenience library for realtime +programming, with a bias towards audio applications +on GNU/Linux machines. @@ -1,7 +1,7 @@ #!/bin/sh echo 'Generating necessary files...' -#libtoolize --copy --force +libtoolize --copy --force aclocal #autoheader -Wall automake --gnu --add-missing -Wall diff --git a/configure.ac b/configure.ac index 6b9302a..3b40be9 100644 --- a/configure.ac +++ b/configure.ac @@ -8,7 +8,7 @@ AC_LANG([C++]) #AC_PROG_CXX AC_TYPE_SIZE_T -#AC_PROG_LIBTOOL +AC_PROG_LIBTOOL AC_HEADER_STDC AC_TYPE_INT32_T @@ -69,6 +69,7 @@ fi AM_CONDITIONAL(WITH_LIBLO, [test "$build_liblo" = "yes"]) AC_CONFIG_FILES([Makefile]) +AC_CONFIG_FILES([src/Makefile]) AC_CONFIG_FILES([raul/Makefile]) AC_CONFIG_FILES([tests/Makefile]) AC_CONFIG_FILES([doc/Makefile]) @@ -6,5 +6,5 @@ includedir=@includedir@ Name: raul Version: @VERSION@ Description: A C++ convenience library for realtime audio applications -Libs: +Libs: -L${libdir} -lraul Cflags: -I${includedir} diff --git a/raul/Thread.h b/raul/Thread.h index b7fd9c4..2a7a321 100644 --- a/raul/Thread.h +++ b/raul/Thread.h @@ -28,17 +28,34 @@ * Extend this and override the _run method to easily create a thread * to perform some task. * + * The current Thread can be accessed using the get() method. + * * \ingroup raul */ class Thread : boost::noncopyable { public: - Thread() : _pthread_exists(false) {} - virtual ~Thread() { stop(); } + + static Thread* create(const std::string& name="") + { return new Thread(name); } - void set_name(const std::string& name) { _name = name; } + /** Must be called from thread */ + static Thread* create_for_this_thread(const std::string& name="") + { return new Thread(pthread_self(), name); } + /** Return the calling thread. + * The return value of this should NOT be cached unless the thread is + * explicitly user created with create(). + */ + static Thread& get() { + Thread* this_thread = reinterpret_cast<Thread*>(pthread_getspecific(_thread_key)); + if (!this_thread) + this_thread = new Thread(); // sets thread-specific data + + return *this_thread; + } + /** Launch and start the thread. */ virtual void start() { std::cout << "[" << _name << " Thread] Starting." << std::endl; @@ -78,23 +95,56 @@ public: << strerror(result) << ")" << std::endl; } } - + + const std::string& name() { return _name; } + void set_name(const std::string& name) { _name = name; } + + const unsigned context() { return _context; } + void set_context(unsigned context) { _context = context; } protected: + Thread(const std::string& name="") : _context(0), _name(name), _pthread_exists(false) + { + pthread_once(&_thread_key_once, thread_key_alloc); + } + + /** Must be called from thread */ + Thread(pthread_t thread, const std::string& name="") + : _context(0), _name(name), _pthread_exists(true), _pthread(thread) + { + pthread_once(&_thread_key_once, thread_key_alloc); + pthread_setspecific(_thread_key, this); + } + /** Thread function to execute. * * This is called once on start, and terminated on stop. * Implementations likely want to put some infinite loop here. */ - virtual void _run() = 0; + virtual void _run() {} private: + inline static void* _static_run(void* me) { + pthread_setspecific(_thread_key, me); Thread* myself = (Thread*)me; myself->_run(); return NULL; // and I } + /** Allocate thread-specific data key */ + static void thread_key_alloc() + { + pthread_key_create(&_thread_key, NULL); + } + + /* Key for the thread-specific buffer */ + static pthread_key_t _thread_key; + + /* Once-only initialisation of the key */ + static pthread_once_t _thread_key_once; + + unsigned _context; std::string _name; bool _pthread_exists; pthread_t _pthread; diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..aa1143e --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,10 @@ +AM_CXXFLAGS = -I$(top_srcdir) + +lib_LTLIBRARIES = libraul.la + +#libraul_la_LIBADD = @FOO_LIBS@ + +libraul_la_SOURCES = \ + Thread.cpp + + diff --git a/src/Thread.cpp b/src/Thread.cpp new file mode 100644 index 0000000..34ba0f9 --- /dev/null +++ b/src/Thread.cpp @@ -0,0 +1,21 @@ +/* This file is part of Ingen. Copyright (C) 2007 Dave Robillard. + * + * Ingen is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * Ingen is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "raul/Thread.h" + +/* Thread-specific data key (once-only initialized) */ +pthread_once_t Thread::_thread_key_once = PTHREAD_ONCE_INIT; +pthread_key_t Thread::_thread_key; diff --git a/tests/Makefile.am b/tests/Makefile.am index 0732d07..2389628 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,8 +1,12 @@ if BUILD_TESTS -AM_CXXFLAGS = -I.. -bin_PROGRAMS = path_test +AM_CXXFLAGS = -I.. -lpthread +bin_PROGRAMS = path_test thread_test queue_test + +thread_test_LDADD = ../src/libraul.la path_test_SOURCES = path_test.cpp +thread_test_SOURCES = thread_test.cpp +queue_test_SOURCES = queue_test.cpp endif diff --git a/tests/queue_test.cpp b/tests/queue_test.cpp new file mode 100644 index 0000000..c39d156 --- /dev/null +++ b/tests/queue_test.cpp @@ -0,0 +1,47 @@ +#include <iostream> +#include <string> +#include "raul/Queue.h" + +using std::string; using std::cerr; using std::cout; using std::endl; + + +int main() +{ + Queue<int> q(10); + + cout << "New queue. Should be empty: " << q.is_empty() << endl; + cout << "Capacity: " << q.capacity() << endl; + cout << "Fill: " << q.fill() << endl; + + for (uint i=0; i < 5; ++i) { + q.push(i); + assert(!q.is_full()); + q.pop(); + } + cout << "Pushed and popped 5 elements. Queue should be empty: " << q.is_empty() << endl; + cout << "Fill: " << q.fill() << endl; + + for (uint i=10; i < 20; ++i) { + q.push(i); + } + cout << "Pushed 10 elements. Queue should be full: " << q.is_full() << endl; + cout << "Fill: " << q.fill() << endl; + + cout << "The digits 10->19 should print: " << endl; + while (!q.is_empty()) { + int foo = q.pop(); + cout << "Popped: " << foo << endl; + } + cout << "Queue should be empty: " << q.is_empty() << endl; + cout << "Fill: " << q.fill() << endl; + + cout << "Attempting to add eleven elements to queue of size 10. Only first 10 should succeed:" << endl; + for (uint i=20; i <= 39; ++i) { + cout << i; + cout << " - Fill: " << q.fill(); + cout << ", is full: " << q.is_full(); + cout << ", succeeded: " << q.push(i) << endl; + } + + return 0; +} diff --git a/tests/thread_test.cpp b/tests/thread_test.cpp new file mode 100644 index 0000000..7a4d875 --- /dev/null +++ b/tests/thread_test.cpp @@ -0,0 +1,16 @@ +#include <iostream> +#include <raul/Thread.h> + +using namespace std; + +int +main() +{ + Thread& this_thread = Thread::get(); + this_thread.set_name("Main"); + + cerr << "Thread name: " << Thread::get().name() << endl; + + return 0; +} + |