BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bslmt_threadutilimpl_pthread.h
Go to the documentation of this file.
1/// @file bslmt_threadutilimpl_pthread.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bslmt_threadutilimpl_pthread.h -*-C++-*-
8#ifndef INCLUDED_BSLMT_THREADUTILIMPL_PTHREAD
9#define INCLUDED_BSLMT_THREADUTILIMPL_PTHREAD
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bslmt_threadutilimpl_pthread bslmt_threadutilimpl_pthread
15/// @brief Provide a POSIX implementation of `bslmt::ThreadUtil`.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bslmt
19/// @{
20/// @addtogroup bslmt_threadutilimpl_pthread
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bslmt_threadutilimpl_pthread-purpose"> Purpose</a>
25/// * <a href="#bslmt_threadutilimpl_pthread-classes"> Classes </a>
26/// * <a href="#bslmt_threadutilimpl_pthread-description"> Description </a>
27/// * <a href="#bslmt_threadutilimpl_pthread-supported-clock-types"> Supported Clock-Types </a>
28/// * <a href="#bslmt_threadutilimpl_pthread-usage"> Usage </a>
29///
30/// # Purpose {#bslmt_threadutilimpl_pthread-purpose}
31/// Provide a POSIX implementation of `bslmt::ThreadUtil`.
32///
33/// # Classes {#bslmt_threadutilimpl_pthread-classes}
34///
35/// - bslmt::ThreadUtilImpl<PosixThreads>: POSIX specialization
36///
37/// @see bslmt_threadutil
38///
39/// # Description {#bslmt_threadutilimpl_pthread-description}
40/// This component provides an implementation of
41/// `bslmt::ThreadUtil` for POSIX threads ("pthreads"),
42/// `bslmt::ThreadUtilImpl<PosixThreads>`, via the template specialization:
43/// @code
44/// bslmt::ThreadUtilImpl<Platform::PosixThreads>
45/// @endcode
46/// This template class should not be used (directly) by client code. Clients
47/// should instead use `bslmt::ThreadUtil`.
48///
49/// ## Supported Clock-Types {#bslmt_threadutilimpl_pthread-supported-clock-types}
50///
51///
52/// `bsls::SystemClockType` supplies the enumeration indicating the system clock
53/// on which timeouts supplied to other methods should be based. If the clock
54/// type indicated at construction is `bsls::SystemClockType::e_REALTIME`, the
55/// `absTime` argument passed to the `timedWait` method of the various
56/// synchronization primitives offered in `bslmt` should be expressed as an
57/// *absolute* offset since 00:00:00 UTC, January 1, 1970 (which matches the
58/// epoch used in `bsls::SystemTime::now(bsls::SystemClockType::e_REALTIME)`.
59/// If the clock type indicated at construction is
60/// `bsls::SystemClockType::e_MONOTONIC`, the `absTime` argument passed to the
61/// `timedWait` method of the various synchronization primitives offered in
62/// `bslmt` should be expressed as an *absolute* offset since the epoch of this
63/// clock (which matches the epoch used in
64/// `bsls::SystemTime::now(bsls::SystemClockType::e_MONOTONIC)`.
65///
66/// ## Usage {#bslmt_threadutilimpl_pthread-usage}
67///
68///
69/// This component is an implementation detail of `bslmt` and is *not* intended
70/// for direct client use. It is subject to change without notice. As such, a
71/// usage example is not provided.
72/// @}
73/** @} */
74/** @} */
75
76/** @addtogroup bsl
77 * @{
78 */
79/** @addtogroup bslmt
80 * @{
81 */
82/** @addtogroup bslmt_threadutilimpl_pthread
83 * @{
84 */
85
86#include <bslscm_version.h>
87
88#include <bslmt_platform.h>
89
90#ifdef BSLMT_PLATFORM_POSIX_THREADS
91
92// Platform-specific implementation starts here.
93
95
96#include <bsls_platform.h>
98#include <bsls_timeinterval.h>
99#include <bsls_types.h>
100
101#include <bsl_string.h>
102
103#include <pthread.h>
104
105#ifdef BSLS_PLATFORM_OS_LINUX
106#include <sys/syscall.h>
107#include <unistd.h>
108#endif
109
110#ifdef BSLS_PLATFORM_OS_SOLARIS
111#include <thread.h>
112#endif
113
114
115
116extern "C" {
117 /// `bslmt_ThreadFunction` is an alias for a function type taking a
118 /// single `void` pointer argument and returning `void *`. Such
119 /// functions are suitable to be specified as thread entry point
120 /// functions to `bslmt::ThreadUtil::create`.
121 typedef void *(*bslmt_ThreadFunction)(void *);
122
123 /// `bslmt_KeyDestructorFunction` is an alias for a function type taking
124 /// a single `void` pointer argument and returning `void`. Such
125 /// functions are suitable to be specified as thread-specific key
126 /// destructor functions to `bslmt::ThreadUtil::createKey`.
127 typedef void (*bslmt_KeyDestructorFunction)(void *);
128}
129
130namespace bslmt {
131
132template <class THREAD_POLICY>
133struct ThreadUtilImpl;
134
135 // ============================================
136 // class ThreadUtilImpl<Platform::PosixThreads>
137 // ============================================
138
139/// This class provides a full specialization of `ThreadUtilImpl` for
140/// pthreads.
141template <>
142struct ThreadUtilImpl<Platform::PosixThreads> {
143
144 // TYPES
145 typedef pthread_t Handle; // thread handle type
146 typedef pthread_t NativeHandle; // native thread handle type
147 typedef pthread_t Id; // thread Id type
148 typedef pthread_key_t Key; // thread-specific storage key type
149
150 // CLASS DATA
151 static const pthread_t INVALID_HANDLE;
152
153 // CLASS METHODS
154 // *** Thread Management ***
155
156 /// Create a new thread of program control having the specified
157 /// `attributes` that invokes the specified `function` with a single
158 /// argument specified by `userData`, and load into the specified
159 /// `threadHandle` an identifier that may be used to refer to the thread
160 /// in future calls to this utility. Return 0 on success, and a non-zero value otherwise.
161 ///
162 /// \pre The behavior is undefined if the
163 /// specified `thread` is 0 or if `attributes.stackSize()` has been set to a negative value other than the unset value.
164 ///
165 /// \note Note that unless
166 /// explicitly "detached" (by `detach`), or unless the
167 /// `BSLMT_CREATE_DETACHED` attribute is specified, a call to `join`
168 /// must be made once the thread terminates to reclaim any system
169 /// resources associated with the newly created identifier.
170 static int create(Handle *threadHandle,
171 const ThreadAttributes& attributes,
172 bslmt_ThreadFunction function,
173 void *userData);
174
175 /// Create a new thread of program control having platform specific
176 /// default attributes (i.e., "stack size", "scheduling priority"), that
177 /// invokes the specified `function` with a single argument specified by
178 /// `userData`, and load into the specified `threadHandle`, an
179 /// identifier that may be used to refer to the thread in future calls
180 /// to this utility. Return 0 on success, and a non-zero value otherwise.
181 ///
182 /// \pre The behavior is undefined if the `threadHandle` is 0.
183 ///
184 /// \note Note that unless explicitly "detached" (`detach`), a call to `join`
185 /// must be made once the thread terminates to reclaim any system
186 /// resources associated with the newly created identifier.
187 static int create(Handle *threadHandle,
188 bslmt_ThreadFunction function,
189 void *userData);
190
191 /// "Detach" the thread identified by the specified `threadHandle`, such
192 /// that when it terminates, the resources associated the thread will automatically be reclaimed.
193 ///
194 /// \note Note that once a thread is "detached",
195 /// it is no longer possible to `join` the thread to retrieve the its
196 /// exit status.
197 static int detach(Handle& threadHandle);
198
199 /// Exit the current thread and return the specified `status`. If the
200 /// current thread is not "detached", then a call to `join` must be made
201 /// to reclaim any resources used by the thread, and to retrieve the exit status.
202 ///
203 /// \note Note that generally, the preferred method of exiting a
204 /// thread is to return form the entry point function.
205 static void exit(void *status);
206
207 /// Return the maximum available priority for the specified `policy`,
208 /// where `policy` is of type `ThreadAttributes::SchedulingPolicy`.
209 /// Return `ThreadAttributes::BSLMT_UNSET_PRIORITY` if the maximum scheduling priority cannot be determined.
210 ///
211 /// \note Note that, for some
212 /// platform / policy combinations, `getMinSchedulingPriority(policy)`
213 /// and `getMaxSchedulingPriority(policy)` return the same value.
214 static int getMaxSchedulingPriority(
216
217 /// Return the minimum available priority for the specified `policy`,
218 /// where `policy` is of type `ThreadAttributes::SchedulingPolicy`.
219 /// Return `ThreadAttributes::BSLMT_UNSET_PRIORITY` if the minimum scheduling priority cannot be determined.
220 ///
221 /// \note Note that, for some
222 /// platform / policy combinations, `getMinSchedulingPriority(policy)`
223 /// and `getMaxSchedulingPriority(policy)` return the same value.
224 static int getMinSchedulingPriority(
226
227 /// Load the name of the current thread into the specified `threadName`.
228 ///
229 /// \note Note that this method clears `*threadName` on all platforms other
230 /// than Linux and Darwin.
231 static void getThreadName(bsl::string *threadName);
232
233 /// Suspend execution of the current thread until the thread specified
234 /// by `threadHandle` terminates, and reclaim any system resources
235 /// associated with the `threadHandle`. Return 0 on success, and a
236 /// non-zero value otherwise. If the optionally specified `status` is
237 /// not 0, load into the `status` the value returned by the specified
238 /// `thread`.
239 static int join(Handle& threadHandle, void **status = (void**)0);
240
241 /// Suspend execution of the current thread for a period of at least the
242 /// optionally specified `seconds` and `microseconds` (relative time),
243 /// and optionally load into the optionally specified `unsleptTime` the
244 /// amount of time that was not slept by this function if the operation
245 /// was interrupted by a signal. Return 0 on success, and non-zero if the operation was interrupted by a signal.
246 ///
247 /// \note Note that the actual
248 /// time suspended depends on many factors including system scheduling, and system timer resolution.
249 ///
250 /// \note Note that the actual time suspended
251 /// depends on many factors including system scheduling, and system
252 /// timer resolution.
253 static int microSleep(int microseconds,
254 int seconds = 0,
255 bsls::TimeInterval *unsleptTime = 0);
256
257 /// Set the name of the current thread to the specified `threadName`.
258 /// On all platforms other than Linux and Darwin this method has no effect.
259 ///
260 /// \note Note that on those two platforms `threadName` will be
261 /// truncated to a length of 15 bytes, not including the terminating
262 /// '\0'.
263 static void setThreadName(const bslstl::StringRef& threadName);
264
265 /// Suspend execution of the current thread for a period of at least the
266 /// specified `sleepTime` (relative time), and optionally load into the
267 /// optionally specified `unsleptTime` the amount of time that was not
268 /// slept by this function if the operation was interrupted by a signal.
269 /// Return 0 on success, and a non-zero value if the operation was interrupted by a signal.
270 ///
271 /// \note Note that the actual time suspended
272 /// depends on many factors including system scheduling, and system
273 /// timer resolution.
274 static int sleep(const bsls::TimeInterval& sleepTime,
275 bsls::TimeInterval *unsleptTime = 0);
276
277 /// Suspend execution of the current thread until the specified
278 /// `absoluteTime`. Optionally specify `clockType` which determines the
279 /// epoch from which the interval `absoluteTime` is measured (see
280 /// {Supported Clock-Types} in the component documentation). Return 0
281 /// on success, and a non-zero value otherwise.
282 ///
283 /// \pre The behavior is undefined unless `absoluteTime` represents a time after January 1,
284 /// 1970 and before the end of December 31, 9999 (i.e., a time interval
285 /// greater than or equal to 0, and less than 253,402,300,800 seconds).
286 ///
287 /// \note Note that the actual time suspended depends on many factors
288 /// including system scheduling and system timer resolution.
289 static int sleepUntil(const bsls::TimeInterval& absoluteTime,
292
293 /// Suspend execution of the current thread until the specified
294 /// `absoluteTime`. Optionally specify `retryOnSignalInterrupt`
295 /// indicating whether to put this thread to sleep again if the
296 /// operating system interrupts the sleep because of a signal.
297 /// Optionally specify `clockType` which determines the epoch from which
298 /// the interval `absoluteTime` is measured (see {Supported
299 /// Clock-Types} in the component documentation). Return 0 on success,
300 /// and a non-zero value otherwise. If `retryOnSignalInterrupt` is
301 /// `true`, an interrupt from a signal will be ignored and the current
302 /// the thread will be put back to sleep until `absoluteTime`, otherwise
303 /// this call will return 0 to the calling thread immediately.
304 ///
305 /// \pre The behavior is undefined unless `absoluteTime` represents a time after
306 /// January 1, 1970 and before the end of December 31, 9999 (i.e., a
307 /// time interval greater than or equal to 0, and less than 253,402,300,800 seconds).
308 ///
309 /// \note Note that the actual time suspended
310 /// depends on many factors including system scheduling and system timer
311 /// resolution.
312 static int sleepUntil(const bsls::TimeInterval& absoluteTime,
313 bool retryOnSignalInterrupt
314 = false,
317
318 /// Put the current thread to the end of the scheduler's queue and
319 /// schedule another thread to run. This allows cooperating threads of
320 /// the same priority to share CPU resources equally.
321 static void yield();
322
323 // *** Thread Identification ***
324
325 /// Return `true` if the specified `a` and `b` thread handles, identify
326 /// the same thread, and `false` otherwise.
327 static bool areEqual(const Handle& a, const Handle& b);
328
329 /// Return `true` if the specified `a` and `b` thread id identify the
330 /// same thread, and `false` otherwise.
331 static bool areEqualId(const Id& a, const Id& b);
332
333 /// Return the unique integral identifier of a thread uniquely
334 /// identified by the specified `threadId` within the current process.
335 ///
336 /// \note Note that this representation is particularly useful for logging
337 /// purposes. Also note that this value is only valid until the thread
338 /// terminates and may be reused thereafter.
339 static bsls::Types::Uint64 idAsUint64(const Id& threadId);
340
341 /// Return the unique integral identifier of a thread uniquely
342 /// identified by the specified `threadId` within the current process.
343 ///
344 /// \note Note that this representation is particularly useful for logging
345 /// purposes. Also note that this value is only valid until the thread
346 /// terminates and may be reused thereafter.
347 ///
348 /// DEPRECATED: use `idAsUint64`.
349 static int idAsInt(const Id& threadId);
350
351 /// Return the platform specific identifier associated with the thread specified by `threadHandle`.
352 ///
353 /// \note Note that the returned native handle
354 /// may not be a globally unique identifier for the thread (see
355 /// `selfIdAsUint`).
356 static NativeHandle nativeHandle(const Handle& threadHandle);
357
358 /// Return an identifier that can be used to refer to the current thread
359 /// in future calls to this utility.
360 static Handle self();
361
362 /// Return an identifier that can be used to uniquely identify the current thread within the current process.
363 ///
364 /// \note Note that the id is only
365 /// valid until the thread terminates and may be reused thereafter.
366 static Id selfId();
367
368 /// Return an integeral identifier that can be used to uniquely identify
369 /// the current thread within the current process. This representation is particularly useful for logging purposes.
370 ///
371 /// \note Note that this value is only
372 /// valid until the thread terminates and may be reused thereafter.
373 ///
374 /// DEPRECATED: Use `selfIdAsUint64` instead.
375 static bsls::Types::Uint64 selfIdAsInt();
376
377 /// Return an integral identifier that can be used to uniquely identify the
378 /// current thread within the current process. This representation is particularly useful for logging purposes.
379 ///
380 /// \note Note that this value is only
381 /// valid until the thread terminates and may be reused thereafter.
382 static bsls::Types::Uint64 selfIdAsUint64();
383
384 /// Return an integral identifier of the current thread used by the operating system.
385 ///
386 /// \note Note that kernel thread ID is different from the
387 /// user-space thread ID returned by `selfIdAsUint64()`.
388 /// \note Note that this
389 /// value is only valid until the thread terminates and may be reused
390 /// thereafter.
391 static bsls::Types::Uint64 selfKernelIdAsUint64();
392
393 /// Return the unique identifier of the thread having the specified `threadHandle` within the current process.
394 ///
395 /// \note Note that this value is
396 /// only valid until the thread terminates and may be reused thereafter.
397 static Id handleToId(const Handle& threadHandle);
398
399 // *** Thread-Specific (Local) Storage (TSS or TLS) ***
400
401 /// Load, into the specified `key`, an identifier that can be used to
402 /// store (`setSpecific`) and retrieve (`getSpecific`) a single
403 /// thread-specific pointer value. Associate with the identifier, the
404 /// specified `destructor` if a non-zero value is specified. Return 0
405 /// on success, and a non-zero value otherwise.
406 static int createKey(Key *key, bslmt_KeyDestructorFunction destructor);
407
408 /// Delete the specified thread-specific `key`. Return 0 on success, and a non-zero value otherwise.
409 ///
410 /// \note Note that deleting a key does not
411 /// delete any data that is currently associated with the key in the
412 /// calling thread or any other thread.
413 static int deleteKey(Key& key);
414
415 /// Return the value associated with the specified thread-specific `key`.
416 ///
417 /// \note Note that if the key is not valid, a value of zero is
418 /// returned, which is indistinguishable from a valid key with a 0
419 /// value.
420 static void *getSpecific(const Key& key);
421
422 /// Associate the specified `value` with the specified thread-specific
423 /// `key`. Return 0 on success, and a non-zero value otherwise. TBD
424 /// elaborate on what `value` represents
425 static int setSpecific(const Key& key, const void *value);
426
427 /// Return the number of concurrent threads supported by the
428 /// implementation on success, and 0 otherwise.
429 static unsigned int hardwareConcurrency();
430};
431
432// ============================================================================
433// INLINE DEFINITIONS
434// ============================================================================
435
436 // --------------------------------------------
437 // class ThreadUtilImpl<Platform::PosixThreads>
438 // --------------------------------------------
439
440// CLASS METHODS
441 // *** Thread Management ***
442inline
443int ThreadUtilImpl<bslmt::Platform::PosixThreads>::create(
444 Handle *threadHandle,
445 bslmt_ThreadFunction function,
446 void *userData)
447{
448 ThreadAttributes attr;
449 return create(threadHandle, attr, function, userData);
450}
451
452inline
453int ThreadUtilImpl<bslmt::Platform::PosixThreads>::detach(Handle& threadHandle)
454{
455 return pthread_detach(threadHandle);
456}
457
458inline
459void ThreadUtilImpl<bslmt::Platform::PosixThreads>::exit(void *status)
460{
461 pthread_exit(status);
462}
463
464inline
465int ThreadUtilImpl<bslmt::Platform::PosixThreads>::join(Handle& threadHandle,
466 void **status)
467{
468 return pthread_join(threadHandle, status);
469}
470
471inline
472int ThreadUtilImpl<bslmt::Platform::PosixThreads>::sleepUntil(
473 const bsls::TimeInterval& absoluteTime,
475{
476 return sleepUntil(absoluteTime, false, clockType);
477}
478
479inline
480void ThreadUtilImpl<bslmt::Platform::PosixThreads>::yield()
481{
482 sched_yield();
483}
484
485 // *** Thread Identification ***
486
487inline
488bool ThreadUtilImpl<bslmt::Platform::PosixThreads>::areEqual(const Handle& a,
489 const Handle& b)
490{
491 return pthread_equal(a, b);
492}
493
494inline
495bool ThreadUtilImpl<bslmt::Platform::PosixThreads>::areEqualId(const Id& a,
496 const Id& b)
497{
498 return pthread_equal(a, b);
499}
500
501inline
502ThreadUtilImpl<bslmt::Platform::PosixThreads>::Id
503ThreadUtilImpl<bslmt::Platform::PosixThreads>::handleToId(
504 const Handle& threadHandle)
505{
506 return threadHandle;
507}
508
509inline
511ThreadUtilImpl<bslmt::Platform::PosixThreads>::idAsUint64(const Id& threadId)
512{
513#ifdef BSLS_PLATFORM_OS_DARWIN
514 return reinterpret_cast<bsls::Types::Uint64>(threadId);
515#else
516 return static_cast<bsls::Types::Uint64>(threadId);
517#endif
518}
519
520inline
521int
522ThreadUtilImpl<bslmt::Platform::PosixThreads>::idAsInt(const Id& threadId)
523{
524 // Our interface is not good if the id is a pointer. The two casts will
525 // avoid a compilation error though. TBD
526
527 return static_cast<int>(idAsUint64(threadId));
528}
529
530inline
531ThreadUtilImpl<bslmt::Platform::PosixThreads>::NativeHandle
532ThreadUtilImpl<bslmt::Platform::PosixThreads>::nativeHandle(
533 const Handle& threadHandle)
534{
535 return threadHandle;
536}
537
538inline
539ThreadUtilImpl<bslmt::Platform::PosixThreads>::Handle
540ThreadUtilImpl<bslmt::Platform::PosixThreads>::self()
541{
542 return pthread_self();
543}
544
545inline
546ThreadUtilImpl<bslmt::Platform::PosixThreads>::Id
547ThreadUtilImpl<bslmt::Platform::PosixThreads>::selfId()
548{
549 return pthread_self();
550}
551
552inline
554ThreadUtilImpl<bslmt::Platform::PosixThreads>::selfIdAsInt()
555{
556 return idAsInt(selfId());
557}
558
559inline
561ThreadUtilImpl<bslmt::Platform::PosixThreads>::selfIdAsUint64()
562{
563 return idAsUint64(selfId());
564}
565
566inline
568ThreadUtilImpl<bslmt::Platform::PosixThreads>::selfKernelIdAsUint64()
569{
570#if defined(BSLS_PLATFORM_OS_LINUX)
571 return static_cast<bsls::Types::Uint64>(syscall(SYS_gettid));
572#elif defined(BSLS_PLATFORM_OS_SOLARIS)
573 return static_cast<bsls::Types::Uint64>(thr_self());
574#else
575 return selfIdAsUint64();
576#endif
577}
578
579 // *** Thread-Specific (Local) Storage (TSS or TLS) ***
580
581inline
582int ThreadUtilImpl<bslmt::Platform::PosixThreads>::createKey(
583 Key *key,
585{
586 return pthread_key_create(key,destructor);
587}
588
589inline
590int ThreadUtilImpl<bslmt::Platform::PosixThreads>::deleteKey(Key& key)
591{
592 return pthread_key_delete(key);
593}
594
595inline
596void *ThreadUtilImpl<bslmt::Platform::PosixThreads>::getSpecific(
597 const Key& key)
598{
599 return pthread_getspecific(key);
600}
601
602inline
603int ThreadUtilImpl<bslmt::Platform::PosixThreads>::setSpecific(
604 const Key& key,
605 const void *value)
606{
607 return pthread_setspecific(key, value);
608}
609
610} // close package namespace
611
612
613#endif // BSLMT_PLATFORM_POSIX_THREADS
614
615#endif
616
617// ----------------------------------------------------------------------------
618// Copyright 2015 Bloomberg Finance L.P.
619//
620// Licensed under the Apache License, Version 2.0 (the "License");
621// you may not use this file except in compliance with the License.
622// You may obtain a copy of the License at
623//
624// http://www.apache.org/licenses/LICENSE-2.0
625//
626// Unless required by applicable law or agreed to in writing, software
627// distributed under the License is distributed on an "AS IS" BASIS,
628// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
629// See the License for the specific language governing permissions and
630// limitations under the License.
631// ----------------------------- END-OF-FILE ----------------------------------
632
633/** @} */
634/** @} */
635/** @} */
Definition bslstl_string.h:1252
SchedulingPolicy
Definition bslmt_threadattributes.h:381
Definition bsls_timeinterval.h:307
Definition bslstl_stringref.h:374
void(* bslmt_KeyDestructorFunction)(void *)
Definition bslmt_threadutil.h:363
void *(* bslmt_ThreadFunction)(void *)
Definition bslmt_threadutil.h:357
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
Definition bslmt_barrier.h:344
Enum
Definition bsls_systemclocktype.h:119
@ e_REALTIME
Definition bsls_systemclocktype.h:122
unsigned long long Uint64
Definition bsls_types.h:139