source: XMLIO_V2/external/src/POCO/Foundation.save/Thread_POSIX.cpp @ 80

Last change on this file since 80 was 80, checked in by ymipsl, 14 years ago

ajout lib externe

  • Property svn:eol-style set to native
File size: 10.2 KB
Line 
1//
2// Thread_POSIX.cpp
3//
4// $Id: //poco/1.3/Foundation/src/Thread_POSIX.cpp#15 $
5//
6// Library: Foundation
7// Package: Threading
8// Module:  Thread
9//
10// Copyright (c) 2004-2007, Applied Informatics Software Engineering GmbH.
11// and Contributors.
12//
13// Permission is hereby granted, free of charge, to any person or organization
14// obtaining a copy of the software and accompanying documentation covered by
15// this license (the "Software") to use, reproduce, display, distribute,
16// execute, and transmit the Software, and to prepare derivative works of the
17// Software, and to permit third-parties to whom the Software is furnished to
18// do so, all subject to the following:
19//
20// The copyright notices in the Software and this entire statement, including
21// the above license grant, this restriction and the following disclaimer,
22// must be included in all copies of the Software, in whole or in part, and
23// all derivative works of the Software, unless such copies or derivative
24// works are solely in the form of machine-executable object code generated by
25// a source language processor.
26//
27// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
30// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
31// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
32// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
33// DEALINGS IN THE SOFTWARE.
34//
35
36
37#include "Poco/Thread_POSIX.h"
38#include "Poco/Exception.h"
39#include "Poco/ErrorHandler.h"
40#include "Poco/Timespan.h"
41#include "Poco/Timestamp.h"
42#include <signal.h>
43#if defined(__sun) && defined(__SVR4)
44#       if !defined(__EXTENSIONS__)
45#               define __EXTENSIONS__
46#       endif
47#endif
48#if POCO_OS == POCO_OS_LINUX || POCO_OS == POCO_OS_MAC_OS_X || POCO_OS == POCO_OS_QNX
49#       include <time.h>
50#endif
51
52//
53// Block SIGPIPE in main thread.
54//
55#if defined(POCO_OS_FAMILY_UNIX)
56namespace
57{
58        class SignalBlocker
59        {
60        public:
61                SignalBlocker()
62                {
63                        sigset_t sset;
64                        sigemptyset(&sset);
65                        sigaddset(&sset, SIGPIPE); 
66                        pthread_sigmask(SIG_BLOCK, &sset, 0);
67                }
68                ~SignalBlocker()
69                {
70                }
71        };
72       
73        static SignalBlocker signalBlocker;
74}
75#endif
76
77
78namespace Poco {
79
80
81ThreadImpl::CurrentThreadHolder ThreadImpl::_currentThreadHolder;
82
83
84ThreadImpl::ThreadImpl():
85        _pData(new ThreadData)
86{
87}
88
89                       
90ThreadImpl::~ThreadImpl()
91{
92        if (isRunningImpl())
93                pthread_detach(_pData->thread);
94}
95
96
97void ThreadImpl::setPriorityImpl(int prio)
98{
99        if (prio != _pData->prio)
100        {
101                _pData->prio = prio;
102                if (isRunningImpl())
103                {
104                        struct sched_param par;
105                        par.sched_priority = mapPrio(_pData->prio);
106                        if (pthread_setschedparam(_pData->thread, SCHED_OTHER, &par))
107                                throw SystemException("cannot set thread priority");
108                }
109        }
110}
111
112
113void ThreadImpl::setOSPriorityImpl(int prio)
114{
115        if (prio != _pData->osPrio)
116        {
117                if (_pData->pRunnableTarget || _pData->pCallbackTarget)
118                {
119                        struct sched_param par;
120                        par.sched_priority = prio;
121                        if (pthread_setschedparam(_pData->thread, SCHED_OTHER, &par))
122                                throw SystemException("cannot set thread priority");
123                }
124                _pData->prio   = reverseMapPrio(prio);
125                _pData->osPrio = prio;
126        }
127}
128
129
130int ThreadImpl::getMinOSPriorityImpl()
131{
132#if defined(__VMS) || defined(__digital__)
133        return PRI_OTHER_MIN;
134#else
135        return sched_get_priority_min(SCHED_OTHER);
136#endif
137}
138
139
140int ThreadImpl::getMaxOSPriorityImpl()
141{
142#if defined(__VMS) || defined(__digital__)
143        return PRI_OTHER_MAX;
144#else
145        return sched_get_priority_max(SCHED_OTHER);
146#endif
147}
148
149
150void ThreadImpl::setStackSizeImpl(int size)
151{
152#ifndef PTHREAD_STACK_MIN
153        _pData->stackSize = 0;
154#else
155        if (size != 0)
156        {
157#if defined(__APPLE__)
158                // we must round up to a multiple of the memory page size
159                const int PAGE_SIZE = 4096;
160                size = ((size + PAGE_SIZE - 1)/PAGE_SIZE)*PAGE_SIZE;
161#endif
162                if (size < PTHREAD_STACK_MIN)
163                        size = PTHREAD_STACK_MIN;
164        }
165        _pData->stackSize = size;
166#endif
167}
168
169
170void ThreadImpl::startImpl(Runnable& target)
171{
172        if (_pData->pRunnableTarget)
173                throw SystemException("thread already running");
174
175        pthread_attr_t attributes;
176        pthread_attr_init(&attributes);
177
178        if (_pData->stackSize != 0)
179        {
180                if (0 != pthread_attr_setstacksize(&attributes, _pData->stackSize))
181                        throw SystemException("cannot set thread stack size");
182        }
183
184        _pData->pRunnableTarget = &target;
185        if (pthread_create(&_pData->thread, &attributes, runnableEntry, this))
186        {
187                _pData->pRunnableTarget = 0;
188                throw SystemException("cannot start thread");
189        }
190
191        if (_pData->prio != PRIO_NORMAL_IMPL)
192        {
193                struct sched_param par;
194                par.sched_priority = mapPrio(_pData->prio);
195                if (pthread_setschedparam(_pData->thread, SCHED_OTHER, &par))
196                        throw SystemException("cannot set thread priority");
197        }
198}
199
200
201void ThreadImpl::startImpl(Callable target, void* pData)
202{
203        if (_pData->pCallbackTarget && _pData->pCallbackTarget->callback)
204                throw SystemException("thread already running");
205
206        pthread_attr_t attributes;
207        pthread_attr_init(&attributes);
208
209        if (_pData->stackSize != 0)
210        {
211                if (0 != pthread_attr_setstacksize(&attributes, _pData->stackSize))
212                        throw SystemException("can not set thread stack size");
213        }
214
215        if (0 == _pData->pCallbackTarget.get())
216                _pData->pCallbackTarget = new CallbackData;
217
218        _pData->pCallbackTarget->callback = target;
219        _pData->pCallbackTarget->pData = pData;
220
221        if (pthread_create(&_pData->thread, &attributes, callableEntry, this))
222        {
223                _pData->pCallbackTarget->callback = 0;
224                _pData->pCallbackTarget->pData = 0;
225                throw SystemException("cannot start thread");
226        }
227
228        if (_pData->prio != PRIO_NORMAL_IMPL)
229        {
230                struct sched_param par;
231                par.sched_priority = mapPrio(_pData->prio);
232                if (pthread_setschedparam(_pData->thread, SCHED_OTHER, &par))
233                        throw SystemException("cannot set thread priority");
234        }
235}
236
237
238void ThreadImpl::joinImpl()
239{
240        _pData->done.wait();
241        void* result;
242        if (pthread_join(_pData->thread, &result))
243                throw SystemException("cannot join thread"); 
244}
245
246
247bool ThreadImpl::joinImpl(long milliseconds)
248{
249        if (_pData->done.tryWait(milliseconds))
250        {
251                void* result;
252                if (pthread_join(_pData->thread, &result))
253                        throw SystemException("cannot join thread");
254                return true;
255        }
256        else return false;
257}
258
259
260ThreadImpl* ThreadImpl::currentImpl()
261{
262        return _currentThreadHolder.get();
263}
264
265
266ThreadImpl::TIDImpl ThreadImpl::currentTidImpl()
267{
268    return pthread_self();
269}
270
271
272void ThreadImpl::sleepImpl(long milliseconds)
273{
274#if defined(__VMS) || defined(__digital__)
275                // This is specific to DECThreads
276                struct timespec interval;
277                interval.tv_sec  = milliseconds / 1000;
278                interval.tv_nsec = (milliseconds % 1000)*1000000; 
279                pthread_delay_np(&interval);
280#elif POCO_OS == POCO_OS_LINUX || POCO_OS == POCO_OS_MAC_OS_X || POCO_OS == POCO_OS_QNX
281        Poco::Timespan remainingTime(1000*Poco::Timespan::TimeDiff(milliseconds));
282        int rc;
283        do
284        {
285                struct timespec ts;
286                ts.tv_sec  = (long) remainingTime.totalSeconds();
287                ts.tv_nsec = (long) remainingTime.useconds()*1000;
288                Poco::Timestamp start;
289                rc = ::nanosleep(&ts, 0);
290                if (rc < 0 && errno == EINTR)
291                {
292                        Poco::Timestamp end;
293                        Poco::Timespan waited = start.elapsed();
294                        if (waited < remainingTime)
295                                remainingTime -= waited;
296                        else
297                                remainingTime = 0;
298                }
299        }
300        while (remainingTime > 0 && rc < 0 && errno == EINTR);
301        if (rc < 0 && remainingTime > 0) throw Poco::SystemException("Thread::sleep(): nanosleep() failed");
302#else
303        Poco::Timespan remainingTime(1000*Poco::Timespan::TimeDiff(milliseconds));
304        int rc;
305        do
306        {
307                struct timeval tv;
308                tv.tv_sec  = (long) remainingTime.totalSeconds();
309                tv.tv_usec = (long) remainingTime.useconds();
310                Poco::Timestamp start;
311                rc = ::select(0, NULL, NULL, NULL, &tv);
312                if (rc < 0 && errno == EINTR)
313                {
314                        Poco::Timestamp end;
315                        Poco::Timespan waited = start.elapsed();
316                        if (waited < remainingTime)
317                                remainingTime -= waited;
318                        else
319                                remainingTime = 0;
320                }
321        }
322        while (remainingTime > 0 && rc < 0 && errno == EINTR);
323        if (rc < 0 && remainingTime > 0) throw Poco::SystemException("Thread::sleep(): select() failed");
324#endif
325}
326
327
328void* ThreadImpl::runnableEntry(void* pThread)
329{
330        _currentThreadHolder.set(reinterpret_cast<ThreadImpl*>(pThread));
331
332#if defined(POCO_OS_FAMILY_UNIX)
333        sigset_t sset;
334        sigemptyset(&sset);
335        sigaddset(&sset, SIGQUIT);
336        sigaddset(&sset, SIGTERM);
337        sigaddset(&sset, SIGPIPE); 
338        pthread_sigmask(SIG_BLOCK, &sset, 0);
339#endif
340
341        ThreadImpl* pThreadImpl = reinterpret_cast<ThreadImpl*>(pThread);
342        AutoPtr<ThreadData> pData = pThreadImpl->_pData;
343        try
344        {
345                pData->pRunnableTarget->run();
346        }
347        catch (Exception& exc)
348        {
349                ErrorHandler::handle(exc);
350        }
351        catch (std::exception& exc)
352        {
353                ErrorHandler::handle(exc);
354        }
355        catch (...)
356        {
357                ErrorHandler::handle();
358        }
359
360        pData->pRunnableTarget = 0;
361        pData->done.set();
362        return 0;
363}
364
365
366void* ThreadImpl::callableEntry(void* pThread)
367{
368        _currentThreadHolder.set(reinterpret_cast<ThreadImpl*>(pThread));
369
370#if defined(POCO_OS_FAMILY_UNIX)
371        sigset_t sset;
372        sigemptyset(&sset);
373        sigaddset(&sset, SIGQUIT);
374        sigaddset(&sset, SIGTERM);
375        sigaddset(&sset, SIGPIPE); 
376        pthread_sigmask(SIG_BLOCK, &sset, 0);
377#endif
378
379        ThreadImpl* pThreadImpl = reinterpret_cast<ThreadImpl*>(pThread);
380        AutoPtr<ThreadData> pData = pThreadImpl->_pData;
381        try
382        {
383                pData->pCallbackTarget->callback(pData->pCallbackTarget->pData);
384        }
385        catch (Exception& exc)
386        {
387                ErrorHandler::handle(exc);
388        }
389        catch (std::exception& exc)
390        {
391                ErrorHandler::handle(exc);
392        }
393        catch (...)
394        {
395                ErrorHandler::handle();
396        }
397
398        pData->pCallbackTarget->callback = 0;
399        pData->pCallbackTarget->pData = 0;
400
401        pData->done.set();
402        return 0;
403}
404
405
406int ThreadImpl::mapPrio(int prio)
407{
408        int pmin = getMinOSPriorityImpl();
409        int pmax = getMaxOSPriorityImpl();
410
411        switch (prio)
412        {
413        case PRIO_LOWEST_IMPL:
414                return pmin;
415        case PRIO_LOW_IMPL:
416                return pmin + (pmax - pmin)/4;
417        case PRIO_NORMAL_IMPL:
418                return pmin + (pmax - pmin)/2;
419        case PRIO_HIGH_IMPL:
420                return pmin + 3*(pmax - pmin)/4;
421        case PRIO_HIGHEST_IMPL:
422                return pmax;
423        default:
424                poco_bugcheck_msg("invalid thread priority");
425        }
426        return -1; // just to satisfy compiler - we'll never get here anyway
427}
428
429
430int ThreadImpl::reverseMapPrio(int prio)
431{
432        int pmin = getMinOSPriorityImpl();
433        int pmax = getMaxOSPriorityImpl();
434        int normal = pmin + (pmax - pmin)/2;
435        if (prio == pmax)
436                return PRIO_HIGHEST_IMPL;
437        if (prio > normal)
438                return PRIO_HIGH_IMPL;
439        else if (prio == normal)
440                return PRIO_NORMAL_IMPL;
441        else if (prio > pmin)
442                return PRIO_LOW_IMPL;
443        else
444                return PRIO_LOWEST_IMPL;
445}
446
447
448} // namespace Poco
Note: See TracBrowser for help on using the repository browser.