From 727f8ce40806cc2f7c295260f3c9aa156c815c70 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Thu, 24 Aug 2006 18:26:01 +0000 Subject: [PATCH] Native threads for Win32 --- source/application.cpp | 25 +++++++++++++- source/application.h | 10 ++---- source/mutex.h | 12 +++++-- source/pollable.cpp | 1 - source/thread.cpp | 62 ++++++++++++++++++++++++++++++----- source/thread.h | 38 ++++++++++++++-------- source/types.h | 27 +++++++++++++++ source/win32signum.h | 74 ------------------------------------------ 8 files changed, 141 insertions(+), 108 deletions(-) create mode 100644 source/types.h delete mode 100644 source/win32signum.h diff --git a/source/application.cpp b/source/application.cpp index 22c8d26..a9aa88e 100644 --- a/source/application.cpp +++ b/source/application.cpp @@ -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) diff --git a/source/application.h b/source/application.h index b2502ed..5f3968a 100644 --- a/source/application.h +++ b/source/application.h @@ -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 #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 &); diff --git a/source/mutex.h b/source/mutex.h index 0c2879e..b619fcd 100644 --- a/source/mutex.h +++ b/source/mutex.h @@ -6,21 +6,29 @@ Distributed under the LGPL #ifndef MSP_FRAMEWORK_MUTEX_H_ #define MSP_FRAMEWORK_MUTEX_H_ -#include #include +#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; }; diff --git a/source/pollable.cpp b/source/pollable.cpp index 4b0cb1c..4db38dd 100644 --- a/source/pollable.cpp +++ b/source/pollable.cpp @@ -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; diff --git a/source/thread.cpp b/source/thread.cpp index ba0c479..6858ce9 100644 --- a/source/thread.cpp +++ b/source/thread.cpp @@ -3,26 +3,70 @@ This file is part of libmspframework Copyright © 2006 Mikko Rasa, Mikkosoft Productions Distributed under the LGPL */ +#ifndef WIN32 #include +#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 diff --git a/source/thread.h b/source/thread.h index 51ca0ef..2b0766c 100644 --- a/source/thread.h +++ b/source/thread.h @@ -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 +#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 index 0000000..7296689 --- /dev/null +++ b/source/types.h @@ -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 +#else +#include +#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 index 1635ea9..0000000 --- a/source/win32signum.h +++ /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 -- 2.43.0