Native threads for Win32
authorMikko Rasa <tdb@tdb.fi>
Thu, 24 Aug 2006 18:26:01 +0000 (18:26 +0000)
committerMikko Rasa <tdb@tdb.fi>
Thu, 24 Aug 2006 18:26:01 +0000 (18:26 +0000)
source/application.cpp
source/application.h
source/mutex.h
source/pollable.cpp
source/thread.cpp
source/thread.h
source/types.h [new file with mode: 0644]
source/win32signum.h [deleted file]

index 22c8d2688310685fb2aaeb4e30857256bcc7c062..a9aa88ea55bdee578d81238d614120a962be2173 100644 (file)
@@ -19,7 +19,9 @@ Poller::Slot &Application::add_pollable(Pollable *obj, short events)
        
        Poller::Slot &slot=poller_->add_pollable(obj, events);
        // Interrupt a possible poll in progress
-       pthread_kill(main_tid, SIGALRM);        
+#ifndef WIN32  //XXX
+       pthread_kill(main_tid, SIGALRM);
+#endif
        return slot;
 }
 
@@ -62,7 +64,9 @@ int Application::run(int argc, char **argv)
                return 126;
        }
 
+#ifndef WIN32 //XXX
        signal(SIGALRM, &sigalrm_);
+#endif
        
        try
        {
@@ -91,6 +95,17 @@ void Application::usage(const char *, bool)
        cerr<<"The programmer was lazy and didn't write a usage() function for this application.\n";
 }
 
+Application::Application():
+       exit_code(0),
+       tick_mode_(IDLE),
+       poller_(0),
+       ev_mgr_(0)
+#ifndef WIN32
+       //XXX Figure out how to get the current thread on win32
+       ,main_tid(pthread_self())
+#endif
+{ }
+
 /**
 Default main loop.  Calls tick() periodically if do_ticks is true, otherwise
 just sleeps.  A custom main loop should monitor the done member variable and
@@ -106,7 +121,11 @@ int Application::main()
                        if(poller_)
                                poller_->poll(0);
                        tick();
+#ifdef WIN32
+                       Sleep(0);
+#else
                        sched_yield();
+#endif
                }
                else
                {
@@ -140,7 +159,9 @@ void Application::catch_signal(int s)
 void Application::set_tick_mode(TickMode t)
 {
        tick_mode_=t;
+#ifndef WIN32 //XXX
        pthread_kill(main_tid, SIGALRM);        
+#endif
 }
 
 /**
@@ -150,7 +171,9 @@ void Application::exit(int c)
 {
        done=true;
        exit_code=c;
+#ifndef WIN32 //XXX
        pthread_kill(main_tid, SIGALRM);        
+#endif
 }
 
 void Application::sighandler_(int s)
index b2502edd83501094060450dae399d234b4444d51..5f3968ac4018faa2c6f3f8b1e3e3fb8f77f1ef64 100644 (file)
@@ -6,13 +6,9 @@ Distributed under the LGPL
 #ifndef MSP_FRAMEWORK_APPLICATION_H_
 #define MSP_FRAMEWORK_APPLICATION_H_
 
-#ifdef WIN32
-#include "win32signum.h"
-#endif
-
-#include <pthread.h>
 #include "event.h"
 #include "poller.h"
+#include "types.h"
 
 namespace Msp {
 
@@ -58,7 +54,7 @@ protected:
        bool done;
        int  exit_code;
 
-       Application(): exit_code(0), tick_mode_(IDLE), poller_(0), ev_mgr_(0), main_tid(pthread_self()) { }
+       Application();
        virtual int main();
        void catch_signal(int);
        void set_tick_mode(TickMode);
@@ -69,7 +65,7 @@ private:
        TickMode     tick_mode_;
        Poller       *poller_;
        EventManager *ev_mgr_;
-       pthread_t    main_tid;
+       ThreadHandle main_tid;
 
        Application(const Application &);
        Application &operator=(const Application &);
index 0c2879e0cff6eb3301dd66c8c3c57faa3c1d0ba3..b619fcdb7c6b9127a550a296c9f4cb521d0d3ecc 100644 (file)
@@ -6,21 +6,29 @@ Distributed under the LGPL
 #ifndef MSP_FRAMEWORK_MUTEX_H_
 #define MSP_FRAMEWORK_MUTEX_H_
 
-#include <pthread.h>
 #include <msp/refcount.h>
+#include "types.h"
 
 namespace Msp {
 
 class Mutex
 {
 public:
+#ifndef WIN32
        Mutex()       { pthread_mutex_init(&mutex, 0); }
        int lock()    { return pthread_mutex_lock(&mutex); }
        int trylock() { return pthread_mutex_trylock(&mutex); }
        int unlock()  { return pthread_mutex_unlock(&mutex); }
        ~Mutex()      { pthread_mutex_destroy(&mutex); }
+#else
+       Mutex()       { mutex=CreateMutex(0, false, 0); }
+       int lock()    { return WaitForSingleObject(mutex, INFINITE)==WAIT_OBJECT_0; }
+       int trylock() { return WaitForSingleObject(mutex, 0)==WAIT_OBJECT_0; }
+       int unlock()  { return !ReleaseMutex(mutex); }
+       ~Mutex()      { CloseHandle(mutex); }
+#endif
 private:
-       pthread_mutex_t mutex;
+       MutexHandle mutex;
 
        friend class Semaphore;
 };
index 4b0cb1c7bb3804e3aeef109a27405ae0ceac57c8..4db38dd70ac222823b039ab466acd98a409fd595 100644 (file)
@@ -19,7 +19,6 @@ short Pollable::poll(short events, int timeout)
        return 0;
 #else
        pollfd pfd={get_fd(), events, 0};
-       int result=select(&pfd, 1, timeout);
        int result=::poll(&pfd, 1, timeout);
        if(result<=0)
                return result;
index ba0c479770b4c7cbcee4c975e19180565dad4ea5..6858ce9999b8ba2211db353802acfa2750811125 100644 (file)
@@ -3,26 +3,70 @@ This file is part of libmspframework
 Copyright © 2006 Mikko Rasa, Mikkosoft Productions
 Distributed under the LGPL
 */
