root/trunk/dep/src/zthread/ThreadImpl.cxx @ 2

Revision 2, 11.6 kB (checked in by yumileroy, 17 years ago)

[svn] * Proper SVN structure

Original author: Neo2003
Date: 2008-10-02 16:23:55-05:00

Line 
1/*
2 * Copyright (c) 2005, Eric Crahen
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is furnished
9 * to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in all
12 * copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 *
21 */
22
23#include "Debug.h"
24
25#include "zthread/Runnable.h"
26#include "ThreadImpl.h"
27#include "ThreadQueue.h"
28#include "DeferredInterruptionScope.h"
29
30#include <assert.h>
31
32namespace ZThread {
33
34  TSS<ThreadImpl*> ThreadImpl::_threadMap;
35
36  namespace {
37 
38    class Launcher : public Runnable {
39     
40      ThreadImpl* x;
41      ThreadImpl* y;
42      Task z;
43     
44    public:
45     
46      Launcher(ThreadImpl* a, ThreadImpl* b, const Task& c) : x(a), y(b), z(c) {}
47     
48      void run() {     
49        y->dispatch(x,y,z);     
50      }
51           
52    };
53   
54  }
55
56  ThreadImpl::ThreadImpl()
57    : _state(State::REFERENCE), _priority(Medium), _autoCancel(false) {
58   
59    ZTDEBUG("Reference thread created.\n");
60   
61  }
62
63  ThreadImpl::ThreadImpl(const Task& task, bool autoCancel)
64    : _state(State::IDLE), _priority(Medium), _autoCancel(autoCancel) {
65   
66    ZTDEBUG("User thread created.\n");
67
68    start(task);
69
70  }
71 
72 
73  ThreadImpl::~ThreadImpl() {
74   
75    _tls.clear();
76
77    if(isActive()) {
78     
79      ZTDEBUG("You are destroying an executing thread!\n");
80      abort();
81     
82    }
83   
84    ZTDEBUG("Thread destroyed.\n");
85   
86  }
87 
88  Monitor& ThreadImpl::getMonitor() {
89    return _monitor;
90  }
91 
92  void ThreadImpl::cancel(bool autoCancel) {
93    if(!autoCancel || _autoCancel)
94      _monitor.cancel();
95  }
96 
97  bool ThreadImpl::interrupt() {
98    return _monitor.interrupt();
99  }
100 
101  bool ThreadImpl::isInterrupted() {
102    return _monitor.isInterrupted();
103  }
104 
105  bool ThreadImpl::isCanceled() {
106    return _monitor.isCanceled();
107  }
108
109  Priority ThreadImpl::getPriority() const {
110    return _priority; 
111  }
112 
113 
114
115  bool ThreadImpl::isReference() {
116    return _state.isReference();
117  }
118 
119  /**
120   * Join the thread, blocking the caller until it is interrupted or until
121   * the thread represented by this object exits.
122   *
123   * Reference threads are not under the control of ZThreads and cannot be
124   * joined.
125   */
126  bool ThreadImpl::join(unsigned long timeout) {
127     
128    // Serial access to this ThreadImpl's state
129    Guard<Monitor> g1(_monitor);
130 
131    // Make sure a thread is not trying to join() itself.
132    if(ThreadOps::isCurrent(this))
133      throw Deadlock_Exception("Cannot join self.");
134   
135    // Reference threads can't be joined.
136    if(_state.isReference())
137      throw InvalidOp_Exception("Can not join this thread.");
138   
139    /* 
140       
141    TODO: Insert cyclic join check.
142   
143    */
144   
145    // If the task has not completed yet, wait for completion
146    if(!_state.isJoined()) {
147     
148      // Add the current thread to the joiner list
149      ThreadImpl* impl = current();
150      _joiners.push_back(impl);
151
152      Monitor::STATE result;
153
154      { // Release this ThreadImpl's lock while the joiner sleeps
155
156        _monitor.release(); 
157        Guard<Monitor> g3(impl->getMonitor());
158 
159        result = impl->_monitor.wait(timeout);
160 
161        _monitor.acquire();
162         
163      }
164       
165      // Update the joiner list
166      List::iterator i = std::find(_joiners.begin(), _joiners.end(), impl);
167      if(i != _joiners.end())
168        _joiners.erase(i);
169     
170     
171      switch(result) {
172       
173        case Monitor::TIMEDOUT:
174          return false;
175         
176        case Monitor::INTERRUPTED:
177          throw Interrupted_Exception();
178         
179        default:
180          break;
181         
182      }
183     
184    }
185
186    return true;
187   
188  }
189 
190
191  /**
192   * Translate the priority into a pthread value, and update the thread priority.
193   *
194   * This is not available on all platforms, and probably works differently
195   * the platforms that do support it. Pthreads does not have very portable
196   * priority support as far I am aware.
197   *
198   * If SCHED_OTHER is not supported priority values are still set but 
199   * dont not actually in affect anything.
200   *
201   * @param prio PRIORITY value
202   *
203   * @exception Killed_Exception thrown by KILLED threads.
204   * @exception InvalidOp_Exception thrown by IDLE, JOINING or JOINED threads.
205   */
206  void ThreadImpl::setPriority(Priority p) {
207   
208    Guard<Monitor> g(_monitor);
209   
210    // Only set the native priority when the thread is running
211    if(_state.isRunning())
212      ThreadOps::setPriority(this, p);
213   
214    _priority = p;
215   
216  }
217 
218 
219  /**
220   * Test the state Monitor of this thread to determine if the thread
221   * is an active thread created by zthreads.
222   *
223   * @return bool indicating the activity of the thread.
224   */
225  bool ThreadImpl::isActive() {
226   
227    Guard<Monitor> g(_monitor);
228    return _state.isRunning();
229   
230  }
231 
232 
233  /**
234   * Get a reference to an implmenetation that maps to the current thread.
235   * Accomplished by checking the TLS map. This will always return a valid
236   * ThreadImpl instance.
237   *
238   * @return ThreadImpl* current implementation that maps to the
239   * executing thread.
240   */
241  ThreadImpl* ThreadImpl::current() {
242   
243    // Get the ThreadImpl previously mapped onto the executing thread.
244    ThreadImpl* impl = _threadMap.get();
245   
246    // Create a reference thread for any threads that have been 'discovered'
247    // because they are not created by ZThreads.
248    if(impl == 0) {
249     
250      // Create a ThreadImpl to represent this thread.
251      impl = new ThreadImpl();
252      impl->_state.setReference();
253     
254      ThreadOps::activate(impl);
255     
256      // Map a reference thread and insert it into the queue
257      _threadMap.set(impl);
258     
259      ThreadQueue::instance()->insertReferenceThread(impl);
260     
261    }
262   
263    assert(impl != 0);
264    return impl;
265   
266  }
267 
268  /**
269   * Make current thread sleep for the given number of milliseconds.
270   * This sleep can be interrupt()ed.
271   *
272   * @param ms timeout for the sleep.
273   *
274   * @post the calling thread is blocked by waiting on the internal condition
275   * variable. This can be signaled in the monitor of an interrupt
276   */
277  void ThreadImpl::sleep(unsigned long ms) {
278   
279    // Make sleep()ing for 0 milliseconds equivalent to a yield.
280    if(ms == 0) {
281     
282      yield();
283      return;
284     
285    }
286   
287    // Get the monitor for the current thread
288    Monitor& monitor = current()->getMonitor();
289   
290    // Acquire that threads Monitor with a Guard
291    Guard<Monitor> g(monitor);
292   
293    for(;;) {
294     
295      switch(monitor.wait(ms)) {
296       
297        case Monitor::INTERRUPTED:
298          throw Interrupted_Exception();
299         
300        default:
301          return;
302         
303      }
304     
305    }
306   
307  }
308 
309 
310  /**
311   * Yield the current timeslice to another thread.
312   * If sched_yield() is available it is used.
313   * Otherwise, the state Monitor for this thread is used to simiulate a
314   * yield by blocking for 1  millisecond, which should give the
315   * scheduler a chance to schedule another thread.
316   */
317  void ThreadImpl::yield() {
318   
319    // Try to yield with the native operation. If it fails, then
320    // simulate with a short wait() on the monitor.
321    if(!ThreadOps::yield()) {
322     
323      // Get the monitor for the current thread
324      Monitor& monitor = current()->getMonitor();
325     
326      // Attempt a wait().
327      Guard<Monitor> g(monitor);   
328      monitor.wait(1);
329     
330    }
331   
332  }
333
334  void ThreadImpl::start(const Task& task) {
335
336    Guard<Monitor> g1(_monitor);
337
338    // A Thread must be idle in order to be eligable to run a task.
339    if(!_state.isIdle())
340      throw InvalidOp_Exception("Thread is not idle.");
341 
342    _state.setRunning();
343 
344    // Spawn a new thread, blocking the parent (current) thread until
345    // the child starts.
346
347    ThreadImpl* parent = current();
348    Launcher launch(parent, this, task);
349
350    // Attempt to start the child thread
351    Guard<Monitor> g2(parent->_monitor);
352
353    if(!spawn(&launch)) {
354
355      // Return to the idle state & report the error if it doesn't work out.
356      _state.setIdle();   
357      throw Synchronization_Exception();   
358
359
360    }
361
362    // Wait, uninterruptably, for the child's signal. The parent thread
363    // still can be interrupted and killed; it just won't take effect
364    // until the child has started.
365
366    Guard<Monitor, DeferredInterruptionScope> g3(parent->_monitor);
367
368    if(parent->_monitor.wait() != Monitor::SIGNALED) {
369      assert(0);
370    }
371 
372
373  }
374
375
376  void ThreadImpl::dispatch(ThreadImpl* parent, ThreadImpl* impl, Task task) {
377
378    // Map the implementation object onto the running thread.
379    _threadMap.set(impl);
380
381    // Update the reference count on a ThreadImpl before the 'Thread'
382    // that owns it can go out of scope (by signaling the parent)
383    impl->addReference();
384
385    // Update the priority of the thread
386    if(parent->_state.isReference())
387      ThreadOps::setPriority(impl,
388                             parent->_state.isReference() ? impl->_priority : parent->_priority);
389
390    // Inherit ThreadLocal values from the parent
391    typedef ThreadLocalMap::const_iterator It;
392
393    for(It i = parent->getThreadLocalMap().begin(); i != parent->getThreadLocalMap().end(); ++i)
394      if( (i->second)->isInheritable() )
395        impl->getThreadLocalMap()[ i->first ] = (i->second)->clone();
396   
397    // Insert a user-thread mapping
398    ThreadQueue::instance()->insertUserThread(impl);
399    // Wake the parent once the thread is setup
400    parent->_monitor.notify();
401
402    ZTDEBUG("Thread starting...\n");
403
404    // not catch exceptions, let program terminate
405    //try {
406   
407      task->run();
408
409    //} catch(...) {
410
411      // Result of running a task that threw an exception.
412    //  ZTDEBUG("The task has thrown an unhandled exception\n");
413          //assert(0); // UQ1: Go to debugger...
414   
415    //}
416
417    ZTDEBUG("Thread joining...\n");
418   
419    { // Update the state of the thread
420   
421      Guard<Monitor> g(impl->_monitor);
422      impl->_state.setJoined();
423   
424      // Wake the joiners that will be easy to join first
425      for(List::iterator i = impl->_joiners.begin(); i != impl->_joiners.end();) {
426     
427        ThreadImpl* joiner = *i;
428        Monitor& m = joiner->getMonitor();
429
430        if(m.tryAcquire()) {
431 
432          m.notify();
433          m.release();   
434       
435          i = impl->_joiners.erase(i);
436
437        } else
438          ++i;
439
440      }
441
442      // Wake the joiners that might take a while next
443      for(List::iterator i = impl->_joiners.begin(); i != impl->_joiners.end(); ++i) {
444     
445        ThreadImpl* joiner = *i;
446        Monitor& m = joiner->getMonitor();
447
448        m.acquire();
449        m.notify();
450        m.release();   
451       
452      }
453     
454    }
455
456    ZTDEBUG("Thread exiting...\n");
457
458    // Insert a pending-thread mapping, allowing the resources to be reclaimed
459    ThreadQueue::instance()->insertPendingThread(impl);
460
461    // Cleanup ThreadLocal values
462    impl->getThreadLocalMap().clear();
463
464    // Update the reference count allowing it to be destroyed
465    impl->delReference();
466
467  }
468
469
470} // namespace ZThread
Note: See TracBrowser for help on using the browser.