summaryrefslogtreecommitdiff
path: root/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange/test2/test.cpp
blob: 902f626d47894f186f575d2fc6cbcfd4755b4fc2 (plain)
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
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

/*============================================================
**
** Source : test.c
**
** Purpose: Test for InterlockedCompareExchange() function using multiple threads
**
**
**=========================================================*/



#include <palsuite.h>

#define MAX_THREADS 10
#define REPEAT_COUNT 10

//Global Variable Declaration
LONG g_Total = 0;
LONG Lock=0;


void ModifyGlobalResource(void);
void AcquireLock(PLONG pLock);
void ReleaseLock(PLONG pLock);



//Main entry point of the program
int __cdecl main(int argc, char *argv[]) {
  
    int i = 0;
    DWORD dwThreadID=0;
    LONG totalOperations = 0;

    HANDLE hThread[MAX_THREADS];

    /*
     * Initialize the PAL and return FAILURE if this fails
     */

    if(0 != (PAL_Initialize(argc, argv)))
    {
        return FAIL;
    }


	totalOperations = MAX_THREADS * REPEAT_COUNT;


	//Create MAX_THREADS threads that will operate on the global counter
	for (i=0;i<MAX_THREADS;i++)
	{
			hThread[i] = CreateThread( 
				NULL,                        // default security attributes 
				0,                           // use default stack size  
				(LPTHREAD_START_ROUTINE) ModifyGlobalResource,    // thread function 
				NULL,                // argument to thread function 
				0,                           // use default creation flags 
				&dwThreadID);                // returns the thread identifier 
 
		   // Check the return value for success. 
 
			if (hThread[i] == NULL) 
			{
				Fail("ERROR: Was not able to create thread\n"
           				 "GetLastError returned %d\n", GetLastError());
			}

	}


	//Wait for all threads to finish
	for (i=0;i<MAX_THREADS;i++)
	{

		 if (WAIT_OBJECT_0 != WaitForSingleObject (hThread[i], INFINITE))
 		{
	 		Fail ("Main: Wait for Single Object failed.  Failing test.\n"
		       "GetLastError returned %d\n", GetLastError());  
 		}
	
	}
	

	if (0!= g_Total)
		{
			Fail("Test Failed \n");
		}

	Trace("Global Counter Value at the end of the test %d \n", g_Total);

    /*
     * Terminate PAL 
     */
	
    PAL_Terminate();
    return PASS; 
} 


void ModifyGlobalResource(void)
{

	int i =0;
	
	for (i=0;i<REPEAT_COUNT;i++)
		{

			/*
				Acquire Lock Provides Synchronization Around g_Total global variable
			*/

			AcquireLock(&Lock);
			
			/*
			The following set of operations is gauranteed to be atomic by virtue of the fact 
			that InterLockedCompareExchange was able to gaurantee that the compare 
			and exchange operation on pLock was thread safe.  If the same set of code was 
			executed without using InterlockedCompareExchange the code would fail most of 
			time.
			
			*/
			g_Total++;
			Sleep(100);
			g_Total--;
			if (0!=g_Total)
				{
					Fail("Test Failed beacuse g_Total was not protected \n");
				}

			
			/*
				Acquire Lock releases the lock around g_Total Global variable 
			*/

			ReleaseLock(&Lock);
		}
	
	
}


void AcquireLock(PLONG pLock)
{
	//Spin Lock implemented with the help of InterlockedCompareExchange

	
	while(1)
		{
		if (InterlockedCompareExchange(pLock,1,0)==0)
			break;
		}
		
}


void ReleaseLock(PLONG pLock)
{
	

	MemoryBarrier();
	*pLock = 0;
}