Remove the obsolete pascal16 (replaced by pascal -ret16).
[wine] / dlls / kernel / sync.c
1 /*
2  * Kernel synchronization objects
3  *
4  * Copyright 1998 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <string.h>
25 #ifdef HAVE_UNISTD_H
26 # include <unistd.h>
27 #endif
28 #include <errno.h>
29 #ifdef HAVE_SYS_IOCTL_H
30 #include <sys/ioctl.h>
31 #endif
32 #ifdef HAVE_SYS_POLL_H
33 #include <sys/poll.h>
34 #endif
35 #include <stdarg.h>
36 #include <stdio.h>
37
38 #include "ntstatus.h"
39 #include "windef.h"
40 #include "winbase.h"
41 #include "winerror.h"
42 #include "winnls.h"
43
44 #include "wine/server.h"
45 #include "wine/unicode.h"
46 #include "kernel_private.h"
47 #include "file.h"
48
49 #include "wine/debug.h"
50
51 WINE_DEFAULT_DEBUG_CHANNEL(win32);
52
53 /* check if current version is NT or Win95 */
54 inline static int is_version_nt(void)
55 {
56     return !(GetVersion() & 0x80000000);
57 }
58
59
60 /***********************************************************************
61  *              Sleep  (KERNEL32.@)
62  */
63 VOID WINAPI Sleep( DWORD timeout )
64 {
65     SleepEx( timeout, FALSE );
66 }
67
68 /******************************************************************************
69  *              SleepEx   (KERNEL32.@)
70  */
71 DWORD WINAPI SleepEx( DWORD timeout, BOOL alertable )
72 {
73     NTSTATUS status;
74
75     if (timeout == INFINITE) status = NtDelayExecution( alertable, NULL );
76     else
77     {
78         LARGE_INTEGER time;
79
80         time.QuadPart = timeout * (ULONGLONG)10000;
81         time.QuadPart = -time.QuadPart;
82         status = NtDelayExecution( alertable, &time );
83     }
84     if (status != STATUS_USER_APC) status = STATUS_SUCCESS;
85     return status;
86 }
87
88
89 /***********************************************************************
90  *           WaitForSingleObject   (KERNEL32.@)
91  */
92 DWORD WINAPI WaitForSingleObject( HANDLE handle, DWORD timeout )
93 {
94     return WaitForMultipleObjectsEx( 1, &handle, FALSE, timeout, FALSE );
95 }
96
97
98 /***********************************************************************
99  *           WaitForSingleObjectEx   (KERNEL32.@)
100  */
101 DWORD WINAPI WaitForSingleObjectEx( HANDLE handle, DWORD timeout,
102                                     BOOL alertable )
103 {
104     return WaitForMultipleObjectsEx( 1, &handle, FALSE, timeout, alertable );
105 }
106
107
108 /***********************************************************************
109  *           WaitForMultipleObjects   (KERNEL32.@)
110  */
111 DWORD WINAPI WaitForMultipleObjects( DWORD count, const HANDLE *handles,
112                                      BOOL wait_all, DWORD timeout )
113 {
114     return WaitForMultipleObjectsEx( count, handles, wait_all, timeout, FALSE );
115 }
116
117
118 /***********************************************************************
119  *           WaitForMultipleObjectsEx   (KERNEL32.@)
120  */
121 DWORD WINAPI WaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
122                                        BOOL wait_all, DWORD timeout,
123                                        BOOL alertable )
124 {
125     NTSTATUS status;
126     HANDLE hloc[MAXIMUM_WAIT_OBJECTS];
127     int i;
128
129     if (count >= MAXIMUM_WAIT_OBJECTS)
130     {
131         SetLastError(ERROR_INVALID_PARAMETER);
132         return WAIT_FAILED;
133     }
134     for (i = 0; i < count; i++)
135     {
136         if ((handles[i] == (HANDLE)STD_INPUT_HANDLE) ||
137             (handles[i] == (HANDLE)STD_OUTPUT_HANDLE) ||
138             (handles[i] == (HANDLE)STD_ERROR_HANDLE))
139             hloc[i] = GetStdHandle( (DWORD)handles[i] );
140         else
141             hloc[i] = handles[i];
142
143         /* yes, even screen buffer console handles are waitable, and are
144          * handled as a handle to the console itself !!
145          */
146         if (is_console_handle(hloc[i]))
147         {
148             if (!VerifyConsoleIoHandle(hloc[i]))
149             {
150                 return FALSE;
151             }
152             hloc[i] = GetConsoleInputWaitHandle();
153         }
154     }
155
156     if (timeout == INFINITE)
157     {
158         status = NtWaitForMultipleObjects( count, hloc, wait_all, alertable, NULL );
159     }
160     else
161     {
162         LARGE_INTEGER time;
163
164         time.QuadPart = timeout * (ULONGLONG)10000;
165         time.QuadPart = -time.QuadPart;
166         status = NtWaitForMultipleObjects( count, hloc, wait_all, alertable, &time );
167     }
168
169     if (HIWORD(status))  /* is it an error code? */
170     {
171         SetLastError( RtlNtStatusToDosError(status) );
172         status = WAIT_FAILED;
173     }
174     return status;
175 }
176
177
178 /***********************************************************************
179  *           WaitForSingleObject   (KERNEL.460)
180  */
181 DWORD WINAPI WaitForSingleObject16( HANDLE handle, DWORD timeout )
182 {
183     DWORD retval, mutex_count;
184
185     ReleaseThunkLock( &mutex_count );
186     retval = WaitForSingleObject( handle, timeout );
187     RestoreThunkLock( mutex_count );
188     return retval;
189 }
190
191 /***********************************************************************
192  *           WaitForMultipleObjects   (KERNEL.461)
193  */
194 DWORD WINAPI WaitForMultipleObjects16( DWORD count, const HANDLE *handles,
195                                        BOOL wait_all, DWORD timeout )
196 {
197     DWORD retval, mutex_count;
198
199     ReleaseThunkLock( &mutex_count );
200     retval = WaitForMultipleObjectsEx( count, handles, wait_all, timeout, FALSE );
201     RestoreThunkLock( mutex_count );
202     return retval;
203 }
204
205 /***********************************************************************
206  *           WaitForMultipleObjectsEx   (KERNEL.495)
207  */
208 DWORD WINAPI WaitForMultipleObjectsEx16( DWORD count, const HANDLE *handles,
209                                          BOOL wait_all, DWORD timeout, BOOL alertable )
210 {
211     DWORD retval, mutex_count;
212
213     ReleaseThunkLock( &mutex_count );
214     retval = WaitForMultipleObjectsEx( count, handles, wait_all, timeout, alertable );
215     RestoreThunkLock( mutex_count );
216     return retval;
217 }
218
219 /***********************************************************************
220  *           InitializeCriticalSection   (KERNEL32.@)
221  *
222  * Initialise a critical section before use.
223  *
224  * PARAMS
225  *  crit [O] Critical section to initialise.
226  *
227  * RETURNS
228  *  Nothing. If the function fails an exception is raised.
229  */
230 void WINAPI InitializeCriticalSection( CRITICAL_SECTION *crit )
231 {
232     NTSTATUS ret = RtlInitializeCriticalSection( crit );
233     if (ret) RtlRaiseStatus( ret );
234 }
235
236 /***********************************************************************
237  *           InitializeCriticalSectionAndSpinCount   (KERNEL32.@)
238  *
239  * Initialise a critical section with a spin count.
240  *
241  * PARAMS
242  *  crit      [O] Critical section to initialise.
243  *  spincount [I] Number of times to spin upon contention.
244  *
245  * RETURNS
246  *  Success: TRUE.
247  *  Failure: Nothing. If the function fails an exception is raised.
248  *
249  * NOTES
250  *  spincount is ignored on uni-processor systems.
251  */
252 BOOL WINAPI InitializeCriticalSectionAndSpinCount( CRITICAL_SECTION *crit, DWORD spincount )
253 {
254     NTSTATUS ret = RtlInitializeCriticalSectionAndSpinCount( crit, spincount );
255     if (ret) RtlRaiseStatus( ret );
256     return !ret;
257 }
258
259 /***********************************************************************
260  *           SetCriticalSectionSpinCount   (KERNEL32.@)
261  *
262  * Set the spin count for a critical section.
263  *
264  * PARAMS
265  *  crit      [O] Critical section to set the spin count for.
266  *  spincount [I] Number of times to spin upon contention.
267  *
268  * RETURNS
269  *  The previous spin count value of crit.
270  *
271  * NOTES
272  *  This function is available on NT4SP3 or later, but not Win98.
273  */
274 DWORD WINAPI SetCriticalSectionSpinCount( CRITICAL_SECTION *crit, DWORD spincount )
275 {
276     ULONG_PTR oldspincount = crit->SpinCount;
277     if(spincount) FIXME("critsection=%p: spincount=%ld not supported\n", crit, spincount);
278     crit->SpinCount = spincount;
279     return oldspincount;
280 }
281
282 /***********************************************************************
283  *           MakeCriticalSectionGlobal   (KERNEL32.@)
284  */
285 void WINAPI MakeCriticalSectionGlobal( CRITICAL_SECTION *crit )
286 {
287     /* let's assume that only one thread at a time will try to do this */
288     HANDLE sem = crit->LockSemaphore;
289     if (!sem) NtCreateSemaphore( &sem, SEMAPHORE_ALL_ACCESS, NULL, 0, 1 );
290     crit->LockSemaphore = ConvertToGlobalHandle( sem );
291     if (crit->DebugInfo)
292     {
293         RtlFreeHeap( GetProcessHeap(), 0, crit->DebugInfo );
294         crit->DebugInfo = NULL;
295     }
296 }
297
298
299 /***********************************************************************
300  *           ReinitializeCriticalSection   (KERNEL32.@)
301  *
302  * Initialise an already used critical section.
303  *
304  * PARAMS
305  *  crit [O] Critical section to initialise.
306  *
307  * RETURNS
308  *  Nothing.
309  */
310 void WINAPI ReinitializeCriticalSection( CRITICAL_SECTION *crit )
311 {
312     if ( !crit->LockSemaphore )
313         RtlInitializeCriticalSection( crit );
314 }
315
316
317 /***********************************************************************
318  *           UninitializeCriticalSection   (KERNEL32.@)
319  *
320  * UnInitialise a critical section after use.
321  *
322  * PARAMS
323  *  crit [O] Critical section to uninitialise (destroy).
324  *
325  * RETURNS
326  *  Nothing.
327  */
328 void WINAPI UninitializeCriticalSection( CRITICAL_SECTION *crit )
329 {
330     RtlDeleteCriticalSection( crit );
331 }
332
333
334 /***********************************************************************
335  *           CreateEventA    (KERNEL32.@)
336  */
337 HANDLE WINAPI CreateEventA( SECURITY_ATTRIBUTES *sa, BOOL manual_reset,
338                             BOOL initial_state, LPCSTR name )
339 {
340     WCHAR buffer[MAX_PATH];
341
342     if (!name) return CreateEventW( sa, manual_reset, initial_state, NULL );
343
344     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
345     {
346         SetLastError( ERROR_FILENAME_EXCED_RANGE );
347         return 0;
348     }
349     return CreateEventW( sa, manual_reset, initial_state, buffer );
350 }
351
352
353 /***********************************************************************
354  *           CreateEventW    (KERNEL32.@)
355  */
356 HANDLE WINAPI CreateEventW( SECURITY_ATTRIBUTES *sa, BOOL manual_reset,
357                             BOOL initial_state, LPCWSTR name )
358 {
359     HANDLE ret;
360     DWORD len = name ? strlenW(name) : 0;
361     if (len >= MAX_PATH)
362     {
363         SetLastError( ERROR_FILENAME_EXCED_RANGE );
364         return 0;
365     }
366     /* one buggy program needs this
367      * ("Van Dale Groot woordenboek der Nederlandse taal")
368      */
369     if (sa && IsBadReadPtr(sa,sizeof(SECURITY_ATTRIBUTES)))
370     {
371         ERR("Bad security attributes pointer %p\n",sa);
372         SetLastError( ERROR_INVALID_PARAMETER);
373         return 0;
374     }
375     SERVER_START_REQ( create_event )
376     {
377         req->manual_reset = manual_reset;
378         req->initial_state = initial_state;
379         req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
380         wine_server_add_data( req, name, len * sizeof(WCHAR) );
381         SetLastError(0);
382         wine_server_call_err( req );
383         ret = reply->handle;
384     }
385     SERVER_END_REQ;
386     return ret;
387 }
388
389
390 /***********************************************************************
391  *           CreateW32Event    (KERNEL.457)
392  */
393 HANDLE WINAPI WIN16_CreateEvent( BOOL manual_reset, BOOL initial_state )
394 {
395     return CreateEventA( NULL, manual_reset, initial_state, NULL );
396 }
397
398
399 /***********************************************************************
400  *           OpenEventA    (KERNEL32.@)
401  */
402 HANDLE WINAPI OpenEventA( DWORD access, BOOL inherit, LPCSTR name )
403 {
404     WCHAR buffer[MAX_PATH];
405
406     if (!name) return OpenEventW( access, inherit, NULL );
407
408     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
409     {
410         SetLastError( ERROR_FILENAME_EXCED_RANGE );
411         return 0;
412     }
413     return OpenEventW( access, inherit, buffer );
414 }
415
416
417 /***********************************************************************
418  *           OpenEventW    (KERNEL32.@)
419  */
420 HANDLE WINAPI OpenEventW( DWORD access, BOOL inherit, LPCWSTR name )
421 {
422     HANDLE ret;
423     DWORD len = name ? strlenW(name) : 0;
424     if (len >= MAX_PATH)
425     {
426         SetLastError( ERROR_FILENAME_EXCED_RANGE );
427         return 0;
428     }
429     if (!is_version_nt()) access = EVENT_ALL_ACCESS;
430
431     SERVER_START_REQ( open_event )
432     {
433         req->access  = access;
434         req->inherit = inherit;
435         wine_server_add_data( req, name, len * sizeof(WCHAR) );
436         wine_server_call_err( req );
437         ret = reply->handle;
438     }
439     SERVER_END_REQ;
440     return ret;
441 }
442
443
444 /***********************************************************************
445  *           EVENT_Operation
446  *
447  * Execute an event operation (set,reset,pulse).
448  */
449 static BOOL EVENT_Operation( HANDLE handle, enum event_op op )
450 {
451     BOOL ret;
452     SERVER_START_REQ( event_op )
453     {
454         req->handle = handle;
455         req->op     = op;
456         ret = !wine_server_call_err( req );
457     }
458     SERVER_END_REQ;
459     return ret;
460 }
461
462
463 /***********************************************************************
464  *           PulseEvent    (KERNEL32.@)
465  */
466 BOOL WINAPI PulseEvent( HANDLE handle )
467 {
468     return EVENT_Operation( handle, PULSE_EVENT );
469 }
470
471
472 /***********************************************************************
473  *           SetW32Event (KERNEL.458)
474  *           SetEvent    (KERNEL32.@)
475  */
476 BOOL WINAPI SetEvent( HANDLE handle )
477 {
478     return EVENT_Operation( handle, SET_EVENT );
479 }
480
481
482 /***********************************************************************
483  *           ResetW32Event (KERNEL.459)
484  *           ResetEvent    (KERNEL32.@)
485  */
486 BOOL WINAPI ResetEvent( HANDLE handle )
487 {
488     return EVENT_Operation( handle, RESET_EVENT );
489 }
490
491
492 /***********************************************************************
493  * NOTE: The Win95 VWin32_Event routines given below are really low-level
494  *       routines implemented directly by VWin32. The user-mode libraries
495  *       implement Win32 synchronisation routines on top of these low-level
496  *       primitives. We do it the other way around here :-)
497  */
498
499 /***********************************************************************
500  *       VWin32_EventCreate     (KERNEL.442)
501  */
502 HANDLE WINAPI VWin32_EventCreate(VOID)
503 {
504     HANDLE hEvent = CreateEventA( NULL, FALSE, 0, NULL );
505     return ConvertToGlobalHandle( hEvent );
506 }
507
508 /***********************************************************************
509  *       VWin32_EventDestroy    (KERNEL.443)
510  */
511 VOID WINAPI VWin32_EventDestroy(HANDLE event)
512 {
513     CloseHandle( event );
514 }
515
516 /***********************************************************************
517  *       VWin32_EventWait       (KERNEL.450)
518  */
519 VOID WINAPI VWin32_EventWait(HANDLE event)
520 {
521     DWORD mutex_count;
522
523     ReleaseThunkLock( &mutex_count );
524     WaitForSingleObject( event, INFINITE );
525     RestoreThunkLock( mutex_count );
526 }
527
528 /***********************************************************************
529  *       VWin32_EventSet        (KERNEL.451)
530  *       KERNEL_479             (KERNEL.479)
531  */
532 VOID WINAPI VWin32_EventSet(HANDLE event)
533 {
534     SetEvent( event );
535 }
536
537
538
539 /***********************************************************************
540  *           CreateMutexA   (KERNEL32.@)
541  */
542 HANDLE WINAPI CreateMutexA( SECURITY_ATTRIBUTES *sa, BOOL owner, LPCSTR name )
543 {
544     WCHAR buffer[MAX_PATH];
545
546     if (!name) return CreateMutexW( sa, owner, NULL );
547
548     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
549     {
550         SetLastError( ERROR_FILENAME_EXCED_RANGE );
551         return 0;
552     }
553     return CreateMutexW( sa, owner, buffer );
554 }
555
556
557 /***********************************************************************
558  *           CreateMutexW   (KERNEL32.@)
559  */
560 HANDLE WINAPI CreateMutexW( SECURITY_ATTRIBUTES *sa, BOOL owner, LPCWSTR name )
561 {
562     HANDLE ret;
563     DWORD len = name ? strlenW(name) : 0;
564     if (len >= MAX_PATH)
565     {
566         SetLastError( ERROR_FILENAME_EXCED_RANGE );
567         return 0;
568     }
569     SERVER_START_REQ( create_mutex )
570     {
571         req->owned   = owner;
572         req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
573         wine_server_add_data( req, name, len * sizeof(WCHAR) );
574         SetLastError(0);
575         wine_server_call_err( req );
576         ret = reply->handle;
577     }
578     SERVER_END_REQ;
579     return ret;
580 }
581
582
583 /***********************************************************************
584  *           OpenMutexA   (KERNEL32.@)
585  */
586 HANDLE WINAPI OpenMutexA( DWORD access, BOOL inherit, LPCSTR name )
587 {
588     WCHAR buffer[MAX_PATH];
589
590     if (!name) return OpenMutexW( access, inherit, NULL );
591
592     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
593     {
594         SetLastError( ERROR_FILENAME_EXCED_RANGE );
595         return 0;
596     }
597     return OpenMutexW( access, inherit, buffer );
598 }
599
600
601 /***********************************************************************
602  *           OpenMutexW   (KERNEL32.@)
603  */
604 HANDLE WINAPI OpenMutexW( DWORD access, BOOL inherit, LPCWSTR name )
605 {
606     HANDLE ret;
607     DWORD len = name ? strlenW(name) : 0;
608     if (len >= MAX_PATH)
609     {
610         SetLastError( ERROR_FILENAME_EXCED_RANGE );
611         return 0;
612     }
613     if (!is_version_nt()) access = MUTEX_ALL_ACCESS;
614
615     SERVER_START_REQ( open_mutex )
616     {
617         req->access  = access;
618         req->inherit = inherit;
619         wine_server_add_data( req, name, len * sizeof(WCHAR) );
620         wine_server_call_err( req );
621         ret = reply->handle;
622     }
623     SERVER_END_REQ;
624     return ret;
625 }
626
627
628 /***********************************************************************
629  *           ReleaseMutex   (KERNEL32.@)
630  */
631 BOOL WINAPI ReleaseMutex( HANDLE handle )
632 {
633     BOOL ret;
634     SERVER_START_REQ( release_mutex )
635     {
636         req->handle = handle;
637         ret = !wine_server_call_err( req );
638     }
639     SERVER_END_REQ;
640     return ret;
641 }
642
643
644 /*
645  * Semaphores
646  */
647
648
649 /***********************************************************************
650  *           CreateSemaphoreA   (KERNEL32.@)
651  */
652 HANDLE WINAPI CreateSemaphoreA( SECURITY_ATTRIBUTES *sa, LONG initial, LONG max, LPCSTR name )
653 {
654     WCHAR buffer[MAX_PATH];
655
656     if (!name) return CreateSemaphoreW( sa, initial, max, NULL );
657
658     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
659     {
660         SetLastError( ERROR_FILENAME_EXCED_RANGE );
661         return 0;
662     }
663     return CreateSemaphoreW( sa, initial, max, buffer );
664 }
665
666
667 /***********************************************************************
668  *           CreateSemaphoreW   (KERNEL32.@)
669  */
670 HANDLE WINAPI CreateSemaphoreW( SECURITY_ATTRIBUTES *sa, LONG initial,
671                                     LONG max, LPCWSTR name )
672 {
673     HANDLE ret;
674     DWORD len = name ? strlenW(name) : 0;
675
676     /* Check parameters */
677
678     if ((max <= 0) || (initial < 0) || (initial > max))
679     {
680         SetLastError( ERROR_INVALID_PARAMETER );
681         return 0;
682     }
683     if (len >= MAX_PATH)
684     {
685         SetLastError( ERROR_FILENAME_EXCED_RANGE );
686         return 0;
687     }
688
689     SERVER_START_REQ( create_semaphore )
690     {
691         req->initial = (unsigned int)initial;
692         req->max     = (unsigned int)max;
693         req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
694         wine_server_add_data( req, name, len * sizeof(WCHAR) );
695         SetLastError(0);
696         wine_server_call_err( req );
697         ret = reply->handle;
698     }
699     SERVER_END_REQ;
700     return ret;
701 }
702
703
704 /***********************************************************************
705  *           OpenSemaphoreA   (KERNEL32.@)
706  */
707 HANDLE WINAPI OpenSemaphoreA( DWORD access, BOOL inherit, LPCSTR name )
708 {
709     WCHAR buffer[MAX_PATH];
710
711     if (!name) return OpenSemaphoreW( access, inherit, NULL );
712
713     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
714     {
715         SetLastError( ERROR_FILENAME_EXCED_RANGE );
716         return 0;
717     }
718     return OpenSemaphoreW( access, inherit, buffer );
719 }
720
721
722 /***********************************************************************
723  *           OpenSemaphoreW   (KERNEL32.@)
724  */
725 HANDLE WINAPI OpenSemaphoreW( DWORD access, BOOL inherit, LPCWSTR name )
726 {
727     HANDLE ret;
728     DWORD len = name ? strlenW(name) : 0;
729     if (len >= MAX_PATH)
730     {
731         SetLastError( ERROR_FILENAME_EXCED_RANGE );
732         return 0;
733     }
734     if (!is_version_nt()) access = SEMAPHORE_ALL_ACCESS;
735
736     SERVER_START_REQ( open_semaphore )
737     {
738         req->access  = access;
739         req->inherit = inherit;
740         wine_server_add_data( req, name, len * sizeof(WCHAR) );
741         wine_server_call_err( req );
742         ret = reply->handle;
743     }
744     SERVER_END_REQ;
745     return ret;
746 }
747
748
749 /***********************************************************************
750  *           ReleaseSemaphore   (KERNEL32.@)
751  */
752 BOOL WINAPI ReleaseSemaphore( HANDLE handle, LONG count, LONG *previous )
753 {
754     NTSTATUS status = NtReleaseSemaphore( handle, count, previous );
755     if (status) SetLastError( RtlNtStatusToDosError(status) );
756     return !status;
757 }
758
759
760 /*
761  * Timers
762  */
763
764
765 /***********************************************************************
766  *           CreateWaitableTimerA    (KERNEL32.@)
767  */
768 HANDLE WINAPI CreateWaitableTimerA( SECURITY_ATTRIBUTES *sa, BOOL manual, LPCSTR name )
769 {
770     WCHAR buffer[MAX_PATH];
771
772     if (!name) return CreateWaitableTimerW( sa, manual, NULL );
773
774     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
775     {
776         SetLastError( ERROR_FILENAME_EXCED_RANGE );
777         return 0;
778     }
779     return CreateWaitableTimerW( sa, manual, buffer );
780 }
781
782
783 /***********************************************************************
784  *           CreateWaitableTimerW    (KERNEL32.@)
785  */
786 HANDLE WINAPI CreateWaitableTimerW( SECURITY_ATTRIBUTES *sa, BOOL manual, LPCWSTR name )
787 {
788     HANDLE              handle;
789     NTSTATUS            status;
790     UNICODE_STRING      us;
791     DWORD               attr = 0;
792     OBJECT_ATTRIBUTES   oa;
793
794     if (name) RtlInitUnicodeString(&us, name);
795     if (sa && (sa->nLength >= sizeof(*sa)) && sa->bInheritHandle)
796         attr |= OBJ_INHERIT;
797     InitializeObjectAttributes(&oa, name ? &us : NULL, attr,
798                                NULL /* FIXME */, NULL /* FIXME */);
799     status = NtCreateTimer(&handle, TIMER_ALL_ACCESS, &oa,
800                            manual ? NotificationTimer : SynchronizationTimer);
801
802     if (status != STATUS_SUCCESS)
803     {
804         SetLastError( RtlNtStatusToDosError(status) );
805         return 0;
806     }
807     return handle;
808 }
809
810
811 /***********************************************************************
812  *           OpenWaitableTimerA    (KERNEL32.@)
813  */
814 HANDLE WINAPI OpenWaitableTimerA( DWORD access, BOOL inherit, LPCSTR name )
815 {
816     WCHAR buffer[MAX_PATH];
817
818     if (!name) return OpenWaitableTimerW( access, inherit, NULL );
819
820     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
821     {
822         SetLastError( ERROR_FILENAME_EXCED_RANGE );
823         return 0;
824     }
825     return OpenWaitableTimerW( access, inherit, buffer );
826 }
827
828
829 /***********************************************************************
830  *           OpenWaitableTimerW    (KERNEL32.@)
831  */
832 HANDLE WINAPI OpenWaitableTimerW( DWORD access, BOOL inherit, LPCWSTR name )
833 {
834     NTSTATUS            status;
835     ULONG               attr = 0;
836     UNICODE_STRING      us;
837     HANDLE              handle;
838     OBJECT_ATTRIBUTES   oa;
839
840     if (inherit) attr |= OBJ_INHERIT;
841
842     if (name) RtlInitUnicodeString(&us, name);
843     InitializeObjectAttributes(&oa, name ? &us : NULL, attr, NULL /* FIXME */, NULL /* FIXME */);
844     status = NtOpenTimer(&handle, access, &oa);
845     if (status != STATUS_SUCCESS)
846     {
847         SetLastError( RtlNtStatusToDosError(status) );
848         return 0;
849     }
850     return handle;
851 }
852
853
854 /***********************************************************************
855  *           SetWaitableTimer    (KERNEL32.@)
856  */
857 BOOL WINAPI SetWaitableTimer( HANDLE handle, const LARGE_INTEGER *when, LONG period,
858                               PTIMERAPCROUTINE callback, LPVOID arg, BOOL resume )
859 {
860     NTSTATUS status = NtSetTimer(handle, when, callback, arg, resume, period, NULL);
861
862     if (status != STATUS_SUCCESS)
863     {
864         SetLastError( RtlNtStatusToDosError(status) );
865         if (status != STATUS_TIMER_RESUME_IGNORED) return FALSE;
866     }
867     return TRUE;
868 }
869
870
871 /***********************************************************************
872  *           CancelWaitableTimer    (KERNEL32.@)
873  */
874 BOOL WINAPI CancelWaitableTimer( HANDLE handle )
875 {
876     NTSTATUS status;
877
878     status = NtCancelTimer(handle, NULL);
879     if (status != STATUS_SUCCESS)
880     {
881         SetLastError( RtlNtStatusToDosError(status) );
882         return FALSE;
883     }
884     return TRUE;
885 }
886
887
888 /***********************************************************************
889  *           CreateTimerQueue  (KERNEL32.@)
890  */
891 HANDLE WINAPI CreateTimerQueue(void)
892 {
893     FIXME("stub\n");
894     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
895     return NULL;
896 }
897
898
899 /***********************************************************************
900  *           DeleteTimerQueueEx  (KERNEL32.@)
901  */
902 BOOL WINAPI DeleteTimerQueueEx(HANDLE TimerQueue, HANDLE CompletionEvent)
903 {
904     FIXME("(%p, %p): stub\n", TimerQueue, CompletionEvent);
905     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
906     return 0;
907 }
908
909 /***********************************************************************
910  *           CreateTimerQueueTimer  (KERNEL32.@)
911  *
912  * Creates a timer-queue timer. This timer expires at the specified due
913  * time (in ms), then after every specified period (in ms). When the timer
914  * expires, the callback function is called.
915  *
916  * RETURNS
917  *   nonzero on success or zero on faillure
918  *
919  * BUGS
920  *   Unimplemented
921  */
922 BOOL WINAPI CreateTimerQueueTimer( PHANDLE phNewTimer, HANDLE TimerQueue,
923                                    WAITORTIMERCALLBACK Callback, PVOID Parameter,
924                                    DWORD DueTime, DWORD Period, ULONG Flags )
925 {
926     FIXME("stub\n");
927     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
928     return TRUE;
929 }
930
931 /***********************************************************************
932  *           DeleteTimerQueueTimer  (KERNEL32.@)
933  *
934  * Cancels a timer-queue timer.
935  *
936  * RETURNS
937  *   nonzero on success or zero on faillure
938  *
939  * BUGS
940  *   Unimplemented
941  */
942 BOOL WINAPI DeleteTimerQueueTimer( HANDLE TimerQueue, HANDLE Timer,
943                                    HANDLE CompletionEvent )
944 {
945     FIXME("stub\n");
946     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
947     return TRUE;
948 }
949
950
951 /*
952  * Pipes
953  */
954
955
956 /***********************************************************************
957  *           CreateNamedPipeA   (KERNEL32.@)
958  */
959 HANDLE WINAPI CreateNamedPipeA( LPCSTR name, DWORD dwOpenMode,
960                                 DWORD dwPipeMode, DWORD nMaxInstances,
961                                 DWORD nOutBufferSize, DWORD nInBufferSize,
962                                 DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES attr )
963 {
964     WCHAR buffer[MAX_PATH];
965
966     if (!name) return CreateNamedPipeW( NULL, dwOpenMode, dwPipeMode, nMaxInstances,
967                                         nOutBufferSize, nInBufferSize, nDefaultTimeOut, attr );
968
969     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
970     {
971         SetLastError( ERROR_FILENAME_EXCED_RANGE );
972         return INVALID_HANDLE_VALUE;
973     }
974     return CreateNamedPipeW( buffer, dwOpenMode, dwPipeMode, nMaxInstances,
975                              nOutBufferSize, nInBufferSize, nDefaultTimeOut, attr );
976 }
977
978
979 /***********************************************************************
980  *           CreateNamedPipeW   (KERNEL32.@)
981  */
982 HANDLE WINAPI CreateNamedPipeW( LPCWSTR name, DWORD dwOpenMode,
983                                 DWORD dwPipeMode, DWORD nMaxInstances,
984                                 DWORD nOutBufferSize, DWORD nInBufferSize,
985                                 DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES attr )
986 {
987     HANDLE ret;
988     DWORD len;
989     static const WCHAR leadin[] = {'\\','\\','.','\\','P','I','P','E','\\'};
990
991     TRACE("(%s, %#08lx, %#08lx, %ld, %ld, %ld, %ld, %p)\n",
992           debugstr_w(name), dwOpenMode, dwPipeMode, nMaxInstances,
993           nOutBufferSize, nInBufferSize, nDefaultTimeOut, attr );
994
995     if (!name)
996     {
997         SetLastError( ERROR_PATH_NOT_FOUND );
998         return INVALID_HANDLE_VALUE;
999     }
1000     len = strlenW(name);
1001     if (len >= MAX_PATH)
1002     {
1003         SetLastError( ERROR_FILENAME_EXCED_RANGE );
1004         return INVALID_HANDLE_VALUE;
1005     }
1006     if (strncmpiW(name, leadin, sizeof(leadin)/sizeof(leadin[0])))
1007     {
1008         SetLastError( ERROR_INVALID_NAME );
1009         return INVALID_HANDLE_VALUE;
1010     }
1011     SERVER_START_REQ( create_named_pipe )
1012     {
1013         req->openmode = dwOpenMode;
1014         req->pipemode = dwPipeMode;
1015         req->maxinstances = nMaxInstances;
1016         req->outsize = nOutBufferSize;
1017         req->insize = nInBufferSize;
1018         req->timeout = nDefaultTimeOut;
1019         wine_server_add_data( req, name, len * sizeof(WCHAR) );
1020         SetLastError(0);
1021         if (!wine_server_call_err( req )) ret = reply->handle;
1022         else ret = INVALID_HANDLE_VALUE;
1023     }
1024     SERVER_END_REQ;
1025     return ret;
1026 }
1027
1028
1029 /***********************************************************************
1030  *           PeekNamedPipe   (KERNEL32.@)
1031  */
1032 BOOL WINAPI PeekNamedPipe( HANDLE hPipe, LPVOID lpvBuffer, DWORD cbBuffer,
1033                            LPDWORD lpcbRead, LPDWORD lpcbAvail, LPDWORD lpcbMessage )
1034 {
1035 #ifdef FIONREAD
1036     int avail=0,fd;
1037
1038     fd = FILE_GetUnixHandle(hPipe, GENERIC_READ);
1039     if (fd == -1) return FALSE;
1040
1041     if (ioctl(fd,FIONREAD, &avail ) != 0)
1042     {
1043         TRACE("FIONREAD failed reason: %s\n",strerror(errno));
1044         close(fd);
1045         return FALSE;
1046     }
1047     if (!avail)  /* check for closed pipe */
1048     {
1049         struct pollfd pollfd;
1050         pollfd.fd = fd;
1051         pollfd.events = POLLIN;
1052         pollfd.revents = 0;
1053         switch (poll( &pollfd, 1, 0 ))
1054         {
1055         case 0:
1056             break;
1057         case 1:  /* got something */
1058             if (!(pollfd.revents & (POLLHUP | POLLERR))) break;
1059             TRACE("POLLHUP | POLLERR\n");
1060             /* fall through */
1061         case -1:
1062             close(fd);
1063             SetLastError(ERROR_BROKEN_PIPE);
1064             return FALSE;
1065         }
1066     }
1067     close(fd);
1068     TRACE(" 0x%08x bytes available\n", avail );
1069     if (!lpvBuffer && lpcbAvail)
1070       {
1071         *lpcbAvail= avail;
1072         return TRUE;
1073       }
1074 #endif /* defined(FIONREAD) */
1075
1076     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1077     FIXME("function not implemented\n");
1078     return FALSE;
1079 }
1080
1081 /***********************************************************************
1082  *           SYNC_CompletePipeOverlapped   (Internal)
1083  */
1084 static void SYNC_CompletePipeOverlapped (LPOVERLAPPED overlapped, DWORD result)
1085 {
1086     TRACE("for %p result %08lx\n",overlapped,result);
1087     if(!overlapped)
1088         return;
1089     overlapped->Internal = result;
1090     SetEvent(overlapped->hEvent);
1091 }
1092
1093
1094 /***********************************************************************
1095  *           WaitNamedPipeA   (KERNEL32.@)
1096  */
1097 BOOL WINAPI WaitNamedPipeA (LPCSTR name, DWORD nTimeOut)
1098 {
1099     WCHAR buffer[MAX_PATH];
1100
1101     if (!name) return WaitNamedPipeW( NULL, nTimeOut );
1102
1103     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
1104     {
1105         SetLastError( ERROR_FILENAME_EXCED_RANGE );
1106         return 0;
1107     }
1108     return WaitNamedPipeW( buffer, nTimeOut );
1109 }
1110
1111
1112 /***********************************************************************
1113  *           WaitNamedPipeW   (KERNEL32.@)
1114  */
1115 BOOL WINAPI WaitNamedPipeW (LPCWSTR name, DWORD nTimeOut)
1116 {
1117     DWORD len = name ? strlenW(name) : 0;
1118     BOOL ret;
1119     OVERLAPPED ov;
1120
1121     if (len >= MAX_PATH)
1122     {
1123         SetLastError( ERROR_FILENAME_EXCED_RANGE );
1124         return FALSE;
1125     }
1126
1127     TRACE("%s 0x%08lx\n",debugstr_w(name),nTimeOut);
1128
1129     memset(&ov,0,sizeof(ov));
1130     ov.hEvent = CreateEventA( NULL, 0, 0, NULL );
1131     if (!ov.hEvent)
1132         return FALSE;
1133
1134     SERVER_START_REQ( wait_named_pipe )
1135     {
1136         req->timeout = nTimeOut;
1137         req->overlapped = &ov;
1138         req->func = SYNC_CompletePipeOverlapped;
1139         wine_server_add_data( req, name, len * sizeof(WCHAR) );
1140         ret = !wine_server_call_err( req );
1141     }
1142     SERVER_END_REQ;
1143
1144     if(ret)
1145     {
1146         if (WAIT_OBJECT_0==WaitForSingleObject(ov.hEvent,INFINITE))
1147         {
1148             SetLastError(ov.Internal);
1149             ret = (ov.Internal==STATUS_SUCCESS);
1150         }
1151     }
1152     CloseHandle(ov.hEvent);
1153     return ret;
1154 }
1155
1156
1157 /***********************************************************************
1158  *           SYNC_ConnectNamedPipe   (Internal)
1159  */
1160 static BOOL SYNC_ConnectNamedPipe(HANDLE hPipe, LPOVERLAPPED overlapped)
1161 {
1162     BOOL ret;
1163
1164     if(!overlapped)
1165         return FALSE;
1166
1167     overlapped->Internal = STATUS_PENDING;
1168
1169     SERVER_START_REQ( connect_named_pipe )
1170     {
1171         req->handle = hPipe;
1172         req->overlapped = overlapped;
1173         req->func = SYNC_CompletePipeOverlapped;
1174         ret = !wine_server_call_err( req );
1175     }
1176     SERVER_END_REQ;
1177
1178     return ret;
1179 }
1180
1181 /***********************************************************************
1182  *           ConnectNamedPipe   (KERNEL32.@)
1183  */
1184 BOOL WINAPI ConnectNamedPipe(HANDLE hPipe, LPOVERLAPPED overlapped)
1185 {
1186     OVERLAPPED ov;
1187     BOOL ret;
1188
1189     TRACE("(%p,%p)\n",hPipe, overlapped);
1190
1191     if(overlapped)
1192     {
1193         if(SYNC_ConnectNamedPipe(hPipe,overlapped))
1194             SetLastError( ERROR_IO_PENDING );
1195         return FALSE;
1196     }
1197
1198     memset(&ov,0,sizeof(ov));
1199     ov.hEvent = CreateEventA(NULL,0,0,NULL);
1200     if (!ov.hEvent)
1201         return FALSE;
1202
1203     ret=SYNC_ConnectNamedPipe(hPipe, &ov);
1204     if(ret)
1205     {
1206         if (WAIT_OBJECT_0==WaitForSingleObject(ov.hEvent,INFINITE))
1207         {
1208             SetLastError(ov.Internal);
1209             ret = (ov.Internal==STATUS_SUCCESS);
1210         }
1211     }
1212
1213     CloseHandle(ov.hEvent);
1214
1215     return ret;
1216 }
1217
1218 /***********************************************************************
1219  *           DisconnectNamedPipe   (KERNEL32.@)
1220  */
1221 BOOL WINAPI DisconnectNamedPipe(HANDLE hPipe)
1222 {
1223     BOOL ret;
1224
1225     TRACE("(%p)\n",hPipe);
1226
1227     SERVER_START_REQ( disconnect_named_pipe )
1228     {
1229         req->handle = hPipe;
1230         ret = !wine_server_call_err( req );
1231         if (ret && reply->fd != -1) close( reply->fd );
1232     }
1233     SERVER_END_REQ;
1234
1235     return ret;
1236 }
1237
1238 /***********************************************************************
1239  *           TransactNamedPipe   (KERNEL32.@)
1240  */
1241 BOOL WINAPI TransactNamedPipe(
1242     HANDLE hPipe, LPVOID lpInput, DWORD dwInputSize, LPVOID lpOutput,
1243     DWORD dwOutputSize, LPDWORD lpBytesRead, LPOVERLAPPED lpOverlapped)
1244 {
1245     FIXME("%p %p %ld %p %ld %p %p\n",
1246           hPipe, lpInput, dwInputSize, lpOutput,
1247           dwOutputSize, lpBytesRead, lpOverlapped);
1248     if(lpBytesRead)
1249         *lpBytesRead=0;
1250     return FALSE;
1251 }
1252
1253 /***********************************************************************
1254  *           GetNamedPipeInfo   (KERNEL32.@)
1255  */
1256 BOOL WINAPI GetNamedPipeInfo(
1257     HANDLE hNamedPipe, LPDWORD lpFlags, LPDWORD lpOutputBufferSize,
1258     LPDWORD lpInputBufferSize, LPDWORD lpMaxInstances)
1259 {
1260     BOOL ret;
1261
1262     TRACE("%p %p %p %p %p\n", hNamedPipe, lpFlags,
1263           lpOutputBufferSize, lpInputBufferSize, lpMaxInstances);
1264
1265     SERVER_START_REQ( get_named_pipe_info )
1266     {
1267         req->handle = hNamedPipe;
1268         ret = !wine_server_call_err( req );
1269         if(lpFlags) *lpFlags = reply->flags;
1270         if(lpOutputBufferSize) *lpOutputBufferSize = reply->outsize;
1271         if(lpInputBufferSize) *lpInputBufferSize = reply->outsize;
1272         if(lpMaxInstances) *lpMaxInstances = reply->maxinstances;
1273     }
1274     SERVER_END_REQ;
1275
1276     return ret;
1277 }
1278
1279 /***********************************************************************
1280  *           GetNamedPipeHandleStateA  (KERNEL32.@)
1281  */
1282 BOOL WINAPI GetNamedPipeHandleStateA(
1283     HANDLE hNamedPipe, LPDWORD lpState, LPDWORD lpCurInstances,
1284     LPDWORD lpMaxCollectionCount, LPDWORD lpCollectDataTimeout,
1285     LPSTR lpUsername, DWORD nUsernameMaxSize)
1286 {
1287     FIXME("%p %p %p %p %p %p %ld\n",
1288           hNamedPipe, lpState, lpCurInstances,
1289           lpMaxCollectionCount, lpCollectDataTimeout,
1290           lpUsername, nUsernameMaxSize);
1291
1292     return FALSE;
1293 }
1294
1295 /***********************************************************************
1296  *           GetNamedPipeHandleStateW  (KERNEL32.@)
1297  */
1298 BOOL WINAPI GetNamedPipeHandleStateW(
1299     HANDLE hNamedPipe, LPDWORD lpState, LPDWORD lpCurInstances,
1300     LPDWORD lpMaxCollectionCount, LPDWORD lpCollectDataTimeout,
1301     LPWSTR lpUsername, DWORD nUsernameMaxSize)
1302 {
1303     FIXME("%p %p %p %p %p %p %ld\n",
1304           hNamedPipe, lpState, lpCurInstances,
1305           lpMaxCollectionCount, lpCollectDataTimeout,
1306           lpUsername, nUsernameMaxSize);
1307
1308     return FALSE;
1309 }
1310
1311 /***********************************************************************
1312  *           SetNamedPipeHandleState  (KERNEL32.@)
1313  */
1314 BOOL WINAPI SetNamedPipeHandleState(
1315     HANDLE hNamedPipe, LPDWORD lpMode, LPDWORD lpMaxCollectionCount,
1316     LPDWORD lpCollectDataTimeout)
1317 {
1318     FIXME("%p %p %p %p\n",
1319           hNamedPipe, lpMode, lpMaxCollectionCount, lpCollectDataTimeout);
1320     return FALSE;
1321 }
1322
1323 /***********************************************************************
1324  *           CallNamedPipeA  (KERNEL32.@)
1325  */
1326 BOOL WINAPI CallNamedPipeA(
1327     LPCSTR lpNamedPipeName, LPVOID lpInput, DWORD lpInputSize,
1328     LPVOID lpOutput, DWORD lpOutputSize,
1329     LPDWORD lpBytesRead, DWORD nTimeout)
1330 {
1331     FIXME("%s %p %ld %p %ld %p %ld\n",
1332            debugstr_a(lpNamedPipeName), lpInput, lpInputSize,
1333            lpOutput, lpOutputSize, lpBytesRead, nTimeout);
1334     return FALSE;
1335 }
1336
1337 /***********************************************************************
1338  *           CallNamedPipeW  (KERNEL32.@)
1339  */
1340 BOOL WINAPI CallNamedPipeW(
1341     LPCWSTR lpNamedPipeName, LPVOID lpInput, DWORD lpInputSize,
1342     LPVOID lpOutput, DWORD lpOutputSize,
1343     LPDWORD lpBytesRead, DWORD nTimeout)
1344 {
1345     FIXME("%s %p %ld %p %ld %p %ld\n",
1346            debugstr_w(lpNamedPipeName), lpInput, lpInputSize,
1347            lpOutput, lpOutputSize, lpBytesRead, nTimeout);
1348     return FALSE;
1349 }
1350
1351 /******************************************************************
1352  *              CreatePipe (KERNEL32.@)
1353  *
1354  */
1355 BOOL WINAPI CreatePipe( PHANDLE hReadPipe, PHANDLE hWritePipe,
1356                         LPSECURITY_ATTRIBUTES sa, DWORD size )
1357 {
1358     static unsigned  index = 0;
1359     char        name[64];
1360     HANDLE      hr, hw;
1361     unsigned    in_index = index;
1362
1363     *hReadPipe = *hWritePipe = INVALID_HANDLE_VALUE;
1364     /* generate a unique pipe name (system wide) */
1365     do
1366     {
1367         sprintf(name, "\\\\.\\pipe\\Win32.Pipes.%08lu.%08u", GetCurrentProcessId(), ++index);
1368         hr = CreateNamedPipeA(name, PIPE_ACCESS_INBOUND, 
1369                               PIPE_TYPE_BYTE | PIPE_WAIT, 1, size, size, 
1370                               NMPWAIT_USE_DEFAULT_WAIT, sa);
1371     } while (hr == INVALID_HANDLE_VALUE && index != in_index);
1372     /* from completion sakeness, I think system resources might be exhausted before this happens !! */
1373     if (hr == INVALID_HANDLE_VALUE) return FALSE;
1374
1375     hw = CreateFileA(name, GENERIC_WRITE, 0, sa, OPEN_EXISTING, 0, 0);
1376     if (hw == INVALID_HANDLE_VALUE) 
1377     {
1378         CloseHandle(hr);
1379         return FALSE;
1380     }
1381
1382     *hReadPipe = hr;
1383     *hWritePipe = hw;
1384     return TRUE;
1385 }
1386
1387
1388 /******************************************************************************
1389  * CreateMailslotA [KERNEL32.@]
1390  */
1391 HANDLE WINAPI CreateMailslotA( LPCSTR lpName, DWORD nMaxMessageSize,
1392                                DWORD lReadTimeout, LPSECURITY_ATTRIBUTES sa )
1393 {
1394     DWORD len;
1395     HANDLE handle;
1396     LPWSTR name = NULL;
1397
1398     TRACE("%s %ld %ld %p\n", debugstr_a(lpName),
1399           nMaxMessageSize, lReadTimeout, sa);
1400
1401     if( lpName )
1402     {
1403         len = MultiByteToWideChar( CP_ACP, 0, lpName, -1, NULL, 0 );
1404         name = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
1405         MultiByteToWideChar( CP_ACP, 0, lpName, -1, name, len );
1406     }
1407
1408     handle = CreateMailslotW( name, nMaxMessageSize, lReadTimeout, sa );
1409
1410     if( name )
1411         HeapFree( GetProcessHeap(), 0, name );
1412
1413     return handle;
1414 }
1415
1416
1417 /******************************************************************************
1418  * CreateMailslotW [KERNEL32.@]
1419  *
1420  * Create a mailslot with specified name.
1421  *
1422  * PARAMS
1423  *    lpName          [I] Pointer to string for mailslot name
1424  *    nMaxMessageSize [I] Maximum message size
1425  *    lReadTimeout    [I] Milliseconds before read time-out
1426  *    sa              [I] Pointer to security structure
1427  *
1428  * RETURNS
1429  *    Success: Handle to mailslot
1430  *    Failure: INVALID_HANDLE_VALUE
1431  */
1432 HANDLE WINAPI CreateMailslotW( LPCWSTR lpName, DWORD nMaxMessageSize,
1433                                DWORD lReadTimeout, LPSECURITY_ATTRIBUTES sa )
1434 {
1435     FIXME("(%s,%ld,%ld,%p): stub\n", debugstr_w(lpName),
1436           nMaxMessageSize, lReadTimeout, sa);
1437     return (HANDLE)1;
1438 }
1439
1440
1441 /******************************************************************************
1442  * GetMailslotInfo [KERNEL32.@]
1443  *
1444  * Retrieve information about a mailslot.
1445  *
1446  * PARAMS
1447  *    hMailslot        [I] Mailslot handle
1448  *    lpMaxMessageSize [O] Address of maximum message size
1449  *    lpNextSize       [O] Address of size of next message
1450  *    lpMessageCount   [O] Address of number of messages
1451  *    lpReadTimeout    [O] Address of read time-out
1452  *
1453  * RETURNS
1454  *    Success: TRUE
1455  *    Failure: FALSE
1456  */
1457 BOOL WINAPI GetMailslotInfo( HANDLE hMailslot, LPDWORD lpMaxMessageSize,
1458                                LPDWORD lpNextSize, LPDWORD lpMessageCount,
1459                                LPDWORD lpReadTimeout )
1460 {
1461     FIXME("(%p): stub\n",hMailslot);
1462     if (lpMaxMessageSize) *lpMaxMessageSize = (DWORD)NULL;
1463     if (lpNextSize) *lpNextSize = (DWORD)NULL;
1464     if (lpMessageCount) *lpMessageCount = (DWORD)NULL;
1465     if (lpReadTimeout) *lpReadTimeout = (DWORD)NULL;
1466     return TRUE;
1467 }
1468
1469
1470 /******************************************************************************
1471  * SetMailslotInfo [KERNEL32.@]
1472  *
1473  * Set the read timeout of a mailslot.
1474  *
1475  * PARAMS
1476  *  hMailslot     [I] Mailslot handle
1477  *  dwReadTimeout [I] Timeout in milliseconds.
1478  *
1479  * RETURNS
1480  *    Success: TRUE
1481  *    Failure: FALSE
1482  */
1483 BOOL WINAPI SetMailslotInfo( HANDLE hMailslot, DWORD dwReadTimeout)
1484 {
1485     FIXME("%p %ld: stub\n", hMailslot, dwReadTimeout);
1486     return TRUE;
1487 }
1488
1489
1490 #ifdef __i386__
1491
1492 /***********************************************************************
1493  *              InterlockedCompareExchange (KERNEL32.@)
1494  */
1495 /* LONG WINAPI InterlockedCompareExchange( PLONG dest, LONG xchg, LONG compare ); */
1496 __ASM_GLOBAL_FUNC(InterlockedCompareExchange,
1497                   "movl 12(%esp),%eax\n\t"
1498                   "movl 8(%esp),%ecx\n\t"
1499                   "movl 4(%esp),%edx\n\t"
1500                   "lock; cmpxchgl %ecx,(%edx)\n\t"
1501                   "ret $12");
1502
1503 /***********************************************************************
1504  *              InterlockedExchange (KERNEL32.@)
1505  */
1506 /* LONG WINAPI InterlockedExchange( PLONG dest, LONG val ); */
1507 __ASM_GLOBAL_FUNC(InterlockedExchange,
1508                   "movl 8(%esp),%eax\n\t"
1509                   "movl 4(%esp),%edx\n\t"
1510                   "lock; xchgl %eax,(%edx)\n\t"
1511                   "ret $8");
1512
1513 /***********************************************************************
1514  *              InterlockedExchangeAdd (KERNEL32.@)
1515  */
1516 /* LONG WINAPI InterlockedExchangeAdd( PLONG dest, LONG incr ); */
1517 __ASM_GLOBAL_FUNC(InterlockedExchangeAdd,
1518                   "movl 8(%esp),%eax\n\t"
1519                   "movl 4(%esp),%edx\n\t"
1520                   "lock; xaddl %eax,(%edx)\n\t"
1521                   "ret $8");
1522
1523 /***********************************************************************
1524  *              InterlockedIncrement (KERNEL32.@)
1525  */
1526 /* LONG WINAPI InterlockedIncrement( PLONG dest ); */
1527 __ASM_GLOBAL_FUNC(InterlockedIncrement,
1528                   "movl 4(%esp),%edx\n\t"
1529                   "movl $1,%eax\n\t"
1530                   "lock; xaddl %eax,(%edx)\n\t"
1531                   "incl %eax\n\t"
1532                   "ret $4");
1533
1534 /***********************************************************************
1535  *              InterlockedDecrement (KERNEL32.@)
1536  */
1537 __ASM_GLOBAL_FUNC(InterlockedDecrement,
1538                   "movl 4(%esp),%edx\n\t"
1539                   "movl $-1,%eax\n\t"
1540                   "lock; xaddl %eax,(%edx)\n\t"
1541                   "decl %eax\n\t"
1542                   "ret $4");
1543
1544 #else  /* __i386__ */
1545
1546 /***********************************************************************
1547  *              InterlockedCompareExchange (KERNEL32.@)
1548  *
1549  * Atomically swap one value with another.
1550  *
1551  * PARAMS
1552  *  dest    [I/O] The value to replace
1553  *  xchq    [I]   The value to be swapped
1554  *  compare [I]   The value to compare to dest
1555  *
1556  * RETURNS
1557  *  The resulting value of dest.
1558  *
1559  * NOTES
1560  *  dest is updated only if it is equal to compare, otherwise no swap is done.
1561  */
1562 LONG WINAPI InterlockedCompareExchange( PLONG dest, LONG xchg, LONG compare )
1563 {
1564     return interlocked_cmpxchg( dest, xchg, compare );
1565 }
1566
1567 /***********************************************************************
1568  *              InterlockedExchange (KERNEL32.@)
1569  *
1570  * Atomically swap one value with another.
1571  *
1572  * PARAMS
1573  *  dest [I/O] The value to replace
1574  *  val  [I]   The value to be swapped
1575  *
1576  * RETURNS
1577  *  The resulting value of dest.
1578  */
1579 LONG WINAPI InterlockedExchange( PLONG dest, LONG val )
1580 {
1581     return interlocked_xchg( dest, val );
1582 }
1583
1584 /***********************************************************************
1585  *              InterlockedExchangeAdd (KERNEL32.@)
1586  *
1587  * Atomically add one value to another.
1588  *
1589  * PARAMS
1590  *  dest [I/O] The value to add to
1591  *  incr [I]   The value to be added
1592  *
1593  * RETURNS
1594  *  The resulting value of dest.
1595  */
1596 LONG WINAPI InterlockedExchangeAdd( PLONG dest, LONG incr )
1597 {
1598     return interlocked_xchg_add( dest, incr );
1599 }
1600
1601 /***********************************************************************
1602  *              InterlockedIncrement (KERNEL32.@)
1603  *
1604  * Atomically increment a value.
1605  *
1606  * PARAMS
1607  *  dest [I/O] The value to increment
1608  *
1609  * RETURNS
1610  *  The resulting value of dest.
1611  */
1612 LONG WINAPI InterlockedIncrement( PLONG dest )
1613 {
1614     return interlocked_xchg_add( dest, 1 ) + 1;
1615 }
1616
1617 /***********************************************************************
1618  *              InterlockedDecrement (KERNEL32.@)
1619  *
1620  * Atomically decrement a value.
1621  *
1622  * PARAMS
1623  *  dest [I/O] The value to decrement
1624  *
1625  * RETURNS
1626  *  The resulting value of dest.
1627  */
1628 LONG WINAPI InterlockedDecrement( PLONG dest )
1629 {
1630     return interlocked_xchg_add( dest, -1 ) - 1;
1631 }
1632
1633 #endif  /* __i386__ */