+#ifndef WIN32
 #include <signal.h>
+#endif
 #include "thread.h"
 
 namespace Msp {
 
-void *Thread::join()
+/**
+Waits for the thread to exit.  Calling this from the thread will cause a
+deadlock.
+*/
+void Thread::join()
 {
-       if(!valid_)
-               return 0;
+       if(!launched_)
+               return;
 
-       void *result;
-       pthread_join(thread_, &result);
-       valid_=false;
-       return result;
+#ifdef WIN32
+       WaitForSingleObject(thread_, INFINITE);
+#else
+       pthread_join(thread_, 0);
+#endif
+       launched_=false;
+}
+
+/**
+Requests the thread to terminate gracefully.  Currently unimplemented on win32.
+*/
+void Thread::cancel()
+{
+#ifndef WIN32 //XXX
+       pthread_cancel(thread_);
+#endif
+}
+
+/**
+Violently terminates the thread.
+*/
+void Thread::kill()
+{
+#ifdef WIN32
+       TerminateThread(thread_, 0);
+#else
+       pthread_kill(thread_, SIGKILL);
+#endif
 }
 
 Thread::~Thread()
 {
-       if(valid_)
-               kill(SIGKILL);
+       if(launched_)
+               kill();
+}
+
+void Thread::launch()
+{
+       if(launched_)
+               return;
+
+#ifdef WIN32
+       DWORD dummy;  // Win9x needs the lpTthreadId parameter
+       thread_=CreateThread(0, 0, &main_, this, 0, &dummy);
+#else
+       pthread_create(&thread_, 0, &main_, this);
+#endif
+       launched_=true;
 }
 
 } // namespace Msp
index 51ca0ef3395c2abe80d182a6cef056429d655e75..2b0766c68ba7fbd0d443265d30d58628ddda76f8 100644 (file)
@@ -6,33 +6,43 @@ Distributed under the LGPL
 #ifndef MSP_FRAMEWORK_THREAD_H_
 #define MSP_FRAMEWORK_THREAD_H_
 
-#ifdef WIN32
-#include "win32signum.h"
-#endif
-
-#include <pthread.h>
+#include "types.h"
 
 namespace Msp {
 
+/**
+Base class for threads.  To create a thread for some task, derive it from this
+class and implement the main() function.  Note that threads are not
+automatically started upon creation - you must manually call launch() instead.
+This is to allow initializing variables of the derived class before the thread
+is started.
+*/
 class Thread
 {
 public:
-       void *join();
-       void kill(int s)   { pthread_kill(thread_, s); }
+       void join();
+       void cancel();
+       void kill();
        virtual ~Thread();
 protected:
-       Thread(): valid_(false) { }
-       void launch()      { if(!valid_) pthread_create(&thread_, 0, &main_, this); }
-       virtual void *main()=0;
-       void exit(void *r) { pthread_exit(r); }
+       Thread(): launched_(false) { }
+       void launch();
+       virtual void main()=0;
+       void check_cancel();
 private:
-       pthread_t thread_;
-       bool      valid_;
+       ThreadHandle thread_;
+       bool         launched_;
 
        Thread(const Thread &);
        Thread &operator=(const Thread &);
 
-       static void *main_(void *t) { return ((Thread *)t)->main(); }
+#ifdef WIN32
+#      define THREAD_RETURN_ DWORD WINAPI
+#else
+#      define THREAD_RETURN_ void *
+#endif
+       static THREAD_RETURN_ main_(void *t) { ((Thread *)t)->main(); return 0; }
+#undef THREAD_RETURN_
 };
 
 } // namespace Msp
