1 /*
2  * Copyright (c) 2013, NVIDIA CORPORATION.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and/or associated documentation files (the
6  * "Materials"), to deal in the Materials without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Materials, and to
9  * permit persons to whom the Materials are furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included
13  * unaltered in all copies or substantial portions of the Materials.
14  * Any additions, deletions, or changes to the original source files
15  * must be clearly indicated in accompanying documentation.
16  *
17  * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23  * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
24  */
25 
26 #ifndef __GLVND_PTHREAD_H__
27 #define __GLVND_PTHREAD_H__
28 
29 #include <pthread.h>
30 #include <errno.h>
31 
32 /*
33  * pthread wrapper functions used to prevent the vendor-neutral library from
34  * needing to link against pthreads. The locking functions are no-ops unless
35  * the library is linked against pthreads.
36  * This wrapper code is also utilized by some unit tests which dynamically load
37  * pthreads.
38  */
39 
40 /*
41  * Since the underlying pthreads types are opaque, to correctly handle the
42  * single-threaded case we need to wrap some of these types with metadata.  For
43  * consistency, we typedef all pthreads types, including those which don't need
44  * to be wrapped.
45  */
46 typedef pthread_mutex_t glvnd_mutex_t;
47 typedef pthread_mutexattr_t glvnd_mutexattr_t;
48 
49 #if defined(HAVE_PTHREAD_RWLOCK_T)
50 typedef pthread_rwlock_t glvnd_rwlock_t;
51 typedef pthread_rwlockattr_t glvnd_rwlockattr_t;
52 #define GLVND_RWLOCK_INITIALIZER PTHREAD_RWLOCK_INITIALIZER
53 #else
54 typedef pthread_mutex_t glvnd_rwlock_t;
55 typedef pthread_mutexattr_t glvnd_rwlockattr_t;
56 #define GLVND_RWLOCK_INITIALIZER PTHREAD_MUTEX_INITIALIZER
57 #endif
58 
59 #define GLVND_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
60 
61 typedef struct _glvnd_once_t {
62     pthread_once_t once;
63     int done;
64 } glvnd_once_t;
65 
66 #define GLVND_ONCE_INIT { PTHREAD_ONCE_INIT, 0 }
67 
68 typedef struct _glvnd_thread_t {
69     pthread_t tid;
70     int valid;
71 } glvnd_thread_t;
72 
73 #define GLVND_THREAD_NULL_INIT {}
74 
75 typedef pthread_attr_t glvnd_thread_attr_t;
76 
77 typedef union {
78     pthread_key_t key;
79     void **data;
80 } glvnd_key_t;
81 #define GLVND_KEYS_MAX PTHREAD_KEYS_MAX
82 
83 /*!
84  * Struct defining the wrapper functions implemented by this library.
85  * The implementations will differ depending on whether we're in the
86  * singlethreaded case.
87  */
88 typedef struct GLVNDPthreadFuncsRec {
89     /* Should never be used by libglvnd. May be used by some unit tests */
90     int (*create)(glvnd_thread_t *thread, const glvnd_thread_attr_t *attr,
91                   void *(*start_routine) (void *), void *arg);
92     int (*join)(glvnd_thread_t thread, void **retval);
93 
94     /* Only used in debug/tracing code */
95     glvnd_thread_t (*self)(void);
96     int (*equal)(glvnd_thread_t t1, glvnd_thread_t t2);
97 
98     /* Locking primitives */
99     int (*mutex_init)(glvnd_mutex_t *mutex, const glvnd_mutexattr_t *attr);
100     int (*mutex_destroy)(glvnd_mutex_t *mutex);
101     int (*mutex_lock)(glvnd_mutex_t *mutex);
102     int (*mutex_trylock)(glvnd_mutex_t *mutex);
103     int (*mutex_unlock)(glvnd_mutex_t *mutex);
104 
105     int (* mutexattr_init) (glvnd_mutexattr_t *attr);
106     int (* mutexattr_destroy) (glvnd_mutexattr_t *attr);
107     int (* mutexattr_settype) (glvnd_mutexattr_t *attr, int kind);
108 
109     int (*rwlock_init)(glvnd_rwlock_t *rwlock, const glvnd_rwlockattr_t *attr);
110     int (*rwlock_destroy)(glvnd_rwlock_t *rwlock);
111     int (*rwlock_rdlock)(glvnd_rwlock_t *rwlock);
112     int (*rwlock_wrlock)(glvnd_rwlock_t *rwlock);
113     int (*rwlock_tryrdlock)(glvnd_rwlock_t *rwlock);
114     int (*rwlock_trywrlock)(glvnd_rwlock_t *rwlock);
115     int (*rwlock_unlock)(glvnd_rwlock_t *rwlock);
116 
117     /* Other used functions */
118     int (*once)(glvnd_once_t *once_control, void (*init_routine)(void));
119 
120     /*
121      * TSD key management.  Used to handle the corner case when a thread
122      * is destroyed with a context current.
123      */
124     int (*key_create)(glvnd_key_t *key, void (*destr_function)(void *));
125     int (*key_delete)(glvnd_key_t key);
126     int (*setspecific)(glvnd_key_t key, const void *p);
127     void *(*getspecific)(glvnd_key_t key);
128 
129     /*
130      * Are we single-threaded?
131      */
132     int is_singlethreaded;
133 } GLVNDPthreadFuncs;
134 
135 /**
136  * A NULL glvnd_thread_t value. This is mainly useful as something to pass to
137  * \c GLVNDPthreadFuncs.equal. To initialize a glvnd_thread_t variable, use
138  * \c GLVND_THREAD_NULL_INIT.
139  */
140 extern const glvnd_thread_t GLVND_THREAD_NULL;
141 
142 /**
143  * The function table with all of the pthreads function pointers. This table
144  * is initialized by \c glvndSetupPthreads.
145  */
146 extern GLVNDPthreadFuncs __glvndPthreadFuncs;
147 
148 /*!
149  * \brief Sets up pthreads wrappers.
150  *
151  * This fills the given function pointer table with the appropriate wrapper
152  * functions, using the passed-in handle to look for pthreads functions. This
153  * should only be called once on initialization.
154  */
155 void glvndSetupPthreads(void);
156 
157 
158 
159 #endif // __GLVND_PTHREAD_H__
160