summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2007-01-06 19:39:56 +0000
committerDavid Robillard <d@drobilla.net>2007-01-06 19:39:56 +0000
commit4014067a1668d94000b059d72832482a06cf8369 (patch)
tree7617295999221d85fb5fdf6ac92f30beba4141da
parent1a2962681ff62598f6cbe9aed9c5d4c69c0020a6 (diff)
downloadraul-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.am2
-rw-r--r--README5
-rwxr-xr-xautogen.sh2
-rw-r--r--configure.ac3
-rw-r--r--raul.pc.in2
-rw-r--r--raul/Thread.h60
-rw-r--r--src/Makefile.am10
-rw-r--r--src/Thread.cpp21
-rw-r--r--tests/Makefile.am8
-rw-r--r--tests/queue_test.cpp47
-rw-r--r--tests/thread_test.cpp16
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
diff --git a/README b/README
index aad9a98..e400929 100644
--- a/README
+++ b/README
@@ -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.
diff --git a/autogen.sh b/autogen.sh
index 19f7543..fd00b8c 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -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])
diff --git a/raul.pc.in b/raul.pc.in
index cbf8fc5..b405f37 100644
--- a/raul.pc.in
+++ b/raul.pc.in
@@ -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;
+}
+