diff --git a/source/types.h b/source/types.h
new file mode 100644 (file)
index 0000000..7296689
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+This file is part of libmspframework
+Copyright © 2006  Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+#ifndef MSP_FRAMEWORK_TYPES_H_
+#define MSP_FRAMEWORK_TYPES_H_
+
+#ifdef WIN32
+#include <windows.h>
+#else
+#include <pthread.h>
+#endif
+
+namespace Msp {
+
+#ifdef WIN32
+typedef HANDLE ThreadHandle;
+typedef HANDLE MutexHandle;
+#else
+typedef pthread_t ThreadHandle;
+typedef pthread_mutex_t MutexHandle;
+#endif
+
+} // namespace Msp
+
+#endif
diff --git a/source/win32signum.h b/source/win32signum.h
deleted file mode 100644 (file)
index 1635ea9..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
-This file is part of libmspframework
-Copyright © 2006 Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-#ifndef MSP_FRAMEWORK_WIN32SIGNUM_H_
-#define MSP_FRAMEWORK_WIN32SIGNUM_H_
-
-/* Fake signal functions.  */
-#ifndef SIG_ERR
-#define SIG_ERR        ((__sighandler_t) -1)           /* Error return.  */
-#endif
-#ifndef SIG_DFL
-#define SIG_DFL        ((__sighandler_t) 0)            /* Default action.  */
-#endif
-#ifndef SIG_IGN
-#define SIG_IGN        ((__sighandler_t) 1)            /* Ignore signal.  */
-#endif
-
-#if defined __USE_UNIX98 && !defined SIG_HOLD
-# define SIG_HOLD      ((__sighandler_t) 2)    /* Add signal to hold mask.  */
-#endif
-
-/* Signals.  */
-#define        SIGHUP          1       /* Hangup (POSIX).  */
-#define        SIGINT          2       /* Interrupt (ANSI).  */
-#define        SIGQUIT         3       /* Quit (POSIX).  */
-#define        SIGILL          4       /* Illegal instruction (ANSI).  */
-#define        SIGTRAP         5       /* Trace trap (POSIX).  */
-#ifndef SIGABRT
-#define        SIGABRT         6       /* Abort (ANSI).  */
-#endif
-#define        SIGIOT          6       /* IOT trap (4.2 BSD).  */
-#define        SIGBUS          7       /* BUS error (4.2 BSD).  */
-#define        SIGFPE          8       /* Floating-point exception (ANSI).  */
-#define        SIGKILL         9       /* Kill, unblockable (POSIX).  */
-#define        SIGUSR1         10      /* User-defined signal 1 (POSIX).  */
-#define        SIGSEGV         11      /* Segmentation violation (ANSI).  */
-#define        SIGUSR2         12      /* User-defined signal 2 (POSIX).  */
-#define        SIGPIPE         13      /* Broken pipe (POSIX).  */
-#define        SIGALRM         14      /* Alarm clock (POSIX).  */
-#define        SIGTERM         15      /* Termination (ANSI).  */
-#define        SIGSTKFLT       16      /* Stack fault.  */
-#define        SIGCLD          SIGCHLD /* Same as SIGCHLD (System V).  */
-#define        SIGCHLD         17      /* Child status has changed (POSIX).  */
-#define        SIGCONT         18      /* Continue (POSIX).  */
-#define        SIGSTOP         19      /* Stop, unblockable (POSIX).  */
-#define        SIGTSTP         20      /* Keyboard stop (POSIX).  */
-#define        SIGTTIN         21      /* Background read from tty (POSIX).  */
-#define        SIGTTOU         22      /* Background write to tty (POSIX).  */
-#define        SIGURG          23      /* Urgent condition on socket (4.2 BSD).  */
-#define        SIGXCPU         24      /* CPU limit exceeded (4.2 BSD).  */
-#define        SIGXFSZ         25      /* File size limit exceeded (4.2 BSD).  */
-#define        SIGVTALRM       26      /* Virtual alarm clock (4.2 BSD).  */
-#define        SIGPROF         27      /* Profiling alarm clock (4.2 BSD).  */
-#define        SIGWINCH        28      /* Window size change (4.3 BSD, Sun).  */
-#define        SIGPOLL         SIGIO   /* Pollable event occurred (System V).  */
-#define        SIGIO           29      /* I/O now possible (4.2 BSD).  */
-#define        SIGPWR          30      /* Power failure restart (System V).  */
-#define SIGSYS         31      /* Bad system call.  */
-#define SIGUNUSED      31
-
-#define        _NSIG           65      /* Biggest signal number + 1
-                                  (including real-time signals).  */
-
-#define SIGRTMIN        (__libc_current_sigrtmin ())
-#define SIGRTMAX        (__libc_current_sigrtmax ())
-
-/* These are the hard limits of the kernel.  These values should not be
-   used directly at user level.  */
-#define __SIGRTMIN     32
-#define __SIGRTMAX     (_NSIG - 1)
-
-#endif