summaryrefslogtreecommitdiff
path: root/VC++Files/thr_test/thr_test.c
blob: efb9ea27ba791013cb9162e7d0c7b81c8fe2194f (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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
/* Testing of thread creation to find memory allocation bug
** This is coded to use as few extern functions as possible!
**
** The program must be compiled to be multithreaded !
**
** The problem is that when this program is run it will allocate more and more
** memory, so there is a memory leak in the thread handling. The problem is how
** to avoid is !
**
** It looks like the bug is that the std library doesn't free thread
** specific variables if one uses a thread variable.
** If one compiles this program with -DREMOVE_BUG
** there is no memory leaks anymore!
**
** This program is tested with Microsofts VC++ 5.0, but BC5.2 is also
** reported to have this bug.
*/

#include <windows.h>
#include <process.h>
#include <stdio.h>

#define TEST_COUNT 100000

/*****************************************************************************
** The following is to emulate the posix thread interface
*****************************************************************************/

typedef HANDLE  pthread_t;
typedef struct thread_attr {
	DWORD	dwStackSize ;
	DWORD	dwCreatingFlag ;
	int	priority ;
} pthread_attr_t ;
typedef struct { int dummy; } pthread_condattr_t;
typedef struct {
        unsigned int msg;
        pthread_t thread;
        DWORD thread_id;
} pthread_cond_t;
typedef CRITICAL_SECTION pthread_mutex_t;

#define pthread_mutex_init(A,B)  InitializeCriticalSection(A)
#define pthread_mutex_lock(A)    (EnterCriticalSection(A),0)
#define pthread_mutex_unlock(A)  LeaveCriticalSection(A)
#define pthread_mutex_destroy(A) DeleteCriticalSection(A)
#define pthread_handler_t unsigned __cdecl
typedef unsigned (__cdecl *pthread_handler)(void *);
#define pthread_self() GetCurrentThread()

static unsigned int thread_count;
static pthread_cond_t COND_thread_count;
static pthread_mutex_t LOCK_thread_count;

pthread_mutex_t THR_LOCK_malloc,THR_LOCK_open,THR_LOCK_keycache,
		THR_LOCK_lock,THR_LOCK_isam;
/*
** We have tried to use '_beginthreadex' instead of '_beginthread' here
** but in this case the program leaks about 512 characters for each
** created thread !
*/

int pthread_create(pthread_t *thread_id, pthread_attr_t *attr,
		   pthread_handler func, void *param)
{
  HANDLE hThread;
 
  hThread=(HANDLE)_beginthread(func,
			       attr->dwStackSize ? attr->dwStackSize :
			       65535,param);
  if ((long) hThread == -1L)
  {
    return(errno ? errno : -1);
  }
  *thread_id=hThread;
  return(0);
}

void pthread_exit(unsigned A)
{
  _endthread();
}

/*
** The following simple implementation of conds works as long as
** only one thread uses pthread_cond_wait at a time.
** This is coded very carefully to work with thr_lock.
*/

static unsigned int WIN32_WAIT_SIGNAL= 30000;	/* Start message to use */

int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
{
  cond->msg=WIN32_WAIT_SIGNAL++;
  cond->thread=(pthread_t) pthread_self();	/* For global conds */
//IRENA
  cond->thread_id=GetCurrentThreadId();
  return 0;
}


int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
{
  MSG	msg ;
  unsigned int	msgCode=cond->msg;

  cond->thread=(pthread_t) pthread_self();
//IRENA
//???  cond->thread_id=GetCurrentThreadId();
  //VOID(ReleaseMutex(*mutex));

  LeaveCriticalSection(mutex);
  do
  {
    WaitMessage() ;
    if (!PeekMessage(&msg, NULL, 1, 65534,PM_REMOVE))
    {
      return errno=GetLastError() ;
    }
  } while (msg.message != msgCode) ;
  EnterCriticalSection(mutex);
  return 0 ;
}


int pthread_cond_signal(pthread_cond_t *cond)
{

  if (!PostThreadMessage(cond->thread_id, cond->msg, 0,0))
  {
    return errno=GetLastError() ;
  }
  return 0 ;
}

int pthread_attr_init(pthread_attr_t *connect_att)
{
  connect_att->dwStackSize	= 0;
  connect_att->dwCreatingFlag	= 0;
  connect_att->priority		= 0;
  return 0;
}

int pthread_attr_setstacksize(pthread_attr_t *connect_att,DWORD stack)
{
  connect_att->dwStackSize=stack;
  return 0;
}

int pthread_attr_setprio(pthread_attr_t *connect_att,int priority)
{
  connect_att->priority=priority;
  return 0;
}

int pthread_attr_destroy(pthread_attr_t *connect_att)
{
  return 0;
}

/* from my_pthread.c */

#ifndef REMOVE_BUG

__declspec(thread) int THR_KEY_my_errno;

int _my_errno(void)
{
  return THR_KEY_my_errno;
}
#endif

/*****************************************************************************
** The test program
*****************************************************************************/

pthread_handler_t test_thread(void *arg)
{
  pthread_mutex_lock(&LOCK_thread_count);
  thread_count--;
  pthread_cond_signal(&COND_thread_count); /* Tell main we are ready */
  pthread_mutex_unlock(&LOCK_thread_count);
  pthread_exit(0);
  return 0;
}

int main(int argc,char **argv)
{
  pthread_t tid;
  pthread_attr_t thr_attr;
  int i,error;

  if ((error=pthread_cond_init(&COND_thread_count,NULL)))
  {
    fprintf(stderr,"Got error: %d from pthread_cond_init (errno: %d)",
	    error,errno);
    exit(1);
  }
  pthread_mutex_init(&LOCK_thread_count,NULL);
 if ((error=pthread_attr_init(&thr_attr)))
  {
    fprintf(stderr,"Got error: %d from pthread_attr_init (errno: %d)",
	    error,errno);
    exit(1);
  }
  if ((error=pthread_attr_setstacksize(&thr_attr,65536L)))
  {
    fprintf(stderr,"Got error: %d from pthread_attr_setstacksize (errno: %d)",
	    error,errno);
    exit(1);
  }

  printf("Init ok. Creating %d threads\n",TEST_COUNT);
  for (i=1 ; i <= TEST_COUNT ; i++)
  {
    int *param= &i;
    if ((i % 100) == 0)
    {
      printf("%8d",i);
      fflush(stdout);
    }
    if ((error=pthread_mutex_lock(&LOCK_thread_count)))
    {
      fprintf(stderr,"\nGot error: %d from pthread_mutex_lock (errno: %d)",
	      error,errno);
      exit(1);
    }
    if ((error=pthread_create(&tid,&thr_attr,test_thread,(void*) param)))
    {
      fprintf(stderr,"\nGot error: %d from pthread_create (errno: %d)\n",
	      error,errno);
      pthread_mutex_unlock(&LOCK_thread_count);
      exit(1);
    }
    thread_count++;
    pthread_mutex_unlock(&LOCK_thread_count);

    if ((error=pthread_mutex_lock(&LOCK_thread_count)))
      fprintf(stderr,"\nGot error: %d from pthread_mutex_lock\n",error);
    while (thread_count)
    {
      if ((error=pthread_cond_wait(&COND_thread_count,&LOCK_thread_count)))
	fprintf(stderr,"\nGot error: %d from pthread_cond_wait\n",error);
    }
    pthread_mutex_unlock(&LOCK_thread_count);
  }
  pthread_attr_destroy(&thr_attr);
  printf("\nend\n");
  return 0;
}