1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3%                                                                             %
4%                                                                             %
5%                  TTTTT  H   H  RRRR   EEEEE   AAA   DDDD                    %
6%                    T    H   H  R   R  E      A   A  D   D                   %
7%                    T    HHHHH  RRRR   EEE    AAAAA  D   D                   %
8%                    T    H   H  R R    E      A   A  D   D                   %
9%                    T    H   H  R  R   EEEEE  A   A  DDDD                    %
10%                                                                             %
11%                                                                             %
12%                         MagickCore Thread Methods                           %
13%                                                                             %
14%                             Software Design                                 %
15%                                  Cristy                                     %
16%                               March  2003                                   %
17%                                                                             %
18%                                                                             %
19%  Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization      %
20%  dedicated to making software imaging solutions freely available.           %
21%                                                                             %
22%  You may not use this file except in compliance with the License.  You may  %
23%  obtain a copy of the License at                                            %
24%                                                                             %
25%    http://www.imagemagick.org/script/license.php                            %
26%                                                                             %
27%  Unless required by applicable law or agreed to in writing, software        %
28%  distributed under the License is distributed on an "AS IS" BASIS,          %
29%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
30%  See the License for the specific language governing permissions and        %
31%  limitations under the License.                                             %
32%                                                                             %
33%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
34%
35%
36*/
37
38/*
39  Include declarations.
40*/
41#include "MagickCore/studio.h"
42#include "MagickCore/memory_.h"
43#include "MagickCore/thread_.h"
44#include "MagickCore/thread-private.h"
45
46/*
47  Typedef declarations.
48*/
49typedef struct _MagickThreadValue
50{
51  size_t
52    number_threads;
53
54  void
55    **values,
56    (*destructor)(void *);
57} MagickThreadValue;
58
59/*
60%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
61%                                                                             %
62%                                                                             %
63%                                                                             %
64%   C r e a t e M a g i c k T h r e a d K e y                                 %
65%                                                                             %
66%                                                                             %
67%                                                                             %
68%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
69%
70%  CreateMagickThreadKey() creates a thread-specific data key visible to all
71%  threads in the process.
72%
73%  The format of the CreateMagickThreadKey method is:
74%
75%      MagickThreadKey CreateMagickThreadKey(MagickThreadKey *key)
76%
77%  A description of each parameter follows:
78%
79%    o key: opaque objects used to locate thread-specific data.
80%
81%    o destructor: associate an optional destructor with each key value.
82%
83*/
84MagickExport MagickBooleanType CreateMagickThreadKey(MagickThreadKey *key,
85  void (*destructor)(void *))
86{
87#if defined(MAGICKCORE_THREAD_SUPPORT)
88  return(pthread_key_create(key,destructor) == 0 ? MagickTrue : MagickFalse);
89#elif defined(MAGICKCORE_WINDOWS_SUPPORT)
90  magick_unreferenced(destructor);
91  *key=TlsAlloc();
92  return(*key != TLS_OUT_OF_INDEXES ? MagickTrue : MagickFalse);
93#else
94  {
95    MagickThreadValue
96      **keys;
97
98    keys=(MagickThreadValue **) key;
99    *keys=(MagickThreadValue *) AcquireQuantumMemory(1,sizeof(*keys));
100    if (*keys != (MagickThreadValue *) NULL)
101      {
102        (*keys)->number_threads=GetOpenMPMaximumThreads();
103        (*keys)->values=AcquireQuantumMemory((*keys)->number_threads,
104          sizeof(void *));
105        if ((*keys)->values == (void *) NULL)
106          *keys=RelinquishMagickMemory(*keys);
107        else
108          (void) memset((*keys)->values,0,(*keys)->number_threads*
109            sizeof(void *));
110        (*keys)->destructor=destructor;
111      }
112    return((*keys != (MagickThreadValue *) NULL) ? MagickTrue : MagickFalse);
113  }
114#endif
115}
116
117/*
118%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
119%                                                                             %
120%                                                                             %
121%                                                                             %
122%   D e l e t e M a g i c k T h r e a d K e y                                 %
123%                                                                             %
124%                                                                             %
125%                                                                             %
126%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
127%
128%  DeleteMagickThreadKey() deletes a thread-specific data key.
129%
130%  The format of the DeleteMagickThreadKey method is:
131%
132%      MagickBooleanType DeleteMagickThreadKey(MagickThreadKey key)
133%
134%  A description of each parameter follows:
135%
136%    o key: the thread key.
137%
138*/
139MagickExport MagickBooleanType DeleteMagickThreadKey(MagickThreadKey key)
140{
141#if defined(MAGICKCORE_THREAD_SUPPORT)
142  return(pthread_key_delete(key) == 0 ? MagickTrue : MagickFalse);
143#elif defined(MAGICKCORE_WINDOWS_SUPPORT)
144  return(TlsFree(key) != 0 ? MagickTrue : MagickFalse);
145#else
146  {
147    MagickThreadValue
148      *keys;
149
150    register ssize_t
151      i;
152
153    keys=(MagickThreadValue *) key;
154    for (i=0; i < (ssize_t) keys->number_threads; i++)
155      if ((keys->destructor != (void *) NULL) &&
156          (keys->values[i] != (void *) NULL))
157        {
158          keys->destructor(keys->values[i]);
159          keys->values[i]=(void *) NULL;
160        }
161    keys=(MagickThreadValue *) RelinquishMagickMemory(keys);
162  }
163  return(MagickTrue);
164#endif
165}
166
167/*
168%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
169%                                                                             %
170%                                                                             %
171%                                                                             %
172%   G e t M a g i c k T h r e a d V a l u e                                   %
173%                                                                             %
174%                                                                             %
175%                                                                             %
176%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
177%
178%  GetMagickThreadValue() returns the value currently bound to the specified
179%  key on behalf of the calling thread.
180%
181%  The format of the GetMagickThreadValue method is:
182%
183%      void *GetMagickThreadValue(MagickThreadKey key)
184%
185%  A description of each parameter follows:
186%
187%    o key: the thread key.
188%
189*/
190MagickExport void *GetMagickThreadValue(MagickThreadKey key)
191{
192#if defined(MAGICKCORE_THREAD_SUPPORT)
193  return(pthread_getspecific(key));
194#elif defined(MAGICKCORE_WINDOWS_SUPPORT)
195  return(TlsGetValue(key));
196#else
197  {
198    MagickThreadValue
199      *keys;
200
201    keys=(MagickThreadValue *) key;
202    return(keys->values[GetOpenMPThreadId()]);
203  }
204#endif
205}
206
207/*
208%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
209%                                                                             %
210%                                                                             %
211%                                                                             %
212%   S e t M a g i c k T h r e a d V a l u e                                   %
213%                                                                             %
214%                                                                             %
215%                                                                             %
216%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
217%
218%  SetMagickThreadValue() binds a value to the specified key on behalf of the
219%  calling thread.
220%
221%  The format of the SetMagickThreadValue method is:
222%
223%      MagickBooleanType SetMagickThreadValue(MagickThreadKey key,
224%        const void *value)
225%
226%  A description of each parameter follows:
227%
228%    o key: the thread key.
229%
230%    o value: the value.
231%
232*/
233MagickExport MagickBooleanType SetMagickThreadValue(MagickThreadKey key,
234  const void *value)
235{
236#if defined(MAGICKCORE_THREAD_SUPPORT)
237  return(pthread_setspecific(key,value) == 0 ? MagickTrue : MagickFalse);
238#elif defined(MAGICKCORE_WINDOWS_SUPPORT)
239  return(TlsSetValue(key,(void *) value) != 0 ? MagickTrue : MagickFalse);
240#else
241  {
242    MagickThreadValue
243      *keys;
244
245    keys=(MagickThreadValue *) key;
246    keys->values[GetOpenMPThreadId()]=(void *) value;
247  }
248  return(MagickTrue);
249#endif
250}
251