root/libs/loader/win32.c

Revision 04c8bb5da416fb26239f21c319966d9f03449dcc, 138.3 kB (checked in by Rafaël Carré <funman@videolan.org>, 8 months ago)

loader: fix a warning

  • Property mode set to 100644
Line 
1 /*
2  * $Id$
3  *
4  * Originally distributed under LPGL 2.1 (or later) by the Wine project.
5  *
6  * Modified for use with MPlayer, detailed CVS changelog at
7  * http://www.mplayerhq.hu/cgi-bin/cvsweb.cgi/main/
8  *
9  * File now distributed as part of VLC media player with no modifications.
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24  */
25
26 /***********************************************************
27
28 Win32 emulation code. Functions that emulate
29 responses from corresponding Win32 API calls.
30 Since we are not going to be able to load
31 virtually any DLL, we can only implement this
32 much, adding needed functions with each new codec.
33
34 Basic principle of implementation: it's not good
35 for DLL to know too much about its environment.
36
37 ************************************************************/
38
39 #include "config.h"
40
41 #ifdef MPLAYER
42 #ifdef USE_QTX_CODECS
43 #define QTX
44 #endif
45 #define REALPLAYER
46 //#define LOADLIB_TRY_NATIVE
47 #endif
48
49 #ifdef QTX
50 #define PSEUDO_SCREEN_WIDTH     /*640*/800
51 #define PSEUDO_SCREEN_HEIGHT    /*480*/600
52 #endif
53
54 #include "wine/winbase.h"
55 #include "wine/winreg.h"
56 #include "wine/winnt.h"
57 #include "wine/winerror.h"
58 #include "wine/debugtools.h"
59 #include "wine/module.h"
60 #include "wine/winuser.h"
61
62 #include <stdio.h>
63 #include "win32.h"
64
65 #include "registry.h"
66 #include "loader.h"
67 #include "com.h"
68 #include "ext.h"
69
70 #include <stdlib.h>
71 #include <assert.h>
72 #include <stdarg.h>
73 #include <ctype.h>
74 #include <pthread.h>
75 #include <errno.h>
76 #ifdef HAVE_MALLOC_H
77 #include <malloc.h>
78 #endif
79 #include <time.h>
80 #include <math.h>
81 #include <unistd.h>
82 #include <fcntl.h>
83 #include <sys/types.h>
84 #include <dirent.h>
85 #include <sys/time.h>
86 #include <sys/timeb.h>
87 #ifdef  HAVE_KSTAT
88 #include <kstat.h>
89 #endif
90
91 #if HAVE_VSSCANF
92 int vsscanf( const char *str, const char *format, va_list ap);
93 #else
94 /* system has no vsscanf.  try to provide one */
95 static int vsscanf( const char *str, const char *format, va_list ap)
96 {
97     long p1 = va_arg(ap, long);
98     long p2 = va_arg(ap, long);
99     long p3 = va_arg(ap, long);
100     long p4 = va_arg(ap, long);
101     long p5 = va_arg(ap, long);
102     return sscanf(str, format, p1, p2, p3, p4, p5);
103 }
104 #endif
105
106 static char* def_path = WIN32_PATH;
107
108 static void do_cpuid(unsigned int ax, unsigned int *regs)
109 {
110     __asm__ __volatile__
111         (
112          "pushl %%ebx; pushl %%ecx; pushl %%edx;"
113          ".byte  0x0f, 0xa2;"
114          "movl   %%eax, (%2);"
115          "movl   %%ebx, 4(%2);"
116          "movl   %%ecx, 8(%2);"
117          "movl   %%edx, 12(%2);"
118          "popl %%edx; popl %%ecx; popl %%ebx;"
119          : "=a" (ax)
120          :  "0" (ax), "S" (regs)
121         );
122 }
123 static unsigned int c_localcount_tsc()
124 {
125     int a;
126     __asm__ __volatile__
127         (
128          "rdtsc\n\t"
129          :"=a"(a)
130          :
131          :"edx"
132         );
133     return a;
134 }
135 static void c_longcount_tsc(long long* z)
136 {
137     __asm__ __volatile__
138         (
139          "pushl %%ebx\n\t"
140          "movl %%eax, %%ebx\n\t"
141          "rdtsc\n\t"
142          "movl %%eax, 0(%%ebx)\n\t"
143          "movl %%edx, 4(%%ebx)\n\t"
144          "popl %%ebx\n\t"
145          ::"a"(z)
146          :"edx"
147         );
148 }
149 static unsigned int c_localcount_notsc()
150 {
151     struct timeval tv;
152     unsigned limit=~0;
153     limit/=1000000;
154     gettimeofday(&tv, 0);
155     return limit*tv.tv_usec;
156 }
157 static void c_longcount_notsc(long long* z)
158 {
159     struct timeval tv;
160     unsigned long long result;
161     unsigned limit=~0;
162     if(!z)return;
163     limit/=1000000;
164     gettimeofday(&tv, 0);
165     result=tv.tv_sec;
166     result<<=32;
167     result+=limit*tv.tv_usec;
168     *z=result;
169 }
170 static unsigned int localcount_stub(void);
171 static void longcount_stub(long long*);
172 static unsigned int (*localcount)()=localcount_stub;
173 static void (*longcount)(long long*)=longcount_stub;
174
175 static pthread_mutex_t memmut;
176
177 static unsigned int localcount_stub(void)
178 {
179     unsigned int regs[4];
180     do_cpuid(1, regs);
181     if ((regs[3] & 0x00000010) != 0)
182     {
183         localcount=c_localcount_tsc;
184         longcount=c_longcount_tsc;
185     }
186     else
187     {
188         localcount=c_localcount_notsc;
189         longcount=c_longcount_notsc;
190     }
191     return localcount();
192 }
193 static void longcount_stub(long long* z)
194 {
195     unsigned int regs[4];
196     do_cpuid(1, regs);
197     if ((regs[3] & 0x00000010) != 0)
198     {
199         localcount=c_localcount_tsc;
200         longcount=c_longcount_tsc;
201     }
202     else
203     {
204         localcount=c_localcount_notsc;
205         longcount=c_longcount_notsc;
206     }
207     longcount(z);
208 }
209
210 #ifdef MPLAYER
211 #include "../mp_msg.h"
212 #endif
213 int LOADER_DEBUG=1; // active only if compiled with -DDETAILED_OUT
214 //#define DETAILED_OUT
215 static inline void dbgprintf(const char* fmt, ...)
216 {
217 #ifdef DETAILED_OUT
218     if(LOADER_DEBUG)
219     {
220         FILE* f;
221         va_list va;
222         va_start(va, fmt);
223         f=fopen("./log", "a");
224         vprintf(fmt, va);
225         fflush(stdout);
226         if(f)
227         {
228             vfprintf(f, fmt, va);
229             fsync(fileno(f));
230             fclose(f);
231         }
232         va_end(va);
233     }
234 #endif
235 #ifdef MPLAYER
236     if (verbose > 2)
237     {
238         va_list va;
239        
240         va_start(va, fmt);
241         vprintf(fmt, va);
242 //      mp_dbg(MSGT_WIN32, MSGL_DBG3, fmt, va);
243         va_end(va);
244     }
245   fflush(stdout);
246 #endif
247 }
248
249
250 char export_names[300][32]={
251     "name1",
252     //"name2",
253     //"name3"
254 };
255 //#define min(x,y) ((x)<(y)?(x):(y))
256
257 void destroy_event(void* event);
258
259 struct th_list_t;
260 typedef struct th_list_t{
261     int id;
262     void* thread;
263     struct th_list_t* next;
264     struct th_list_t* prev;
265 } th_list;
266
267
268 // have to be cleared by GARBAGE COLLECTOR
269 static unsigned char* heap=NULL;
270 static int heap_counter=0;
271 static tls_t* g_tls=NULL;
272 static th_list* list=NULL;
273
274 static void test_heap(void)
275 {
276     int offset=0;
277     if(heap==0)
278         return;
279     while(offset<heap_counter)
280     {
281         if(*(int*)(heap+offset)!=0x433476)
282         {
283             printf("Heap corruption at address %d\n", offset);
284             return;
285         }
286         offset+=8+*(int*)(heap+offset+4);
287     }
288     for(;offset<min(offset+1000, 20000000); offset++)
289         if(heap[offset]!=0xCC)
290         {
291             printf("Free heap corruption at address %d\n", offset);
292         }
293 }
294 #undef MEMORY_DEBUG
295
296 #ifdef MEMORY_DEBUG
297
298 static void* my_mreq(int size, int to_zero)
299 {
300     static int test=0;
301     test++;
302     if(test%10==0)printf("Memory: %d bytes allocated\n", heap_counter);
303     //    test_heap();
304     if(heap==NULL)
305     {
306         heap=malloc(20000000);
307         memset(heap, 0xCC,20000000);
308     }
309     if(heap==0)
310     {
311         printf("No enough memory\n");
312         return 0;
313     }
314     if(heap_counter+size>20000000)
315     {
316         printf("No enough memory\n");
317         return 0;
318     }
319     *(int*)(heap+heap_counter)=0x433476;
320     heap_counter+=4;
321     *(int*)(heap+heap_counter)=size;
322     heap_counter+=4;
323     printf("Allocated %d bytes of memory: sys %d, user %d-%d\n", size, heap_counter-8, heap_counter, heap_counter+size);
324     if(to_zero)
325         memset(heap+heap_counter, 0, size);
326     else
327         memset(heap+heap_counter, 0xcc, size);  // make crash reproducable
328     heap_counter+=size;
329     return heap+heap_counter-size;
330 }
331 static int my_release(char* memory)
332 {
333     //    test_heap();
334     if(memory==NULL)
335     {
336         printf("ERROR: free(0)\n");
337         return 0;
338     }
339     if(*(int*)(memory-8)!=0x433476)
340     {
341         printf("MEMORY CORRUPTION !!!!!!!!!!!!!!!!!!!\n");
342         return 0;
343     }
344     printf("Freed %d bytes of memory\n", *(int*)(memory-4));
345     //    memset(memory-8, *(int*)(memory-4), 0xCC);
346     return 0;
347 }
348
349 #else
350 #define GARBAGE
351 typedef struct alloc_header_t alloc_header;
352 struct alloc_header_t
353 {
354     // let's keep allocated data 16 byte aligned
355     alloc_header* prev;
356     alloc_header* next;
357     long deadbeef;
358     long size;
359     long type;
360     long reserved1;
361     long reserved2;
362     long reserved3;
363 };
364
365 #ifdef GARBAGE
366 static alloc_header* last_alloc = NULL;
367 static int alccnt = 0;
368 #endif
369
370 #define AREATYPE_CLIENT 0
371 #define AREATYPE_EVENT 1
372 #define AREATYPE_MUTEX 2
373 #define AREATYPE_COND 3
374 #define AREATYPE_CRITSECT 4
375
376 /* -- critical sections -- */
377 struct CRITSECT
378 {
379     pthread_t id;
380     pthread_mutex_t mutex;
381     int locked;
382     long deadbeef;
383 };
384
385 void* mreq_private(int size, int to_zero, int type);
386 void* mreq_private(int size, int to_zero, int type)
387 {
388     int nsize = size + sizeof(alloc_header);
389     alloc_header* header = (alloc_header* ) malloc(nsize);
390     if (!header)
391         return 0;
392     if (to_zero)
393         memset(header, 0, nsize);
394 #ifdef GARBAGE
395     if (!last_alloc)
396     {
397         pthread_mutex_init(&memmut, NULL);
398         pthread_mutex_lock(&memmut);
399     }
400     else
401     {
402         pthread_mutex_lock(&memmut);
403         last_alloc->next = header;  /* set next */
404     }
405
406     header->prev = last_alloc;
407     header->next = 0;
408     last_alloc = header;
409     alccnt++;
410     pthread_mutex_unlock(&memmut);
411 #endif
412     header->deadbeef = 0xdeadbeef;
413     header->size = size;
414     header->type = type;
415
416     //if (alccnt < 40000) printf("MY_REQ: %p\t%d   t:%d  (cnt:%d)\n",  header, size, type, alccnt);
417     return header + 1;
418 }
419
420 static int my_release(void* memory)
421 {
422     alloc_header* header = (alloc_header*) memory - 1;
423 #ifdef GARBAGE
424     alloc_header* prevmem;
425     alloc_header* nextmem;
426
427     if (memory == 0)
428         return 0;
429
430     if (header->deadbeef != (long) 0xdeadbeef)
431     {
432         dbgprintf("FATAL releasing corrupted memory! %p  0x%lx  (%d)\n", header, header->deadbeef, alccnt);
433         return 0;
434     }
435
436     pthread_mutex_lock(&memmut);
437
438     switch(header->type)
439     {
440     case AREATYPE_EVENT:
441         destroy_event(memory);
442         break;
443     case AREATYPE_COND:
444         pthread_cond_destroy((pthread_cond_t*)memory);
445         break;
446     case AREATYPE_MUTEX:
447         pthread_mutex_destroy((pthread_mutex_t*)memory);
448         break;
449     case AREATYPE_CRITSECT:
450         pthread_mutex_destroy(&((struct CRITSECT*)memory)->mutex);
451         break;
452     default:
453         //memset(memory, 0xcc, header->size);
454         ;
455     }
456
457     header->deadbeef = 0;
458     prevmem = header->prev;
459     nextmem = header->next;
460
461     if (prevmem)
462         prevmem->next = nextmem;
463     if (nextmem)
464         nextmem->prev = prevmem;
465
466     if (header == last_alloc)
467         last_alloc = prevmem;
468
469     alccnt--;
470
471     if (last_alloc)
472         pthread_mutex_unlock(&memmut);
473     else
474         pthread_mutex_destroy(&memmut);
475
476     //if (alccnt < 40000) printf("MY_RELEASE: %p\t%ld    (%d)\n", header, header->size, alccnt);
477 #else
478     if (memory == 0)
479         return 0;
480 #endif
481     //memset(header + 1, 0xcc, header->size);
482     free(header);
483     return 0;
484 }
485 #endif
486
487 static inline void* my_mreq(int size, int to_zero)
488 {
489     return mreq_private(size, to_zero, AREATYPE_CLIENT);
490 }
491
492 static int my_size(void* memory)
493 {
494     if(!memory) return 0;
495     return ((alloc_header*)memory)[-1].size;
496 }
497
498 static void* my_realloc(void* memory, int size)
499 {
500     void *ans = memory;
501     int osize;
502     if (memory == NULL)
503         return my_mreq(size, 0);
504     osize = my_size(memory);
505     if (osize < size)
506     {
507         ans = my_mreq(size, 0);
508         memcpy(ans, memory, osize);
509         my_release(memory);
510     }
511     return ans;
512 }
513
514 /*
515  *
516  *  WINE  API  - native implementation for several win32 libraries
517  *
518  */
519
520 static int WINAPI ext_unknown()
521 {
522     printf("Unknown func called\n");
523     return 0;
524 }
525
526 static int  WINAPI expGetVolumeInformationA( const char *root, char *label,
527                                        unsigned int label_len, unsigned int *serial,
528                                        unsigned int *filename_len,unsigned int *flags,
529                                        char *fsname, unsigned int fsname_len )
530 {
531 dbgprintf("GetVolumeInformationA( %s, 0x%x, %ld, 0x%x, 0x%x, 0x%x, 0x%x, %ld) => 1\n",
532                       root,label,label_len,serial,filename_len,flags,fsname,fsname_len);
533 //hack Do not return any real data - do nothing
534 return 1;
535 }
536
537 static unsigned int WINAPI expGetDriveTypeA( const char *root )
538 {
539  dbgprintf("GetDriveTypeA( %s ) => %d\n",root,DRIVE_FIXED);
540  // hack return as Fixed Drive Type
541  return DRIVE_FIXED;
542 }
543
544 static unsigned int WINAPI expGetLogicalDriveStringsA( unsigned int len, char *buffer )
545 {
546  dbgprintf("GetLogicalDriveStringsA(%d, 0x%x) => 4\n",len,buffer);
547  // hack only have one drive c:\ in this hack
548   *buffer++='c';
549   *buffer++=':';
550   *buffer++='\\';
551   *buffer++='\0';
552   *buffer= '\0';
553 return 4; // 1 drive * 4 bytes (includes null)
554 }
555
556
557 static int WINAPI expIsBadWritePtr(void* ptr, unsigned int count)
558 {
559     int result = (count == 0 || ptr != 0) ? 0 : 1;
560     dbgprintf("IsBadWritePtr(0x%x, 0x%x) => %d\n", ptr, count, result);
561     return result;
562 }
563 static int WINAPI expIsBadReadPtr(void* ptr, unsigned int count)
564 {
565     int result = (count == 0 || ptr != 0) ? 0 : 1;
566     dbgprintf("IsBadReadPtr(0x%x, 0x%x) => %d\n", ptr, count, result);
567     return result;
568 }
569 static int WINAPI expDisableThreadLibraryCalls(int module)
570 {
571     dbgprintf("DisableThreadLibraryCalls(0x%x) => 0\n", module);
572     return 0;
573 }
574
575 static HMODULE WINAPI expGetDriverModuleHandle(DRVR* pdrv)
576 {
577     HMODULE result;
578     if (pdrv==NULL)
579         result=0;
580     else
581         result=pdrv->hDriverModule;
582     dbgprintf("GetDriverModuleHandle(%p) => %p\n", pdrv, result);
583     return result;
584 }
585
586 #define MODULE_HANDLE_kernel32  ((HMODULE)0x120)
587 #define MODULE_HANDLE_user32    ((HMODULE)0x121)
588 #ifdef QTX
589 #define MODULE_HANDLE_wininet   ((HMODULE)0x122)
590 #define MODULE_HANDLE_ddraw     ((HMODULE)0x123)
591 #define MODULE_HANDLE_advapi32  ((HMODULE)0x124)
592 #endif
593 #define MODULE_HANDLE_comdlg32  ((HMODULE)0x125)
594 #define MODULE_HANDLE_msvcrt    ((HMODULE)0x126)
595 #define MODULE_HANDLE_ole32     ((HMODULE)0x127)
596 #define MODULE_HANDLE_winmm     ((HMODULE)0x128)
597
598 static HMODULE WINAPI expGetModuleHandleA(const char* name)
599 {
600     WINE_MODREF* wm;
601     HMODULE result;
602     if(!name)
603 #ifdef QTX
604         result=1;
605 #else
606         result=0;
607 #endif
608     else
609     {
610         wm=MODULE_FindModule(name);
611         if(wm==0)result=0;
612         else
613             result=(HMODULE)(wm->module);
614     }
615     if(!result)
616     {
617         if(name && (strcasecmp(name, "kernel32")==0 || !strcasecmp(name, "kernel32.dll")))
618             result=MODULE_HANDLE_kernel32;
619 #ifdef QTX
620         if(name && strcasecmp(name, "user32")==0)
621             result=MODULE_HANDLE_user32;
622 #endif
623     }
624     dbgprintf("GetModuleHandleA('%s') => 0x%x\n", name, result);
625     return result;
626 }
627
628 static void* WINAPI expCreateThread(void* pSecAttr, long dwStackSize,
629                                     void* lpStartAddress, void* lpParameter,
630                                     long dwFlags, long* dwThreadId)
631 {
632     pthread_t *pth;
633     //    printf("CreateThread:");
634     pth = (pthread_t*) my_mreq(sizeof(pthread_t), 0);
635     pthread_create(pth, NULL, (void*(*)(void*))lpStartAddress, lpParameter);
636     if(dwFlags)
637         printf( "WARNING: CreateThread flags not supported\n");
638     if(dwThreadId)
639         *dwThreadId=(long)pth;
640     if(list==NULL)
641     {
642         list=my_mreq(sizeof(th_list), 1);
643         list->next=list->prev=NULL;
644     }
645     else
646     {
647         list->next=my_mreq(sizeof(th_list), 0);
648         list->next->prev=list;
649         list->next->next=NULL;
650         list=list->next;
651     }
652     list->thread=pth;
653     dbgprintf("CreateThread(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x) => 0x%x\n",
654               pSecAttr, dwStackSize, lpStartAddress, lpParameter, dwFlags, dwThreadId, pth);
655     return pth;
656 }
657
658 struct mutex_list_t;
659
660 struct mutex_list_t
661 {
662     char type;
663     pthread_mutex_t *pm;
664     pthread_cond_t  *pc;
665     char state;
666     char reset;
667     char name[128];
668     int  semaphore;
669     struct mutex_list_t* next;
670     struct mutex_list_t* prev;
671 };
672 typedef struct mutex_list_t mutex_list;
673 static mutex_list* mlist=NULL;
674
675 void destroy_event(void* event)
676 {
677     mutex_list* pp=mlist;
678     //    printf("garbage collector: destroy_event(%x)\n", event);
679     while(pp)
680     {
681         if(pp==(mutex_list*)event)
682         {
683             if(pp->next)
684                 pp->next->prev=pp->prev;
685             if(pp->prev)
686                 pp->prev->next=pp->next;
687             if(mlist==(mutex_list*)event)
688                 mlist=mlist->prev;
689             /*
690              pp=mlist;
691              while(pp)
692              {
693              printf("%x => ", pp);
694              pp=pp->prev;
695              }
696              printf("0\n");
697              */
698             return;
699         }
700         pp=pp->prev;
701     }
702 }
703
704 static void* WINAPI expCreateEventA(void* pSecAttr, char bManualReset,
705                                     char bInitialState, const char* name)
706 {
707     pthread_mutex_t *pm;
708     pthread_cond_t  *pc;
709     /*
710      mutex_list* pp;
711      pp=mlist;
712      while(pp)
713      {
714      printf("%x => ", pp);
715      pp=pp->prev;
716      }
717      printf("0\n");
718      */
719     if(mlist!=NULL)
720     {
721         mutex_list* pp=mlist;
722         if(name!=NULL)
723             do
724         {
725             if((strcmp(pp->name, name)==0) && (pp->type==0))
726             {
727                 dbgprintf("CreateEventA(0x%x, 0x%x, 0x%x, 0x%x='%s') => 0x%x\n",
728                           pSecAttr, bManualReset, bInitialState, name, name, pp->pm);
729                 return pp->pm;
730             }
731         }while((pp=pp->prev) != NULL);
732     }
733     pm=mreq_private(sizeof(pthread_mutex_t), 0, AREATYPE_MUTEX);
734     pthread_mutex_init(pm, NULL);
735     pc=mreq_private(sizeof(pthread_cond_t), 0, AREATYPE_COND);
736     pthread_cond_init(pc, NULL);
737     if(mlist==NULL)
738     {
739         mlist=mreq_private(sizeof(mutex_list), 00, AREATYPE_EVENT);
740         mlist->next=mlist->prev=NULL;
741     }
742     else
743     {
744         mlist->next=mreq_private(sizeof(mutex_list), 00, AREATYPE_EVENT);
745         mlist->next->prev=mlist;
746         mlist->next->next=NULL;
747         mlist=mlist->next;
748     }
749     mlist->type=0; /* Type Event */
750     mlist->pm=pm;
751     mlist->pc=pc;
752     mlist->state=bInitialState;
753     mlist->reset=bManualReset;
754     if(name)
755         strncpy(mlist->name, name, 127);
756     else
757         mlist->name[0]=0;
758     if(pm==NULL)
759         dbgprintf("ERROR::: CreateEventA failure\n");
760     /*
761      if(bInitialState)
762      pthread_mutex_lock(pm);
763      */
764     if(name)
765         dbgprintf("CreateEventA(0x%x, 0x%x, 0x%x, 0x%x='%s') => 0x%x\n",
766                   pSecAttr, bManualReset, bInitialState, name, name, mlist);
767     else
768         dbgprintf("CreateEventA(0x%x, 0x%x, 0x%x, NULL) => 0x%x\n",
769                   pSecAttr, bManualReset, bInitialState, mlist);
770     return mlist;
771 }
772
773 static void* WINAPI expSetEvent(void* event)
774 {
775     mutex_list *ml = (mutex_list *)event;
776     dbgprintf("SetEvent(%x) => 0x1\n", event);
777     pthread_mutex_lock(ml->pm);
778     if (ml->state == 0) {
779         ml->state = 1;
780         pthread_cond_signal(ml->pc);
781     }
782     pthread_mutex_unlock(ml->pm);
783
784     return (void *)1;
785 }
786 static void* WINAPI expResetEvent(void* event)
787 {
788     mutex_list *ml = (mutex_list *)event;
789     dbgprintf("ResetEvent(0x%x) => 0x1\n", event);
790     pthread_mutex_lock(ml->pm);
791     ml->state = 0;
792     pthread_mutex_unlock(ml->pm);
793
794     return (void *)1;
795 }
796
797 static void* WINAPI expWaitForSingleObject(void* object, int duration)
798 {
799     mutex_list *ml = (mutex_list *)object;
800     // FIXME FIXME FIXME - this value is sometime unititialize !!!
801     int ret = WAIT_FAILED;
802     mutex_list* pp=mlist;
803     if(object == (void*)0xcfcf9898)
804     {
805         /**
806          From GetCurrentThread() documentation:
807          A pseudo handle is a special constant that is interpreted as the current thread handle. The calling thread can use this handle to specify itself whenever a thread handle is required. Pseudo handles are not inherited by child processes.
808
809          This handle has the maximum possible access to the thread object. For systems that support security descriptors, this is the maximum access allowed by the security descriptor for the calling process. For systems that do not support security descriptors, this is THREAD_ALL_ACCESS.
810
811          The function cannot be used by one thread to create a handle that can be used by other threads to refer to the first thread. The handle is always interpreted as referring to the thread that is using it. A thread can create a "real" handle to itself that can be used by other threads, or inherited by other processes, by specifying the pseudo handle as the source handle in a call to the DuplicateHandle function.
812          **/
813         dbgprintf("WaitForSingleObject(thread_handle) called\n");
814         return (void*)WAIT_FAILED;
815     }
816     dbgprintf("WaitForSingleObject(0x%x, duration %d) =>\n",object, duration);
817
818     // loop below was slightly fixed - its used just for checking if
819     // this object really exists in our list
820     if (!ml)
821         return (void*) ret;
822     while (pp && (pp->pm != ml->pm))
823         pp = pp->prev;
824     if (!pp) {
825         dbgprintf("WaitForSingleObject: NotFound\n");
826         return (void*)ret;
827     }
828
829     pthread_mutex_lock(ml->pm);
830
831     switch(ml->type) {
832     case 0: /* Event */
833         if (duration == 0) { /* Check Only */
834             if (ml->state == 1) ret = WAIT_FAILED;
835             else                   ret = WAIT_OBJECT_0;
836         }
837         if (duration == -1) { /* INFINITE */
838             if (ml->state == 0)
839                 pthread_cond_wait(ml->pc,ml->pm);
840             if (ml->reset)
841                 ml->state = 0;
842             ret = WAIT_OBJECT_0;
843         }
844         if (duration > 0) {  /* Timed Wait */
845             struct timespec abstime;
846             struct timeval now;
847             gettimeofday(&now, 0);
848             abstime.tv_sec = now.tv_sec + (now.tv_usec+duration)/1000000;
849             abstime.tv_nsec = ((now.tv_usec+duration)%1000000)*1000;
850             if (ml->state == 0)
851                 ret=pthread_cond_timedwait(ml->pc,ml->pm,&abstime);
852             if (ret == ETIMEDOUT) ret = WAIT_TIMEOUT;
853             else                  ret = WAIT_OBJECT_0;
854             if (ml->reset)
855                 ml->state = 0;
856         }
857         break;
858     case 1/* Semaphore */
859         if (duration == 0) {
860             if(ml->semaphore==0) ret = WAIT_FAILED;
861             else {
862                 ml->semaphore++;
863                 ret = WAIT_OBJECT_0;
864             }
865         }
866         if (duration == -1) {
867             if (ml->semaphore==0)
868                 pthread_cond_wait(ml->pc,ml->pm);
869             ml->semaphore--;
870         }
871         break;
872     }
873     pthread_mutex_unlock(ml->pm);
874
875     dbgprintf("WaitForSingleObject(0x%x, %d): 0x%x => 0x%x \n",object,duration,ml,ret);
876     return (void *)ret;
877 }
878
879 #ifdef QTX
880 static void* WINAPI expWaitForMultipleObjects(int count, const void** objects,
881                     int WaitAll, int duration)
882 {
883     int i;
884     void *object;
885     void *ret;
886
887     dbgprintf("WaitForMultipleObjects(%d, 0x%x, %d, duration %d) =>\n",
888         count, objects, WaitAll, duration);
889    
890     for (i = 0; i < count; i++)
891     {
892         object = (void *)objects[i];
893         ret = expWaitForSingleObject(object, duration);
894         if (WaitAll)
895             dbgprintf("WaitAll flag not yet supported...\n");
896         else
897             return ret;
898     }
899     return NULL;
900 }
901
902 static void WINAPI expExitThread(int retcode)
903 {
904     dbgprintf("ExitThread(%d)\n", retcode);
905     pthread_exit(&retcode);
906 }
907
908 static HANDLE WINAPI expCreateMutexA(void *pSecAttr,
909                     char bInitialOwner, const char *name)
910 {
911     HANDLE mlist = (HANDLE)expCreateEventA(pSecAttr, 0, 0, name);
912    
913     if (name)
914         dbgprintf("CreateMutexA(0x%x, %d, '%s') => 0x%x\n",
915             pSecAttr, bInitialOwner, name, mlist);
916     else
917         dbgprintf("CreateMutexA