root / omnithread / gnuradio / omnithread.h @ c48f42b5
History | View | Annotate | Download (18.7 kB)
| 1 | // -*- Mode: C++; -*-
|
|---|---|
| 2 | // Package : omnithread
|
| 3 | // omnithread.h Created : 7/94 tjr
|
| 4 | //
|
| 5 | // Copyright (C) 2006 Free Software Foundation, Inc.
|
| 6 | // Copyright (C) 1994,1995,1996, 1997 Olivetti & Oracle Research Laboratory
|
| 7 | //
|
| 8 | // This file is part of the omnithread library
|
| 9 | //
|
| 10 | // The omnithread library is free software; you can redistribute it and/or
|
| 11 | // modify it under the terms of the GNU Library General Public
|
| 12 | // License as published by the Free Software Foundation; either
|
| 13 | // version 2 of the License, or (at your option) any later version.
|
| 14 | //
|
| 15 | // This library is distributed in the hope that it will be useful,
|
| 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 18 | // Library General Public License for more details.
|
| 19 | //
|
| 20 | // You should have received a copy of the GNU Library General Public
|
| 21 | // License along with this library; if not, write to the Free
|
| 22 | // Software Foundation, Inc., 51 Franklin Street, Boston, MA
|
| 23 | // 02110-1301, USA
|
| 24 | //
|
| 25 | |
| 26 | //
|
| 27 | // Interface to OMNI thread abstraction.
|
| 28 | //
|
| 29 | // This file declares classes for threads and synchronisation objects
|
| 30 | // (mutexes, condition variables and counting semaphores).
|
| 31 | //
|
| 32 | // Wherever a seemingly arbitrary choice has had to be made as to the interface
|
| 33 | // provided, the intention here has been to be as POSIX-like as possible. This
|
| 34 | // is why there is no semaphore timed wait, for example.
|
| 35 | //
|
| 36 | |
| 37 | #ifndef __omnithread_h_
|
| 38 | #define __omnithread_h_
|
| 39 | |
| 40 | #ifndef NULL |
| 41 | #define NULL 0 |
| 42 | #endif
|
| 43 | |
| 44 | class omni_mutex; |
| 45 | class omni_condition; |
| 46 | class omni_semaphore; |
| 47 | class omni_thread; |
| 48 | |
| 49 | //
|
| 50 | // OMNI_THREAD_EXPOSE can be defined as public or protected to expose the
|
| 51 | // implementation class - this may be useful for debugging. Hopefully this
|
| 52 | // won't change the underlying structure which the compiler generates so that
|
| 53 | // this can work without recompiling the library.
|
| 54 | //
|
| 55 | |
| 56 | #ifndef OMNI_THREAD_EXPOSE
|
| 57 | #define OMNI_THREAD_EXPOSE private
|
| 58 | #endif
|
| 59 | |
| 60 | //
|
| 61 | // Include implementation-specific header file.
|
| 62 | //
|
| 63 | // This must define 4 CPP macros of the form OMNI_x_IMPLEMENTATION for mutex,
|
| 64 | // condition variable, semaphore and thread. Each should define any
|
| 65 | // implementation-specific members of the corresponding classes.
|
| 66 | //
|
| 67 | |
| 68 | |
| 69 | //
|
| 70 | // For now, we assume they've always got a Posix Threads implementation.
|
| 71 | // If not, it'll take some configure hacking to sort it out, along with
|
| 72 | // the relevant libraries to link with, etc.
|
| 73 | //
|
| 74 | |
| 75 | #if !defined(OMNITHREAD_POSIX) && !defined(OMNITHREAD_NT) && defined HAVE_CONFIG_H
|
| 76 | // #include <config.h> // No, No, No! Never include <config.h> from a header
|
| 77 | #endif
|
| 78 | |
| 79 | #if defined(OMNITHREAD_POSIX)
|
| 80 | #include <gnuradio/ot_posix.h> |
| 81 | |
| 82 | #elif defined(OMNITHREAD_NT)
|
| 83 | #include <gnuradio/ot_nt.h> |
| 84 | |
| 85 | #ifdef _MSC_VER
|
| 86 | |
| 87 | // Using MSVC++ to compile. If compiling library as a DLL,
|
| 88 | // define _OMNITHREAD_DLL. If compiling as a statuc library, define
|
| 89 | // _WINSTATIC
|
| 90 | // If compiling an application that is to be statically linked to omnithread,
|
| 91 | // define _WINSTATIC (if the application is to be dynamically linked,
|
| 92 | // there is no need to define any of these macros).
|
| 93 | |
| 94 | #if defined (_OMNITHREAD_DLL) && defined(_WINSTATIC)
|
| 95 | #error "Both _OMNITHREAD_DLL and _WINSTATIC are defined." |
| 96 | #elif defined(_OMNITHREAD_DLL)
|
| 97 | #define _OMNITHREAD_NTDLL_ __declspec(dllexport)
|
| 98 | #elif !defined(_WINSTATIC)
|
| 99 | #define _OMNITHREAD_NTDLL_ __declspec(dllimport)
|
| 100 | #elif defined(_WINSTATIC)
|
| 101 | #define _OMNITHREAD_NTDLL_
|
| 102 | #endif
|
| 103 | // _OMNITHREAD_DLL && _WINSTATIC
|
| 104 | |
| 105 | #else
|
| 106 | |
| 107 | // Not using MSVC++ to compile
|
| 108 | #define _OMNITHREAD_NTDLL_
|
| 109 | |
| 110 | #endif
|
| 111 | // _MSC_VER
|
| 112 | |
| 113 | #elif defined(__vxWorks__)
|
| 114 | #include <gnuradio/ot_VxThread.h> |
| 115 | |
| 116 | #elif defined(__sunos__)
|
| 117 | #if __OSVERSION__ != 5 |
| 118 | // XXX Workaround for SUN C++ compiler (seen on 4.2) Template.DB code
|
| 119 | // regeneration bug. See omniORB2/CORBA_sysdep.h for details.
|
| 120 | #if !defined(__SUNPRO_CC) || __OSVERSION__ != '5' |
| 121 | #error "Only SunOS 5.x or later is supported." |
| 122 | #endif
|
| 123 | #endif
|
| 124 | #ifdef UseSolarisThreads
|
| 125 | #include <gnuradio/ot_solaris.h> |
| 126 | #else
|
| 127 | #include <gnuradio/ot_posix.h> |
| 128 | #endif
|
| 129 | |
| 130 | #elif defined(__rtems__)
|
| 131 | #include <gnuradio/ot_posix.h> |
| 132 | #include <sched.h> |
| 133 | |
| 134 | #elif defined(__macos__)
|
| 135 | #include <gnuradio/ot_posix.h> |
| 136 | #include <sched.h> |
| 137 | |
| 138 | #else
|
| 139 | #error "No implementation header file" |
| 140 | #endif
|
| 141 | |
| 142 | |
| 143 | #if !defined(__WIN32__)
|
| 144 | #define _OMNITHREAD_NTDLL_
|
| 145 | #endif
|
| 146 | |
| 147 | #if (!defined(OMNI_MUTEX_IMPLEMENTATION) || \
|
| 148 | !defined(OMNI_MUTEX_LOCK_IMPLEMENTATION) || \ |
| 149 | !defined(OMNI_MUTEX_TRYLOCK_IMPLEMENTATION)|| \ |
| 150 | !defined(OMNI_MUTEX_UNLOCK_IMPLEMENTATION) || \ |
| 151 | !defined(OMNI_CONDITION_IMPLEMENTATION) || \ |
| 152 | !defined(OMNI_SEMAPHORE_IMPLEMENTATION) || \ |
| 153 | !defined(OMNI_THREAD_IMPLEMENTATION)) |
| 154 | #error "Implementation header file incomplete" |
| 155 | #endif
|
| 156 | |
| 157 | |
| 158 | //
|
| 159 | // This exception is thrown in the event of a fatal error.
|
| 160 | //
|
| 161 | |
| 162 | class _OMNITHREAD_NTDLL_ omni_thread_fatal {
|
| 163 | public:
|
| 164 | int error;
|
| 165 | omni_thread_fatal(int e = 0) : error(e) {} |
| 166 | }; |
| 167 | |
| 168 | |
| 169 | //
|
| 170 | // This exception is thrown when an operation is invoked with invalid
|
| 171 | // arguments.
|
| 172 | //
|
| 173 | |
| 174 | class _OMNITHREAD_NTDLL_ omni_thread_invalid {};
|
| 175 | |
| 176 | |
| 177 | ///////////////////////////////////////////////////////////////////////////
|
| 178 | //
|
| 179 | // Mutex
|
| 180 | //
|
| 181 | ///////////////////////////////////////////////////////////////////////////
|
| 182 | |
| 183 | class _OMNITHREAD_NTDLL_ omni_mutex {
|
| 184 | |
| 185 | public:
|
| 186 | omni_mutex(void);
|
| 187 | ~omni_mutex(void);
|
| 188 | |
| 189 | inline void lock(void) { OMNI_MUTEX_LOCK_IMPLEMENTATION } |
| 190 | inline void unlock(void) { OMNI_MUTEX_UNLOCK_IMPLEMENTATION } |
| 191 | inline int trylock(void) { return OMNI_MUTEX_TRYLOCK_IMPLEMENTATION } |
| 192 | // if mutex is unlocked, lock it and return 1 (true).
|
| 193 | // If it's already locked then return 0 (false).
|
| 194 | |
| 195 | inline void acquire(void) { lock(); } |
| 196 | inline void release(void) { unlock(); } |
| 197 | // the names lock and unlock are preferred over acquire and release
|
| 198 | // since we are attempting to be as POSIX-like as possible.
|
| 199 | |
| 200 | friend class omni_condition; |
| 201 | |
| 202 | private:
|
| 203 | // dummy copy constructor and operator= to prevent copying
|
| 204 | omni_mutex(const omni_mutex&);
|
| 205 | omni_mutex& operator=(const omni_mutex&);
|
| 206 | |
| 207 | OMNI_THREAD_EXPOSE:
|
| 208 | OMNI_MUTEX_IMPLEMENTATION |
| 209 | }; |
| 210 | |
| 211 | //
|
| 212 | // As an alternative to:
|
| 213 | // {
|
| 214 | // mutex.lock();
|
| 215 | // .....
|
| 216 | // mutex.unlock();
|
| 217 | // }
|
| 218 | //
|
| 219 | // you can use a single instance of the omni_mutex_lock class:
|
| 220 | //
|
| 221 | // {
|
| 222 | // omni_mutex_lock l(mutex);
|
| 223 | // ....
|
| 224 | // }
|
| 225 | //
|
| 226 | // This has the advantage that mutex.unlock() will be called automatically
|
| 227 | // when an exception is thrown.
|
| 228 | //
|
| 229 | |
| 230 | class _OMNITHREAD_NTDLL_ omni_mutex_lock {
|
| 231 | omni_mutex& mutex; |
| 232 | public:
|
| 233 | omni_mutex_lock(omni_mutex& m) : mutex(m) { mutex.lock(); }
|
| 234 | ~omni_mutex_lock(void) { mutex.unlock(); }
|
| 235 | private:
|
| 236 | // dummy copy constructor and operator= to prevent copying
|
| 237 | omni_mutex_lock(const omni_mutex_lock&);
|
| 238 | omni_mutex_lock& operator=(const omni_mutex_lock&);
|
| 239 | }; |
| 240 | |
| 241 | |
| 242 | ///////////////////////////////////////////////////////////////////////////
|
| 243 | //
|
| 244 | // Condition variable
|
| 245 | //
|
| 246 | ///////////////////////////////////////////////////////////////////////////
|
| 247 | |
| 248 | class _OMNITHREAD_NTDLL_ omni_condition {
|
| 249 | |
| 250 | omni_mutex* mutex; |
| 251 | |
| 252 | public:
|
| 253 | omni_condition(omni_mutex* m); |
| 254 | // constructor must be given a pointer to an existing mutex. The
|
| 255 | // condition variable is then linked to the mutex, so that there is an
|
| 256 | // implicit unlock and lock around wait() and timed_wait().
|
| 257 | |
| 258 | ~omni_condition(void);
|
| 259 | |
| 260 | void wait(void); |
| 261 | // wait for the condition variable to be signalled. The mutex is
|
| 262 | // implicitly released before waiting and locked again after waking up.
|
| 263 | // If wait() is called by multiple threads, a signal may wake up more
|
| 264 | // than one thread. See POSIX threads documentation for details.
|
| 265 | |
| 266 | int timedwait(unsigned long secs, unsigned long nanosecs = 0); |
| 267 | // timedwait() is given an absolute time to wait until. To wait for a
|
| 268 | // relative time from now, use omni_thread::get_time. See POSIX threads
|
| 269 | // documentation for why absolute times are better than relative.
|
| 270 | // Returns 1 (true) if successfully signalled, 0 (false) if time
|
| 271 | // expired.
|
| 272 | |
| 273 | void signal(void); |
| 274 | // if one or more threads have called wait(), signal wakes up at least
|
| 275 | // one of them, possibly more. See POSIX threads documentation for
|
| 276 | // details.
|
| 277 | |
| 278 | void broadcast(void); |
| 279 | // broadcast is like signal but wakes all threads which have called
|
| 280 | // wait().
|
| 281 | |
| 282 | private:
|
| 283 | // dummy copy constructor and operator= to prevent copying
|
| 284 | omni_condition(const omni_condition&);
|
| 285 | omni_condition& operator=(const omni_condition&);
|
| 286 | |
| 287 | OMNI_THREAD_EXPOSE:
|
| 288 | OMNI_CONDITION_IMPLEMENTATION |
| 289 | }; |
| 290 | |
| 291 | |
| 292 | ///////////////////////////////////////////////////////////////////////////
|
| 293 | //
|
| 294 | // Counting (or binary) semaphore
|
| 295 | //
|
| 296 | ///////////////////////////////////////////////////////////////////////////
|
| 297 | |
| 298 | class _OMNITHREAD_NTDLL_ omni_semaphore {
|
| 299 | |
| 300 | public:
|
| 301 | // if max_count == 1, you've got a binary semaphore.
|
| 302 | omni_semaphore(unsigned int initial = 1, unsigned int max_count = 0x7fffffff); |
| 303 | ~omni_semaphore(void);
|
| 304 | |
| 305 | void wait(void); |
| 306 | // if semaphore value is > 0 then decrement it and carry on. If it's
|
| 307 | // already 0 then block.
|
| 308 | |
| 309 | int trywait(void); |
| 310 | // if semaphore value is > 0 then decrement it and return 1 (true).
|
| 311 | // If it's already 0 then return 0 (false).
|
| 312 | |
| 313 | void post(void); |
| 314 | // if any threads are blocked in wait(), wake one of them up. Otherwise
|
| 315 | // increment the value of the semaphore.
|
| 316 | |
| 317 | private:
|
| 318 | // dummy copy constructor and operator= to prevent copying
|
| 319 | omni_semaphore(const omni_semaphore&);
|
| 320 | omni_semaphore& operator=(const omni_semaphore&);
|
| 321 | |
| 322 | OMNI_THREAD_EXPOSE:
|
| 323 | OMNI_SEMAPHORE_IMPLEMENTATION |
| 324 | }; |
| 325 | |
| 326 | //
|
| 327 | // A helper class for semaphores, similar to omni_mutex_lock above.
|
| 328 | //
|
| 329 | |
| 330 | class _OMNITHREAD_NTDLL_ omni_semaphore_lock {
|
| 331 | omni_semaphore& sem; |
| 332 | public:
|
| 333 | omni_semaphore_lock(omni_semaphore& s) : sem(s) { sem.wait(); }
|
| 334 | ~omni_semaphore_lock(void) { sem.post(); }
|
| 335 | private:
|
| 336 | // dummy copy constructor and operator= to prevent copying
|
| 337 | omni_semaphore_lock(const omni_semaphore_lock&);
|
| 338 | omni_semaphore_lock& operator=(const omni_semaphore_lock&);
|
| 339 | }; |
| 340 | |
| 341 | |
| 342 | ///////////////////////////////////////////////////////////////////////////
|
| 343 | //
|
| 344 | // Thread
|
| 345 | //
|
| 346 | ///////////////////////////////////////////////////////////////////////////
|
| 347 | |
| 348 | class _OMNITHREAD_NTDLL_ omni_thread {
|
| 349 | |
| 350 | public:
|
| 351 | |
| 352 | enum priority_t {
|
| 353 | PRIORITY_LOW, |
| 354 | PRIORITY_NORMAL, |
| 355 | PRIORITY_HIGH |
| 356 | }; |
| 357 | |
| 358 | enum state_t {
|
| 359 | STATE_NEW, // thread object exists but thread hasn't
|
| 360 | // started yet.
|
| 361 | STATE_RUNNING, // thread is running.
|
| 362 | STATE_TERMINATED // thread has terminated but storage has not
|
| 363 | // been reclaimed (i.e. waiting to be joined).
|
| 364 | }; |
| 365 | |
| 366 | //
|
| 367 | // Constructors set up the thread object but the thread won't start until
|
| 368 | // start() is called. The create method can be used to construct and start
|
| 369 | // a thread in a single call.
|
| 370 | //
|
| 371 | |
| 372 | omni_thread(void (*fn)(void*), void* arg = NULL, |
| 373 | priority_t pri = PRIORITY_NORMAL); |
| 374 | omni_thread(void* (*fn)(void*), void* arg = NULL, |
| 375 | priority_t pri = PRIORITY_NORMAL); |
| 376 | // these constructors create a thread which will run the given function
|
| 377 | // when start() is called. The thread will be detached if given a
|
| 378 | // function with void return type, undetached if given a function
|
| 379 | // returning void*. If a thread is detached, storage for the thread is
|
| 380 | // reclaimed automatically on termination. Only an undetached thread
|
| 381 | // can be joined.
|
| 382 | |
| 383 | void start(void); |
| 384 | // start() causes a thread created with one of the constructors to
|
| 385 | // start executing the appropriate function.
|
| 386 | |
| 387 | protected:
|
| 388 | |
| 389 | omni_thread(void* arg = NULL, priority_t pri = PRIORITY_NORMAL); |
| 390 | // this constructor is used in a derived class. The thread will
|
| 391 | // execute the run() or run_undetached() member functions depending on
|
| 392 | // whether start() or start_undetached() is called respectively.
|
| 393 | |
| 394 | public:
|
| 395 | |
| 396 | void start_undetached(void); |
| 397 | // can be used with the above constructor in a derived class to cause
|
| 398 | // the thread to be undetached. In this case the thread executes the
|
| 399 | // run_undetached member function.
|
| 400 | |
| 401 | protected:
|
| 402 | |
| 403 | virtual ~omni_thread(void);
|
| 404 | // destructor cannot be called by user (except via a derived class).
|
| 405 | // Use exit() or cancel() instead. This also means a thread object must
|
| 406 | // be allocated with new - it cannot be statically or automatically
|
| 407 | // allocated. The destructor of a class that inherits from omni_thread
|
| 408 | // shouldn't be public either (otherwise the thread object can be
|
| 409 | // destroyed while the underlying thread is still running).
|
| 410 | |
| 411 | public:
|
| 412 | |
| 413 | void join(void**); |
| 414 | // join causes the calling thread to wait for another's completion,
|
| 415 | // putting the return value in the variable of type void* whose address
|
| 416 | // is given (unless passed a null pointer). Only undetached threads
|
| 417 | // may be joined. Storage for the thread will be reclaimed.
|
| 418 | |
| 419 | void set_priority(priority_t);
|
| 420 | // set the priority of the thread.
|
| 421 | |
| 422 | static omni_thread* create(void (*fn)(void*), void* arg = NULL, |
| 423 | priority_t pri = PRIORITY_NORMAL); |
| 424 | static omni_thread* create(void* (*fn)(void*), void* arg = NULL, |
| 425 | priority_t pri = PRIORITY_NORMAL); |
| 426 | // create spawns a new thread executing the given function with the
|
| 427 | // given argument at the given priority. Returns a pointer to the
|
| 428 | // thread object. It simply constructs a new thread object then calls
|
| 429 | // start.
|
| 430 | |
| 431 | static void exit(void* return_value = NULL); |
| 432 | // causes the calling thread to terminate.
|
| 433 | |
| 434 | static omni_thread* self(void); |
| 435 | // returns the calling thread's omni_thread object. If the
|
| 436 | // calling thread is not the main thread and is not created
|
| 437 | // using this library, returns 0. (But see create_dummy()
|
| 438 | // below.)
|
| 439 | |
| 440 | static void yield(void); |
| 441 | // allows another thread to run.
|
| 442 | |
| 443 | static void sleep(unsigned long secs, unsigned long nanosecs = 0); |
| 444 | // sleeps for the given time.
|
| 445 | |
| 446 | static void get_time(unsigned long* abs_sec, unsigned long* abs_nsec, |
| 447 | unsigned long rel_sec = 0, unsigned long rel_nsec=0); |
| 448 | // calculates an absolute time in seconds and nanoseconds, suitable for
|
| 449 | // use in timed_waits on condition variables, which is the current time
|
| 450 | // plus the given relative offset.
|
| 451 | |
| 452 | |
| 453 | static void stacksize(unsigned long sz); |
| 454 | static unsigned long stacksize(); |
| 455 | // Use this value as the stack size when spawning a new thread.
|
| 456 | // The default value (0) means that the thread library default is
|
| 457 | // to be used.
|
| 458 | |
| 459 | |
| 460 | // Per-thread data
|
| 461 | //
|
| 462 | // These functions allow you to attach additional data to an
|
| 463 | // omni_thread. First allocate a key for yourself with
|
| 464 | // allocate_key(). Then you can store any object whose class is
|
| 465 | // derived from value_t. Any values still stored in the
|
| 466 | // omni_thread when the thread exits are deleted.
|
| 467 | //
|
| 468 | // These functions are NOT thread safe, so you should be very
|
| 469 | // careful about setting/getting data in a different thread to the
|
| 470 | // current thread.
|
| 471 | |
| 472 | typedef unsigned int key_t; |
| 473 | static key_t allocate_key();
|
| 474 | |
| 475 | class value_t {
|
| 476 | public:
|
| 477 | virtual ~value_t() {}
|
| 478 | }; |
| 479 | |
| 480 | value_t* set_value(key_t k, value_t* v); |
| 481 | // Sets a value associated with the given key. The key must
|
| 482 | // have been allocated with allocate_key(). If a value has
|
| 483 | // already been set with the specified key, the old value_t
|
| 484 | // object is deleted and replaced. Returns the value which was
|
| 485 | // set, or zero if the key is invalid.
|
| 486 | |
| 487 | value_t* get_value(key_t k); |
| 488 | // Returns the value associated with the key. If the key is
|
| 489 | // invalid, or there is no value for the key, returns zero.
|
| 490 | |
| 491 | value_t* remove_value(key_t k); |
| 492 | // Removes the value associated with the key and returns it.
|
| 493 | // If the key is invalid, or there is no value for the key,
|
| 494 | // returns zero.
|
| 495 | |
| 496 | |
| 497 | // Dummy omni_thread
|
| 498 | //
|
| 499 | // Sometimes, an application finds itself with threads created
|
| 500 | // outside of omnithread which must interact with omnithread
|
| 501 | // features such as the per-thread data. In this situation,
|
| 502 | // omni_thread::self() would normally return 0. These functions
|
| 503 | // allow the application to create a suitable dummy omni_thread
|
| 504 | // object.
|
| 505 | |
| 506 | static omni_thread* create_dummy(void); |
| 507 | // creates a dummy omni_thread for the calling thread. Future
|
| 508 | // calls to self() will return the dummy omni_thread. Throws
|
| 509 | // omni_thread_invalid if this thread already has an
|
| 510 | // associated omni_thread (real or dummy).
|
| 511 | |
| 512 | static void release_dummy(); |
| 513 | // release the dummy omni_thread for this thread. This
|
| 514 | // function MUST be called before the thread exits. Throws
|
| 515 | // omni_thread_invalid if the calling thread does not have a
|
| 516 | // dummy omni_thread.
|
| 517 | |
| 518 | // class ensure_self should be created on the stack. If created in
|
| 519 | // a thread without an associated omni_thread, it creates a dummy
|
| 520 | // thread which is released when the ensure_self object is deleted.
|
| 521 | |
| 522 | class ensure_self {
|
| 523 | public:
|
| 524 | inline ensure_self() : _dummy(0) |
| 525 | {
|
| 526 | _self = omni_thread::self(); |
| 527 | if (!_self) {
|
| 528 | _dummy = 1;
|
| 529 | _self = omni_thread::create_dummy(); |
| 530 | } |
| 531 | } |
| 532 | inline ~ensure_self()
|
| 533 | {
|
| 534 | if (_dummy)
|
| 535 | omni_thread::release_dummy(); |
| 536 | } |
| 537 | inline omni_thread* self() { return _self; } |
| 538 | private:
|
| 539 | omni_thread* _self; |
| 540 | int _dummy;
|
| 541 | }; |
| 542 | |
| 543 | |
| 544 | private:
|
| 545 | |
| 546 | virtual void run(void* /*arg*/) {} |
| 547 | virtual void* run_undetached(void* /*arg*/) { return NULL; } |
| 548 | // can be overridden in a derived class. When constructed using the
|
| 549 | // the constructor omni_thread(void*, priority_t), these functions are
|
| 550 | // called by start() and start_undetached() respectively.
|
| 551 | |
| 552 | void common_constructor(void* arg, priority_t pri, int det); |
| 553 | // implements the common parts of the constructors.
|
| 554 | |
| 555 | omni_mutex mutex; |
| 556 | // used to protect any members which can change after construction,
|
| 557 | // i.e. the following 2 members.
|
| 558 | |
| 559 | state_t _state; |
| 560 | priority_t _priority; |
| 561 | |
| 562 | static omni_mutex* next_id_mutex;
|
| 563 | static int next_id; |
| 564 | int _id;
|
| 565 | |
| 566 | void (*fn_void)(void*); |
| 567 | void* (*fn_ret)(void*); |
| 568 | void* thread_arg;
|
| 569 | int detached;
|
| 570 | int _dummy;
|
| 571 | value_t** _values; |
| 572 | unsigned long _value_alloc; |
| 573 | |
| 574 | omni_thread(const omni_thread&);
|
| 575 | omni_thread& operator=(const omni_thread&);
|
| 576 | // Not implemented
|
| 577 | |
| 578 | public:
|
| 579 | |
| 580 | priority_t priority(void) {
|
| 581 | |
| 582 | // return this thread's priority.
|
| 583 | |
| 584 | omni_mutex_lock l(mutex); |
| 585 | return _priority;
|
| 586 | } |
| 587 | |
| 588 | state_t state(void) {
|
| 589 | |
| 590 | // return thread state (invalid, new, running or terminated).
|
| 591 | |
| 592 | omni_mutex_lock l(mutex); |
| 593 | return _state;
|
| 594 | } |
| 595 | |
| 596 | int id(void) { return _id; } |
| 597 | // return unique thread id within the current process.
|
| 598 | |
| 599 | |
| 600 | // This class plus the instance of it declared below allows us to execute
|
| 601 | // some initialisation code before main() is called.
|
| 602 | |
| 603 | class _OMNITHREAD_NTDLL_ init_t {
|
| 604 | public:
|
| 605 | init_t(void);
|
| 606 | ~init_t(void);
|
| 607 | }; |
| 608 | |
| 609 | friend class init_t; |
| 610 | friend class omni_thread_dummy; |
| 611 | |
| 612 | OMNI_THREAD_EXPOSE:
|
| 613 | OMNI_THREAD_IMPLEMENTATION |
| 614 | }; |
| 615 | |
| 616 | #ifndef __rtems__
|
| 617 | static omni_thread::init_t omni_thread_init;
|
| 618 | #else
|
| 619 | // RTEMS calls global Ctor/Dtor in a context that is not
|
| 620 | // a posix thread. Calls to functions to pthread_self() in
|
| 621 | // that context returns NULL.
|
| 622 | // So, for RTEMS we will make the thread initialization at the
|
| 623 | // beginning of the Init task that has a posix context.
|
| 624 | #endif
|
| 625 | |
| 626 | #endif
|