Not able to generate race condition...

Submitted by Anonymous
on May 7, 2009 - 9:39pm

Hi,

I am learning linux kernel. I have written a simple program to understand the usage of mutex variable.

Ideally the following program should generate race condition and should produce the different values on i,j,k and l rather than i = j = k = l = 100(LOOPCONSTANT * Number of threads) on usage of mutex. Here shared variables between threads are i,j,k and l.

My kernel is not SMP. Can u please tell me where am i going wrong?
======================================================================================================

#include
#include
#define checkResults(string, val) { \
if (val) { \
printf("Failed with %d at %s", val, string); \
exit(1); \
} \
}
//#define LOOPCONSTANT 100000
#define LOOPCONSTANT 10
#define THREADS 10

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
volatile int i asm("eax"); /* For using eax ebx ecx & edx for i, j , k and l respectively.
* All the threads shud use eax for i, ebx for j ...
*/
volatile int j asm("ebx");
volatile int k asm("ecx");
volatile int l asm("edx");
int uselock=0;

void *threadfunc(void *parm)
{
int loop = 0;
int rc;

for (loop=0; loop < LOOPCONSTANT; ++loop) {
if (uselock) {
rc = pthread_mutex_lock(&mutex);
checkResults("pthread_mutex_lock()\n", rc);
}
++i; ++j; ++k; ++l;
if (uselock) {
rc = pthread_mutex_unlock(&mutex);
checkResults("pthread_mutex_unlock()\n", rc);
}
}
return NULL;
}

int main(int argc, char **argv)
{
pthread_t threadid[THREADS];
int rc=0;

int loop=0;
pthread_attr_t pta;

printf("Entering testcase\n");
printf("Give any number of parameters to show data corruption\n");
if (argc != 1) {
printf("A parameter was specified, no serialization is being done!\n");
uselock = 0;
}

pthread_attr_init(&pta);
pthread_attr_setdetachstate(&pta, PTHREAD_CREATE_JOINABLE);

printf("Creating %d threads\n", THREADS);
for (loop=0; loop < THREADS; ++loop) {
rc = pthread_create(&threadid[loop], &pta, threadfunc, NULL);
checkResults("pthread_create()\n", rc);
}

printf("Wait for results\n");
for (loop=0; loop < THREADS; ++loop) {
rc = pthread_join(threadid[loop], NULL);
checkResults("pthread_join()\n", rc);
}

printf("Cleanup and show results\n");
pthread_attr_destroy(&pta);
pthread_mutex_destroy(&mutex);

printf("\nUsing %d threads and LOOPCONSTANT = %d\n",
THREADS, LOOPCONSTANT);
printf("Values are: (should be %d)\n", THREADS * LOOPCONSTANT);
printf(" ==> | %d, %d, %d, %d\n", i, j, k, l);

printf("Main completed\n");
return 0;
}

======================================================================================================

O/p of the above program:
---------------------------------------

with userlock = 0 (i.e., shud hit race condition)
--------------------------------------------------------------------
gcc check.c -pthread
bash-2.05b$ ./a.out
Creating 10 threads
Wait for results
Cleanup and show results

Using 10 threads and LOOPCONSTANT = 10
Values are: (should be 100)
==> | 100, 100, 100, 100 <<<<<<<<<<<==========*******
Main completed
bash-2.05b$
=====================================
with userlock = 1;
-------------------------
I am getting the same o/p which is correct....

Any help regarding this is greatly appreciated.

Thanks in advance...

make sure

strcmp
on
May 8, 2009 - 5:25am

make sure the situation you need for the race condition to appear is happening with sufficient intensity. add code for measuring this, like tracing code (printf()-s or something like that).

variables can't be register bound for the duration of the program, the registers have assigned roles in the ABI; if eax is fixed to be some variable, you can't execute syscalls or call functions, or multiply or divide, because all that would need eax

Can u please tell me how to

Anonymous (not verified)
on
May 8, 2009 - 6:09am

Can u please tell me how to assign a particular register to a variable? As per ur explanation it shud not be possible.
But still i remember usage of asm("eax") to a variable definition in linux kernel source code.
volatile int i asm("eax");
Am i going wrong here?

Thanks,

I think the problem is in

Mathieu
on
May 9, 2009 - 11:25pm

I think the problem is in the algorithm itself. 10 threads loop 10 times and increment a series of variable.

You won't see any different if a thread interrupt another one to increment the value before another increment the same value.

One way to see the thread blocked on the mutex would be to set a different value to i,j,k,l for each thread and display them inside each tread.
for example, set i,j,k,l = 1 for thread 1, i,j,k,l = 2 for thread 2, .....
then do a separate printf of i, j, k, l, inside the section critic (protected by mutex).

The expected result should be for example (with your userlock = 1):
1111,2222,3333,4444,5555..... (or a different order: 2222,5555,3333... regarding the order the scheduler decide to run the thread, probably, creation order since they have the same weigth).

If you turn off userlock (set to 0), the result will be something like:
1234, 3245, 1235, 3512, 11542 ....

I also don't understand the intent to assign a the global variable to a specific register. I am not sure that this is actually working. there is no way the compiler is going to guaranty to not use eax... as strcmp explained, other function call to libraries will use the registers eax...
Assigning variable registers is usefull when you have inline assembler in C code. But it's not the case here. I would be currious to see the dasm file to see if i is actually assigned to eax in the thread code and the main function.

Regards,

Hi Mathieu My kernel is not

Anonymous (not verified)
on
May 12, 2009 - 11:21am

Hi Mathieu

My kernel is not SMP .I am getting 1111,2222,3333,4444 ...
1. Can u please tell me how to assign a variable load store to operate on a specific register? I have use asm("eax") appended to a variable definition. I have seen similar usage in linux source code
2. I defined it as a global variable so that it can be shared across all the threads else i need to pass address of the variable as a pthread_create function argument. Is this the right way?

Thanks,

registers

strcmp
on
May 12, 2009 - 1:16pm

register contents are a vital part of a thread's execution context. register contents are not shared between threads on i386. registers which are used in function calls and syscalls can't be shared for obvious reasons.

for that asm() syntax read the info page for gcc. In chapter 'C Extensions' there are links 'Explicit Reg Vars' and 'Asm Labels'.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.