1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5/*=============================================================================
6**
7** Source: tls.c
8**
9** Purpose: Test to ensure TlsAlloc, TlsGetValue, TlsSetValue
10** and TlsFree are working properly together.
11**
12** Dependencies: PAL_Initialize
13** Fail
14** Sleep
15** LocalAlloc
16** LocalFree
17** WaitForSingleObject
18** CreateThread
19** GetLastError
20**
21
22**
23**===========================================================================*/
24#include <palsuite.h>
25
26#define NUM_OF_THREADS 10
27
28DWORD dwTlsIndex; /* TLS index */
29
30/**
31 * CommonFunction
32 *
33 * Helper function that calls TlsGetValue
34 */
35VOID CommonFunction(VOID)
36{
37 LPVOID lpvData;
38 DWORD dwError;
39
40 /* Retrieve a data pointer for the current thread. */
41 lpvData = TlsGetValue(dwTlsIndex);
42
43 if ( (lpvData == 0) &&
44 ((dwError = GetLastError()) != NO_ERROR) )
45 {/*ERROR */
46 Fail("TlsGetValue(%d) returned 0 with error %d\n",
47 dwTlsIndex,
48 dwError);
49 }
50
51 Sleep(5000);
52}
53
54/**
55 * ThreadFunc
56 *
57 * Thread function that stores a value in the thread's tls slot
58 * for the predefined tls index
59 */
60DWORD PALAPI ThreadFunc(LPVOID lpThreadParameter)
61{
62 LPVOID lpvData;
63 DWORD dwError;
64
65 /* Initialize the TLS index for this thread.*/
66 lpvData = (LPVOID) LocalAlloc(0, 256);
67
68 if( lpvData == NULL )
69 {/*ERROR */
70 dwError = GetLastError();
71 Fail("Unexpected LocalAlloc(0, 256) failure with error %d\n",
72 dwError);
73 }
74
75
76 if ( TlsSetValue(dwTlsIndex, lpvData) == 0 )
77 {/*ERROR */
78 dwError = GetLastError();
79 Fail("TlsSetValue(%d, %x) returned 0 with error %d\n",
80 dwTlsIndex,
81 lpvData,
82 dwError);
83 }
84
85 CommonFunction();
86
87 /* Release the dynamic memory. */
88 lpvData = TlsGetValue(dwTlsIndex);
89
90 if ( (lpvData == 0) &&
91 ((dwError = GetLastError()) != NO_ERROR) )
92 {/*ERROR */
93 Fail("TlsGetValue(%d) returned 0 with error %d\n",
94 dwTlsIndex,
95 dwError);
96 }
97 else
98 {
99 if( LocalFree((HLOCAL) lpvData) != NULL )
100 {
101 dwError = GetLastError();
102 Fail("Unexpected LocalFree(%x) failure with error %d\n",
103 lpvData,
104 dwError);
105 }
106 }
107
108 return PASS;
109}
110
111/**
112 * main
113 *
114 * executable entry point
115 */
116INT __cdecl main( INT argc, CHAR **argv )
117{
118 DWORD IDThread;
119 HANDLE hThread[NUM_OF_THREADS];
120 int i;
121
122 /*PAL initialization */
123 if( (PAL_Initialize(argc, argv)) != 0 )
124 {
125 return FAIL;
126 }
127
128 /*Allocate a TLS index. */
129 if ((dwTlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES)
130 {/*RROR*/
131 DWORD dwError = GetLastError();
132 Fail("TlsAlloc() returned error %d\n",
133 dwError);
134 }
135
136 /*Create multiple threads.*/
137
138 for (i = 0; i < NUM_OF_THREADS; i++)
139 {
140 hThread[i] = CreateThread(NULL, /* no security attributes*/
141 0, /* use default stack size */
142 ThreadFunc, /* thread function */
143 NULL, /* no thread function argument */
144 0, /* use default creation flags */
145 &IDThread); /* returns thread identifier */
146
147 /* Check the return value for success. */
148 if (hThread[i] == NULL)
149 {/* ERROR */
150 DWORD dwError = GetLastError();
151 Fail("Unexpected CreateThread error %d\n",
152 dwError);
153 }
154 }
155
156 /* Wait for all threads to finish */
157 for (i = 0; i < NUM_OF_THREADS; i++)
158 {
159 DWORD dwRet;
160
161 dwRet = WaitForSingleObject(hThread[i], INFINITE);
162
163 if( dwRet == WAIT_FAILED )
164 {/* ERROR */
165 DWORD dwError = GetLastError();
166 Fail("Unexpected WaitForSingleObject error %d\n",
167 dwError);
168 }
169 }
170
171 /* Release the TLS index */
172 if( TlsFree( dwTlsIndex ) == 0 )
173 {/* ERROR */
174 DWORD dwError = GetLastError();
175 Fail("TlsFree() returned 0 with error %d\n",
176 dwError);
177 }
178
179 PAL_Terminate();
180 return PASS;
181}
182
183