aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2007-06-30 00:50:38 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2007-06-30 00:50:38 +0000
commit77706e5457f8cd6a98857301a79477e899d3c09a (patch)
treeeae4009c1625edfe9023bdb8abb88257c0dbc489
parent489d39ee427d48b12ffc422030805531b2aaa337 (diff)
downloadpaludis-77706e5457f8cd6a98857301a79477e899d3c09a.tar.gz
paludis-77706e5457f8cd6a98857301a79477e899d3c09a.tar.xz
r3670@snowflake: ciaranm | 2007-06-30 01:13:44 +0100
Allow detached threads
-rw-r--r--paludis/util/thread.cc57
-rw-r--r--paludis/util/thread.hh10
-rw-r--r--paludis/util/thread_TEST.cc23
3 files changed, 88 insertions, 2 deletions
diff --git a/paludis/util/thread.cc b/paludis/util/thread.cc
index 9085356..08586ad 100644
--- a/paludis/util/thread.cc
+++ b/paludis/util/thread.cc
@@ -28,7 +28,20 @@ using namespace paludis;
Thread::Thread(const tr1::function<void () throw ()> & f) :
_thread(new pthread_t),
- _func(f)
+ _func(f),
+ _detached(false)
+{
+ int err;
+ if (0 != ((err = pthread_create(_thread, 0, &thread_func, this))))
+ throw InternalError(PALUDIS_HERE, "pthread_create failed: " + stringify(strerror(err)));
+}
+
+Thread::Thread(const tr1::function<void () throw ()> & f,
+ const tr1::function<void (Thread * const) throw ()> & pf) :
+ _thread(new pthread_t),
+ _func(f),
+ _post_func(pf),
+ _detached(false)
{
int err;
if (0 != ((err = pthread_create(_thread, 0, &thread_func, this))))
@@ -39,15 +52,29 @@ void *
Thread::thread_func(void * r)
{
static_cast<Thread *>(r)->_func();
+ if (static_cast<Thread *>(r)->_post_func)
+ static_cast<Thread *>(r)->_post_func(static_cast<Thread *>(r));
+
return 0;
}
Thread::~Thread()
{
- pthread_join(*_thread, 0);
+ if (! _detached)
+ pthread_join(*_thread, 0);
delete _thread;
}
+void
+Thread::detach()
+{
+ if (! _detached)
+ {
+ pthread_detach(*_thread);
+ _detached = true;
+ }
+}
+
#else
Thread::Thread(const tr1::function<void () throw ()> & f)
@@ -55,9 +82,35 @@ Thread::Thread(const tr1::function<void () throw ()> & f)
f();
}
+Thread::Thread(const tr1::function<void () throw ()> & f,
+ const tr1::function<void (Thread * const) throw ()> & pf)
+{
+ f();
+ pf();
+}
+
Thread::~Thread()
{
}
+void
+Thread::detach()
+{
+}
+
#endif
+namespace
+{
+ void post_delete_func(Thread * const t) throw ()
+ {
+ delete t;
+ }
+}
+
+void
+paludis::run_detached(const tr1::function<void () throw ()> & f)
+{
+ (new Thread(f, &post_delete_func))->detach();
+}
+
diff --git a/paludis/util/thread.hh b/paludis/util/thread.hh
index 5729d88..049a60f 100644
--- a/paludis/util/thread.hh
+++ b/paludis/util/thread.hh
@@ -35,14 +35,24 @@ namespace paludis
#ifdef PALUDIS_ENABLE_THREADS
pthread_t * const _thread;
const tr1::function<void () throw ()> _func;
+ const tr1::function<void (Thread * const) throw ()> _post_func;
+ bool _detached;
static void * thread_func(void *);
#endif
public:
Thread(const tr1::function<void () throw ()> &);
+
+ Thread(const tr1::function<void () throw ()> &,
+ const tr1::function<void (Thread * const) throw ()> &);
+
~Thread();
+
+ void detach();
};
+
+ void run_detached(const tr1::function<void () throw ()> &) PALUDIS_VISIBLE;
}
#endif
diff --git a/paludis/util/thread_TEST.cc b/paludis/util/thread_TEST.cc
index 5a39119..046510b 100644
--- a/paludis/util/thread_TEST.cc
+++ b/paludis/util/thread_TEST.cc
@@ -20,6 +20,7 @@
#include <paludis/util/thread.hh>
#include <test/test_runner.hh>
#include <test/test_framework.hh>
+#include <time.h>
using namespace test;
using namespace paludis;
@@ -47,5 +48,27 @@ namespace test_cases
TEST_CHECK(x);
}
} test_thread;
+
+ struct RunDetachedTest : TestCase
+ {
+ RunDetachedTest() : TestCase("run detached") { }
+
+ void run()
+ {
+ bool x(false);
+ run_detached(tr1::bind(&make_true, tr1::ref(x)));
+ while (true)
+ if (x)
+ break;
+ else
+ {
+ struct timespec t;
+ t.tv_sec = 0;
+ t.tv_nsec = 100000;
+ ::nanosleep(&t, 0);
+ TEST_CHECK(true);
+ }
+ }
+ } test_run_detached;
}