File: pthread_manager.h

package info (click to toggle)
libcds 2.3.3-6
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 15,632 kB
  • sloc: cpp: 135,002; ansic: 7,234; perl: 243; sh: 237; makefile: 6
file content (208 lines) | stat: -rw-r--r-- 7,124 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
// Copyright (c) 2006-2018 Maxim Khizhinsky
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)

#ifndef CDSLIB_THREADING_DETAILS_PTHREAD_MANAGER_H
#define CDSLIB_THREADING_DETAILS_PTHREAD_MANAGER_H

#include <system_error>
#include <stdio.h>
#include <pthread.h>
#include <cds/threading/details/_common.h>
#include <cds/details/throw_exception.h>

//@cond
namespace cds { namespace threading {

    /// cds::threading::Manager implementation based on pthread thread-specific data functions
    inline namespace pthread {

        /// Thread-specific data manager based on pthread thread-specific data functions
        /**
            Manager throws an exception of Manager::pthread_exception class if an error occurs
        */
        class Manager {
        private :
            /// pthread error code type
            typedef int pthread_error_code;

            /// pthread exception
            class pthread_exception: public std::system_error
            {
            public:
                /// Exception constructor
                pthread_exception( int nCode, const char * pszFunction )
                    : std::system_error( nCode, std::system_category(), pszFunction )
                {}
            };

            /// pthread TLS key holder
            struct Holder {
            //@cond
                static pthread_key_t   m_key;

                static void key_destructor(void * p)
                {
                    if ( p ) {
                        reinterpret_cast<ThreadData *>(p)->fini();
                        delete reinterpret_cast<ThreadData *>(p);
                    }
                }

                static void init()
                {
                    pthread_error_code  nErr;
                    if ( ( nErr = pthread_key_create( &m_key, key_destructor )) != 0 )
                        CDS_THROW_EXCEPTION( pthread_exception( nErr, "pthread_key_create" ));
                }

                static void fini()
                {
                    pthread_error_code  nErr;
                    if ( ( nErr = pthread_key_delete( m_key )) != 0 )
                        CDS_THROW_EXCEPTION( pthread_exception( nErr, "pthread_key_delete" ));
                }

                static ThreadData *    get()
                {
                    return reinterpret_cast<ThreadData *>( pthread_getspecific( m_key ));
                }

                static void alloc()
                {
                    pthread_error_code  nErr;
                    ThreadData * pData = new ThreadData;
                    if ( ( nErr = pthread_setspecific( m_key, pData )) != 0 )
                        CDS_THROW_EXCEPTION( pthread_exception( nErr, "pthread_setspecific" ));
                }
                static void free()
                {
                    ThreadData * p = get();
                    pthread_setspecific( m_key, nullptr );
                    delete p;
                }
            //@endcond
            };

            //@cond
            enum EThreadAction {
                do_getData,
                do_attachThread,
                do_detachThread,
                do_checkData,
                init_holder,
                fini_holder
            };
            //@endcond

            //@cond
            static ThreadData * _threadData( EThreadAction nAction )
            {
                switch ( nAction ) {
                    case do_getData:
                        return Holder::get();
                    case do_checkData:
                        return Holder::get();
                    case do_attachThread:
                        if ( Holder::get() == nullptr )
                            Holder::alloc();
                        return Holder::get();
                    case do_detachThread:
                        Holder::free();
                        return nullptr;
                    case init_holder:
                    case fini_holder:
                        break;
                    default:
                        assert( false ) ;   // anything forgotten?..
                }
                assert(false)   ;   // how did we get here?
                return nullptr;
            }
            //@endcond

        public:
            /// Initialize manager
            /**
                This function is automatically called by cds::Initialize
            */
            static void init()
            {
                Holder::init();
            }

            /// Terminate manager
            /**
                This function is automatically called by cds::Terminate
            */
            static void fini()
            {
                Holder::fini();
            }

            /// Checks whether current thread is attached to \p libcds feature or not.
            static bool isThreadAttached()
            {
                return _threadData( do_checkData ) != nullptr;
            }

            /// This method must be called in beginning of thread execution
            /**
                If TLS pointer to manager's data is \p nullptr, pthread_exception is thrown
                with code = -1.
                If an error occurs in call of pthread API function, pthread_exception is thrown
                with pthread error code.
            */
            static void attachThread()
            {
                ThreadData * pData = _threadData( do_attachThread );
                assert( pData );

                if ( pData ) {
                    pData->init();
                }
                else
                    CDS_THROW_EXCEPTION( pthread_exception( -1, "cds::threading::pthread::Manager::attachThread" ));
            }

            /// This method must be called in end of thread execution
            /**
                If TLS pointer to manager's data is \p nullptr, pthread_exception is thrown
                with code = -1.
                If an error occurs in call of pthread API function, pthread_exception is thrown
                with pthread error code.
            */
            static void detachThread()
            {
                ThreadData * pData = _threadData( do_getData );
                assert( pData );

                if ( pData ) {
                    if ( pData->fini())
                        _threadData( do_detachThread );
                }
                else
                    CDS_THROW_EXCEPTION( pthread_exception( -1, "cds::threading::pthread::Manager::detachThread" ));
            }

            /// Returns ThreadData pointer for the current thread
            static ThreadData * thread_data()
            {
                return _threadData( do_getData );
            }

            //@cond
            static size_t fake_current_processor()
            {
                return _threadData( do_getData )->fake_current_processor();
            }
            //@endcond

        };

    } // namespace pthread
}} // namespace cds::threading
//@endcond

#endif // #ifndef CDSLIB_THREADING_DETAILS_PTHREAD_MANAGER_H