Fixed definitions of TTTOOLINFOA/W_V1_SIZE and
[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 "file.h"
47
48 #include "wine/debug.h"
49
50 WINE_DEFAULT_DEBUG_CHANNEL(win32);
51
52 /* check if current version is NT or Win95 */
53 inline static int is_version_nt(void)
54 {
55     return !(GetVersion() & 0x80000000);
56 }
57
58
59 /***********************************************************************
60  *           InitializeCriticalSection   (KERNEL32.@)
61  */
62 void WINAPI InitializeCriticalSection( CRITICAL_SECTION *crit )
63 {
64     NTSTATUS ret = RtlInitializeCriticalSection( crit );
65     if (ret) RtlRaiseStatus( ret );
66 }
67
68 /***********************************************************************
69  *           InitializeCriticalSectionAndSpinCount   (KERNEL32.@)
70  */
71 BOOL WINAPI InitializeCriticalSectionAndSpinCount( CRITICAL_SECTION *crit, DWORD spincount )
72 {
73     NTSTATUS ret = RtlInitializeCriticalSectionAndSpinCount( crit, spincount );
74     if (ret) RtlRaiseStatus( ret );
75     return !ret;
76 }
77
78 /***********************************************************************
79  *           SetCriticalSectionSpinCount   (KERNEL32.@)
80  * This function is available on NT4SP3 or later, but not Win98
81  * It is SMP related
82  */
83 DWORD WINAPI SetCriticalSectionSpinCount( CRITICAL_SECTION *crit, DWORD spincount )
84 {
85     ULONG_PTR oldspincount = crit->SpinCount;
86     if(spincount) FIXME("critsection=%p: spincount=%ld not supported\n", crit, spincount);
87     crit->SpinCount = spincount;
88     return oldspincount;
89 }
90
91 /***********************************************************************
92  *           MakeCriticalSectionGlobal   (KERNEL32.@)
93  */
94 void WINAPI MakeCriticalSectionGlobal( CRITICAL_SECTION *crit )
95 {
96     /* let's assume that only one thread at a time will try to do this */
97     HANDLE sem = crit->LockSemaphore;
98     if (!sem) NtCreateSemaphore( &sem, SEMAPHORE_ALL_ACCESS, NULL, 0, 1 );
99     crit->LockSemaphore = ConvertToGlobalHandle( sem );
100     if (crit->DebugInfo)
101     {
102         RtlFreeHeap( GetProcessHeap(), 0, crit->DebugInfo );
103         crit->DebugInfo = NULL;
104     }
105 }
106
107
108 /***********************************************************************
109  *           ReinitializeCriticalSection   (KERNEL32.@)
110  */
111 void WINAPI ReinitializeCriticalSection( CRITICAL_SECTION *crit )
112 {
113     if ( !crit->LockSemaphore )
114         RtlInitializeCriticalSection( crit );
115 }
116
117
118 /***********************************************************************
119  *           UninitializeCriticalSection   (KERNEL32.@)
120  */
121 void WINAPI UninitializeCriticalSection( CRITICAL_SECTION *crit )
122 {
123     RtlDeleteCriticalSection( crit );
124 }
125
126
127 /***********************************************************************
128  *           CreateEventA    (KERNEL32.@)
129  */
130 HANDLE WINAPI CreateEventA( SECURITY_ATTRIBUTES *sa, BOOL manual_reset,
131                             BOOL initial_state, LPCSTR name )
132 {
133     WCHAR buffer[MAX_PATH];
134
135     if (!name) return CreateEventW( sa, manual_reset, initial_state, NULL );
136
137     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
138     {
139         SetLastError( ERROR_FILENAME_EXCED_RANGE );
140         return 0;
141     }
142     return CreateEventW( sa, manual_reset, initial_state, buffer );
143 }
144
145
146 /***********************************************************************
147  *           CreateEventW    (KERNEL32.@)
148  */
149 HANDLE WINAPI CreateEventW( SECURITY_ATTRIBUTES *sa, BOOL manual_reset,
150                             BOOL initial_state, LPCWSTR name )
151 {
152     HANDLE ret;
153     DWORD len = name ? strlenW(name) : 0;
154     if (len >= MAX_PATH)
155     {
156         SetLastError( ERROR_FILENAME_EXCED_RANGE );
157         return 0;
158     }
159     /* one buggy program needs this
160      * ("Van Dale Groot woordenboek der Nederlandse taal")
161      */
162     if (sa && IsBadReadPtr(sa,sizeof(SECURITY_ATTRIBUTES)))
163     {
164         ERR("Bad security attributes pointer %p\n",sa);
165         SetLastError( ERROR_INVALID_PARAMETER);
166         return 0;
167     }
168     SERVER_START_REQ( create_event )
169     {
170         req->manual_reset = manual_reset;
171         req->initial_state = initial_state;
172         req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
173         wine_server_add_data( req, name, len * sizeof(WCHAR) );
174         SetLastError(0);
175         wine_server_call_err( req );
176         ret = reply->handle;
177     }
178     SERVER_END_REQ;
179     return ret;
180 }
181
182
183 /***********************************************************************
184  *           CreateW32Event    (KERNEL.457)
185  */
186 HANDLE WINAPI WIN16_CreateEvent( BOOL manual_reset, BOOL initial_state )
187 {
188     return CreateEventA( NULL, manual_reset, initial_state, NULL );
189 }
190
191
192 /***********************************************************************
193  *           OpenEventA    (KERNEL32.@)
194  */
195 HANDLE WINAPI OpenEventA( DWORD access, BOOL inherit, LPCSTR name )
196 {
197     WCHAR buffer[MAX_PATH];
198
199     if (!name) return OpenEventW( access, inherit, NULL );
200
201     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
202     {
203         SetLastError( ERROR_FILENAME_EXCED_RANGE );
204         return 0;
205     }
206     return OpenEventW( access, inherit, buffer );
207 }
208
209
210 /***********************************************************************
211  *           OpenEventW    (KERNEL32.@)
212  */
213 HANDLE WINAPI OpenEventW( DWORD access, BOOL inherit, LPCWSTR name )
214 {
215     HANDLE ret;
216     DWORD len = name ? strlenW(name) : 0;
217     if (len >= MAX_PATH)
218     {
219         SetLastError( ERROR_FILENAME_EXCED_RANGE );
220         return 0;
221     }
222     if (!is_version_nt()) access = EVENT_ALL_ACCESS;
223
224     SERVER_START_REQ( open_event )
225     {
226         req->access  = access;
227         req->inherit = inherit;
228         wine_server_add_data( req, name, len * sizeof(WCHAR) );
229         wine_server_call_err( req );
230         ret = reply->handle;
231     }
232     SERVER_END_REQ;
233     return ret;
234 }
235
236
237 /***********************************************************************
238  *           EVENT_Operation
239  *
240  * Execute an event operation (set,reset,pulse).
241  */
242 static BOOL EVENT_Operation( HANDLE handle, enum event_op op )
243 {
244     BOOL ret;
245     SERVER_START_REQ( event_op )
246     {
247         req->handle = handle;
248         req->op     = op;
249         ret = !wine_server_call_err( req );
250     }
251     SERVER_END_REQ;
252     return ret;
253 }
254
255
256 /***********************************************************************
257  *           PulseEvent    (KERNEL32.@)
258  */
259 BOOL WINAPI PulseEvent( HANDLE handle )
260 {
261     return EVENT_Operation( handle, PULSE_EVENT );
262 }
263
264
265 /***********************************************************************
266  *           SetW32Event (KERNEL.458)
267  *           SetEvent    (KERNEL32.@)
268  */
269 BOOL WINAPI SetEvent( HANDLE handle )
270 {
271     return EVENT_Operation( handle, SET_EVENT );
272 }
273
274
275 /***********************************************************************
276  *           ResetW32Event (KERNEL.459)
277  *           ResetEvent    (KERNEL32.@)
278  */
279 BOOL WINAPI ResetEvent( HANDLE handle )
280 {
281     return EVENT_Operation( handle, RESET_EVENT );
282 }
283
284
285 /***********************************************************************
286  * NOTE: The Win95 VWin32_Event routines given below are really low-level
287  *       routines implemented directly by VWin32. The user-mode libraries
288  *       implement Win32 synchronisation routines on top of these low-level
289  *       primitives. We do it the other way around here :-)
290  */
291
292 /***********************************************************************
293  *       VWin32_EventCreate     (KERNEL.442)
294  */
295 HANDLE WINAPI VWin32_EventCreate(VOID)
296 {
297     HANDLE hEvent = CreateEventA( NULL, FALSE, 0, NULL );
298     return ConvertToGlobalHandle( hEvent );
299 }
300
301 /***********************************************************************
302  *       VWin32_EventDestroy    (KERNEL.443)
303  */
304 VOID WINAPI VWin32_EventDestroy(HANDLE event)
305 {
306     CloseHandle( event );
307 }
308
309 /***********************************************************************
310  *       VWin32_EventWait       (KERNEL.450)
311  */
312 VOID WINAPI VWin32_EventWait(HANDLE event)
313 {
314     DWORD mutex_count;
315
316     ReleaseThunkLock( &mutex_count );
317     WaitForSingleObject( event, INFINITE );
318     RestoreThunkLock( mutex_count );
319 }
320
321 /***********************************************************************
322  *       VWin32_EventSet        (KERNEL.451)
323  *       KERNEL_479             (KERNEL.479)
324  */
325 VOID WINAPI VWin32_EventSet(HANDLE event)
326 {
327     SetEvent( event );
328 }
329
330
331
332 /***********************************************************************
333  *           CreateMutexA   (KERNEL32.@)
334  */
335 HANDLE WINAPI CreateMutexA( SECURITY_ATTRIBUTES *sa, BOOL owner, LPCSTR name )
336 {
337     WCHAR buffer[MAX_PATH];
338
339     if (!name) return CreateMutexW( sa, owner, NULL );
340
341     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
342     {
343         SetLastError( ERROR_FILENAME_EXCED_RANGE );
344         return 0;
345     }
346     return CreateMutexW( sa, owner, buffer );
347 }
348
349
350 /***********************************************************************
351  *           CreateMutexW   (KERNEL32.@)
352  */
353 HANDLE WINAPI CreateMutexW( SECURITY_ATTRIBUTES *sa, BOOL owner, LPCWSTR name )
354 {
355     HANDLE ret;
356     DWORD len = name ? strlenW(name) : 0;
357     if (len >= MAX_PATH)
358     {
359         SetLastError( ERROR_FILENAME_EXCED_RANGE );
360         return 0;
361     }
362     SERVER_START_REQ( create_mutex )
363     {
364         req->owned   = owner;
365         req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
366         wine_server_add_data( req, name, len * sizeof(WCHAR) );
367         SetLastError(0);
368         wine_server_call_err( req );
369         ret = reply->handle;
370     }
371     SERVER_END_REQ;
372     return ret;
373 }
374
375
376 /***********************************************************************
377  *           OpenMutexA   (KERNEL32.@)
378  */
379 HANDLE WINAPI OpenMutexA( DWORD access, BOOL inherit, LPCSTR name )
380 {
381     WCHAR buffer[MAX_PATH];
382
383     if (!name) return OpenMutexW( access, inherit, NULL );
384
385     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
386     {
387         SetLastError( ERROR_FILENAME_EXCED_RANGE );
388         return 0;
389     }
390     return OpenMutexW( access, inherit, buffer );
391 }
392
393
394 /***********************************************************************
395  *           OpenMutexW   (KERNEL32.@)
396  */
397 HANDLE WINAPI OpenMutexW( DWORD access, BOOL inherit, LPCWSTR name )
398 {
399     HANDLE ret;
400     DWORD len = name ? strlenW(name) : 0;
401     if (len >= MAX_PATH)
402     {
403         SetLastError( ERROR_FILENAME_EXCED_RANGE );
404         return 0;
405     }
406     if (!is_version_nt()) access = MUTEX_ALL_ACCESS;
407
408     SERVER_START_REQ( open_mutex )
409     {
410         req->access  = access;
411         req->inherit = inherit;
412         wine_server_add_data( req, name, len * sizeof(WCHAR) );
413         wine_server_call_err( req );
414         ret = reply->handle;
415     }
416     SERVER_END_REQ;
417     return ret;
418 }
419
420
421 /***********************************************************************
422  *           ReleaseMutex   (KERNEL32.@)
423  */
424 BOOL WINAPI ReleaseMutex( HANDLE handle )
425 {
426     BOOL ret;
427     SERVER_START_REQ( release_mutex )
428     {
429         req->handle = handle;
430         ret = !wine_server_call_err( req );
431     }
432     SERVER_END_REQ;
433     return ret;
434 }
435
436
437 /*
438  * Semaphores
439  */
440
441
442 /***********************************************************************
443  *           CreateSemaphoreA   (KERNEL32.@)
444  */
445 HANDLE WINAPI CreateSemaphoreA( SECURITY_ATTRIBUTES *sa, LONG initial, LONG max, LPCSTR name )
446 {
447     WCHAR buffer[MAX_PATH];
448
449     if (!name) return CreateSemaphoreW( sa, initial, max, NULL );
450
451     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
452     {
453         SetLastError( ERROR_FILENAME_EXCED_RANGE );
454         return 0;
455     }
456     return CreateSemaphoreW( sa, initial, max, buffer );
457 }
458
459
460 /***********************************************************************
461  *           CreateSemaphoreW   (KERNEL32.@)
462  */
463 HANDLE WINAPI CreateSemaphoreW( SECURITY_ATTRIBUTES *sa, LONG initial,
464                                     LONG max, LPCWSTR name )
465 {
466     HANDLE ret;
467     DWORD len = name ? strlenW(name) : 0;
468
469     /* Check parameters */
470
471     if ((max <= 0) || (initial < 0) || (initial > max))
472     {
473         SetLastError( ERROR_INVALID_PARAMETER );
474         return 0;
475     }
476     if (len >= MAX_PATH)
477     {
478         SetLastError( ERROR_FILENAME_EXCED_RANGE );
479         return 0;
480     }
481
482     SERVER_START_REQ( create_semaphore )
483     {
484         req->initial = (unsigned int)initial;
485         req->max     = (unsigned int)max;
486         req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
487         wine_server_add_data( req, name, len * sizeof(WCHAR) );
488         SetLastError(0);
489         wine_server_call_err( req );
490         ret = reply->handle;
491     }
492     SERVER_END_REQ;
493     return ret;
494 }
495
496
497 /***********************************************************************
498  *           OpenSemaphoreA   (KERNEL32.@)
499  */
500 HANDLE WINAPI OpenSemaphoreA( DWORD access, BOOL inherit, LPCSTR name )
501 {
502     WCHAR buffer[MAX_PATH];
503
504     if (!name) return OpenSemaphoreW( access, inherit, NULL );
505
506     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
507     {
508         SetLastError( ERROR_FILENAME_EXCED_RANGE );
509         return 0;
510     }
511     return OpenSemaphoreW( access, inherit, buffer );
512 }
513
514
515 /***********************************************************************
516  *           OpenSemaphoreW   (KERNEL32.@)
517  */
518 HANDLE WINAPI OpenSemaphoreW( DWORD access, BOOL inherit, LPCWSTR name )
519 {
520     HANDLE ret;
521     DWORD len = name ? strlenW(name) : 0;
522     if (len >= MAX_PATH)
523     {
524         SetLastError( ERROR_FILENAME_EXCED_RANGE );
525         return 0;
526     }
527     if (!is_version_nt()) access = SEMAPHORE_ALL_ACCESS;
528
529     SERVER_START_REQ( open_semaphore )
530     {
531         req->access  = access;
532         req->inherit = inherit;
533         wine_server_add_data( req, name, len * sizeof(WCHAR) );
534         wine_server_call_err( req );
535         ret = reply->handle;
536     }
537     SERVER_END_REQ;
538     return ret;
539 }
540
541
542 /***********************************************************************
543  *           ReleaseSemaphore   (KERNEL32.@)
544  */
545 BOOL WINAPI ReleaseSemaphore( HANDLE handle, LONG count, LONG *previous )
546 {
547     NTSTATUS status = NtReleaseSemaphore( handle, count, previous );
548     if (status) SetLastError( RtlNtStatusToDosError(status) );
549     return !status;
550 }
551
552
553 /*
554  * Timers
555  */
556
557
558 /***********************************************************************
559  *           CreateWaitableTimerA    (KERNEL32.@)
560  */
561 HANDLE WINAPI CreateWaitableTimerA( SECURITY_ATTRIBUTES *sa, BOOL manual, LPCSTR name )
562 {
563     WCHAR buffer[MAX_PATH];
564
565     if (!name) return CreateWaitableTimerW( sa, manual, NULL );
566
567     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
568     {
569         SetLastError( ERROR_FILENAME_EXCED_RANGE );
570         return 0;
571     }
572     return CreateWaitableTimerW( sa, manual, buffer );
573 }
574
575
576 /***********************************************************************
577  *           CreateWaitableTimerW    (KERNEL32.@)
578  */
579 HANDLE WINAPI CreateWaitableTimerW( SECURITY_ATTRIBUTES *sa, BOOL manual, LPCWSTR name )
580 {
581     HANDLE              handle;
582     NTSTATUS            status;
583     UNICODE_STRING      us;
584     DWORD               attr = 0;
585     OBJECT_ATTRIBUTES   oa;
586
587     if (name) RtlInitUnicodeString(&us, name);
588     if (sa && (sa->nLength >= sizeof(*sa)) && sa->bInheritHandle)
589         attr |= OBJ_INHERIT;
590     InitializeObjectAttributes(&oa, name ? &us : NULL, attr,
591                                NULL /* FIXME */, NULL /* FIXME */);
592     status = NtCreateTimer(&handle, TIMER_ALL_ACCESS, &oa,
593                            manual ? NotificationTimer : SynchronizationTimer);
594
595     if (status != STATUS_SUCCESS)
596     {
597         SetLastError( RtlNtStatusToDosError(status) );
598         return 0;
599     }
600     return handle;
601 }
602
603
604 /***********************************************************************
605  *           OpenWaitableTimerA    (KERNEL32.@)
606  */
607 HANDLE WINAPI OpenWaitableTimerA( DWORD access, BOOL inherit, LPCSTR name )
608 {
609     WCHAR buffer[MAX_PATH];
610
611     if (!name) return OpenWaitableTimerW( access, inherit, NULL );
612
613     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
614     {
615         SetLastError( ERROR_FILENAME_EXCED_RANGE );
616         return 0;
617     }
618     return OpenWaitableTimerW( access, inherit, buffer );
619 }
620
621
622 /***********************************************************************
623  *           OpenWaitableTimerW    (KERNEL32.@)
624  */
625 HANDLE WINAPI OpenWaitableTimerW( DWORD access, BOOL inherit, LPCWSTR name )
626 {
627     NTSTATUS            status;
628     ULONG               attr = 0;
629     UNICODE_STRING      us;
630     HANDLE              handle;
631     OBJECT_ATTRIBUTES   oa;
632
633     if (inherit) attr |= OBJ_INHERIT;
634
635     if (name) RtlInitUnicodeString(&us, name);
636     InitializeObjectAttributes(&oa, name ? &us : NULL, attr, NULL /* FIXME */, NULL /* FIXME */);
637     status = NtOpenTimer(&handle, access, &oa);
638     if (status != STATUS_SUCCESS)
639     {
640         SetLastError( RtlNtStatusToDosError(status) );
641         return 0;
642     }
643     return handle;
644 }
645
646
647 /***********************************************************************
648  *           SetWaitableTimer    (KERNEL32.@)
649  */
650 BOOL WINAPI SetWaitableTimer( HANDLE handle, const LARGE_INTEGER *when, LONG period,
651                               PTIMERAPCROUTINE callback, LPVOID arg, BOOL resume )
652 {
653     NTSTATUS status = NtSetTimer(handle, when, callback, arg, resume, period, NULL);
654
655     if (status != STATUS_SUCCESS)
656     {
657         SetLastError( RtlNtStatusToDosError(status) );
658         if (status != STATUS_TIMER_RESUME_IGNORED) return FALSE;
659     }
660     return TRUE;
661 }
662
663
664 /***********************************************************************
665  *           CancelWaitableTimer    (KERNEL32.@)
666  */
667 BOOL WINAPI CancelWaitableTimer( HANDLE handle )
668 {
669     NTSTATUS status;
670
671     status = NtCancelTimer(handle, NULL);
672     if (status != STATUS_SUCCESS)
673     {
674         SetLastError( RtlNtStatusToDosError(status) );
675         return FALSE;
676     }
677     return TRUE;
678 }
679
680
681 /***********************************************************************
682  *           CreateTimerQueue  (KERNEL32.@)
683  */
684 HANDLE WINAPI CreateTimerQueue(void)
685 {
686     FIXME("stub\n");
687     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
688     return NULL;
689 }
690
691
692 /***********************************************************************
693  *           DeleteTimerQueueEx  (KERNEL32.@)
694  */
695 BOOL WINAPI DeleteTimerQueueEx(HANDLE TimerQueue, HANDLE CompletionEvent)
696 {
697     FIXME("(%p, %p): stub\n", TimerQueue, CompletionEvent);
698     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
699     return 0;
700 }
701
702 /***********************************************************************
703  *           CreateTimerQueueTimer  (KERNEL32.@)
704  *
705  * Creates a timer-queue timer. This timer expires at the specified due
706  * time (in ms), then after every specified period (in ms). When the timer
707  * expires, the callback function is called.
708  *
709  * RETURNS
710  *   nonzero on success or zero on faillure
711  *
712  * BUGS
713  *   Unimplemented
714  */
715 BOOL WINAPI CreateTimerQueueTimer( PHANDLE phNewTimer, HANDLE TimerQueue,
716                                    WAITORTIMERCALLBACK Callback, PVOID Parameter,
717                                    DWORD DueTime, DWORD Period, ULONG Flags )
718 {
719     FIXME("stub\n");
720     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
721     return TRUE;
722 }
723
724 /***********************************************************************
725  *           DeleteTimerQueueTimer  (KERNEL32.@)
726  *
727  * Cancels a timer-queue timer.
728  *
729  * RETURNS
730  *   nonzero on success or zero on faillure
731  *
732  * BUGS
733  *   Unimplemented
734  */
735 BOOL WINAPI DeleteTimerQueueTimer( HANDLE TimerQueue, HANDLE Timer,
736                                    HANDLE CompletionEvent )
737 {
738     FIXME("stub\n");
739     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
740     return TRUE;
741 }
742
743
744 /*
745  * Pipes
746  */
747
748
749 /***********************************************************************
750  *           CreateNamedPipeA   (KERNEL32.@)
751  */
752 HANDLE WINAPI CreateNamedPipeA( LPCSTR name, DWORD dwOpenMode,
753                                 DWORD dwPipeMode, DWORD nMaxInstances,
754                                 DWORD nOutBufferSize, DWORD nInBufferSize,
755                                 DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES attr )
756 {
757     WCHAR buffer[MAX_PATH];
758
759     if (!name) return CreateNamedPipeW( NULL, dwOpenMode, dwPipeMode, nMaxInstances,
760                                         nOutBufferSize, nInBufferSize, nDefaultTimeOut, attr );
761
762     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
763     {
764         SetLastError( ERROR_FILENAME_EXCED_RANGE );
765         return INVALID_HANDLE_VALUE;
766     }
767     return CreateNamedPipeW( buffer, dwOpenMode, dwPipeMode, nMaxInstances,
768                              nOutBufferSize, nInBufferSize, nDefaultTimeOut, attr );
769 }
770
771
772 /***********************************************************************
773  *           CreateNamedPipeW   (KERNEL32.@)
774  */
775 HANDLE WINAPI CreateNamedPipeW( LPCWSTR name, DWORD dwOpenMode,
776                                 DWORD dwPipeMode, DWORD nMaxInstances,
777                                 DWORD nOutBufferSize, DWORD nInBufferSize,
778                                 DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES attr )
779 {
780     HANDLE ret;
781     DWORD len;
782     static const WCHAR leadin[] = {'\\','\\','.','\\','P','I','P','E','\\'};
783
784     TRACE("(%s, %#08lx, %#08lx, %ld, %ld, %ld, %ld, %p)\n",
785           debugstr_w(name), dwOpenMode, dwPipeMode, nMaxInstances,
786           nOutBufferSize, nInBufferSize, nDefaultTimeOut, attr );
787
788     if (!name)
789     {
790         SetLastError( ERROR_PATH_NOT_FOUND );
791         return INVALID_HANDLE_VALUE;
792     }
793     len = strlenW(name);
794     if (len >= MAX_PATH)
795     {
796         SetLastError( ERROR_FILENAME_EXCED_RANGE );
797         return INVALID_HANDLE_VALUE;
798     }
799     if (strncmpiW(name, leadin, sizeof(leadin)/sizeof(leadin[0])))
800     {
801         SetLastError( ERROR_INVALID_NAME );
802         return INVALID_HANDLE_VALUE;
803     }
804     SERVER_START_REQ( create_named_pipe )
805     {
806         req->openmode = dwOpenMode;
807         req->pipemode = dwPipeMode;
808         req->maxinstances = nMaxInstances;
809         req->outsize = nOutBufferSize;
810         req->insize = nInBufferSize;
811         req->timeout = nDefaultTimeOut;
812         wine_server_add_data( req, name, len * sizeof(WCHAR) );
813         SetLastError(0);
814         if (!wine_server_call_err( req )) ret = reply->handle;
815         else ret = INVALID_HANDLE_VALUE;
816     }
817     SERVER_END_REQ;
818     return ret;
819 }
820
821
822 /***********************************************************************
823  *           PeekNamedPipe   (KERNEL32.@)
824  */
825 BOOL WINAPI PeekNamedPipe( HANDLE hPipe, LPVOID lpvBuffer, DWORD cbBuffer,
826                            LPDWORD lpcbRead, LPDWORD lpcbAvail, LPDWORD lpcbMessage )
827 {
828 #ifdef FIONREAD
829     int avail=0,fd;
830
831     fd = FILE_GetUnixHandle(hPipe, GENERIC_READ);
832     if (fd == -1) return FALSE;
833
834     if (ioctl(fd,FIONREAD, &avail ) != 0)
835     {
836         TRACE("FIONREAD failed reason: %s\n",strerror(errno));
837         close(fd);
838         return FALSE;
839     }
840     if (!avail)  /* check for closed pipe */
841     {
842         struct pollfd pollfd;
843         pollfd.fd = fd;
844         pollfd.events = POLLIN;
845         pollfd.revents = 0;
846         switch (poll( &pollfd, 1, 0 ))
847         {
848         case 0:
849             break;
850         case 1:  /* got something */
851             if (!(pollfd.revents & (POLLHUP | POLLERR))) break;
852             TRACE("POLLHUP | POLLERR\n");
853             /* fall through */
854         case -1:
855             close(fd);
856             SetLastError(ERROR_BROKEN_PIPE);
857             return FALSE;
858         }
859     }
860     close(fd);
861     TRACE(" 0x%08x bytes available\n", avail );
862     if (!lpvBuffer && lpcbAvail)
863       {
864         *lpcbAvail= avail;
865         return TRUE;
866       }
867 #endif /* defined(FIONREAD) */
868
869     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
870     FIXME("function not implemented\n");
871     return FALSE;
872 }
873
874 /***********************************************************************
875  *           SYNC_CompletePipeOverlapped   (Internal)
876  */
877 static void SYNC_CompletePipeOverlapped (LPOVERLAPPED overlapped, DWORD result)
878 {
879     TRACE("for %p result %08lx\n",overlapped,result);
880     if(!overlapped)
881         return;
882     overlapped->Internal = result;
883     SetEvent(overlapped->hEvent);
884 }
885
886
887 /***********************************************************************
888  *           WaitNamedPipeA   (KERNEL32.@)
889  */
890 BOOL WINAPI WaitNamedPipeA (LPCSTR name, DWORD nTimeOut)
891 {
892     WCHAR buffer[MAX_PATH];
893
894     if (!name) return WaitNamedPipeW( NULL, nTimeOut );
895
896     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
897     {
898         SetLastError( ERROR_FILENAME_EXCED_RANGE );
899         return 0;
900     }
901     return WaitNamedPipeW( buffer, nTimeOut );
902 }
903
904
905 /***********************************************************************
906  *           WaitNamedPipeW   (KERNEL32.@)
907  */
908 BOOL WINAPI WaitNamedPipeW (LPCWSTR name, DWORD nTimeOut)
909 {
910     DWORD len = name ? strlenW(name) : 0;
911     BOOL ret;
912     OVERLAPPED ov;
913
914     if (len >= MAX_PATH)
915     {
916         SetLastError( ERROR_FILENAME_EXCED_RANGE );
917         return FALSE;
918     }
919
920     TRACE("%s 0x%08lx\n",debugstr_w(name),nTimeOut);
921
922     memset(&ov,0,sizeof(ov));
923     ov.hEvent = CreateEventA( NULL, 0, 0, NULL );
924     if (!ov.hEvent)
925         return FALSE;
926
927     SERVER_START_REQ( wait_named_pipe )
928     {
929         req->timeout = nTimeOut;
930         req->overlapped = &ov;
931         req->func = SYNC_CompletePipeOverlapped;
932         wine_server_add_data( req, name, len * sizeof(WCHAR) );
933         ret = !wine_server_call_err( req );
934     }
935     SERVER_END_REQ;
936
937     if(ret)
938     {
939         if (WAIT_OBJECT_0==WaitForSingleObject(ov.hEvent,INFINITE))
940         {
941             SetLastError(ov.Internal);
942             ret = (ov.Internal==STATUS_SUCCESS);
943         }
944     }
945     CloseHandle(ov.hEvent);
946     return ret;
947 }
948
949
950 /***********************************************************************
951  *           SYNC_ConnectNamedPipe   (Internal)
952  */
953 static BOOL SYNC_ConnectNamedPipe(HANDLE hPipe, LPOVERLAPPED overlapped)
954 {
955     BOOL ret;
956
957     if(!overlapped)
958         return FALSE;
959
960     overlapped->Internal = STATUS_PENDING;
961
962     SERVER_START_REQ( connect_named_pipe )
963     {
964         req->handle = hPipe;
965         req->overlapped = overlapped;
966         req->func = SYNC_CompletePipeOverlapped;
967         ret = !wine_server_call_err( req );
968     }
969     SERVER_END_REQ;
970
971     return ret;
972 }
973
974 /***********************************************************************
975  *           ConnectNamedPipe   (KERNEL32.@)
976  */
977 BOOL WINAPI ConnectNamedPipe(HANDLE hPipe, LPOVERLAPPED overlapped)
978 {
979     OVERLAPPED ov;
980     BOOL ret;
981
982     TRACE("(%p,%p)\n",hPipe, overlapped);
983
984     if(overlapped)
985     {
986         if(SYNC_ConnectNamedPipe(hPipe,overlapped))
987             SetLastError( ERROR_IO_PENDING );
988         return FALSE;
989     }
990
991     memset(&ov,0,sizeof(ov));
992     ov.hEvent = CreateEventA(NULL,0,0,NULL);
993     if (!ov.hEvent)
994         return FALSE;
995
996     ret=SYNC_ConnectNamedPipe(hPipe, &ov);
997     if(ret)
998     {
999         if (WAIT_OBJECT_0==WaitForSingleObject(ov.hEvent,INFINITE))
1000         {
1001             SetLastError(ov.Internal);
1002             ret = (ov.Internal==STATUS_SUCCESS);
1003         }
1004     }
1005
1006     CloseHandle(ov.hEvent);
1007
1008     return ret;
1009 }
1010
1011 /***********************************************************************
1012  *           DisconnectNamedPipe   (KERNEL32.@)
1013  */
1014 BOOL WINAPI DisconnectNamedPipe(HANDLE hPipe)
1015 {
1016     BOOL ret;
1017
1018     TRACE("(%p)\n",hPipe);
1019
1020     SERVER_START_REQ( disconnect_named_pipe )
1021     {
1022         req->handle = hPipe;
1023         ret = !wine_server_call_err( req );
1024         if (ret && reply->fd != -1) close( reply->fd );
1025     }
1026     SERVER_END_REQ;
1027
1028     return ret;
1029 }
1030
1031 /***********************************************************************
1032  *           TransactNamedPipe   (KERNEL32.@)
1033  */
1034 BOOL WINAPI TransactNamedPipe(
1035     HANDLE hPipe, LPVOID lpInput, DWORD dwInputSize, LPVOID lpOutput,
1036     DWORD dwOutputSize, LPDWORD lpBytesRead, LPOVERLAPPED lpOverlapped)
1037 {
1038     FIXME("%p %p %ld %p %ld %p %p\n",
1039           hPipe, lpInput, dwInputSize, lpOutput,
1040           dwOutputSize, lpBytesRead, lpOverlapped);
1041     if(lpBytesRead)
1042         *lpBytesRead=0;
1043     return FALSE;
1044 }
1045
1046 /***********************************************************************
1047  *           GetNamedPipeInfo   (KERNEL32.@)
1048  */
1049 BOOL WINAPI GetNamedPipeInfo(
1050     HANDLE hNamedPipe, LPDWORD lpFlags, LPDWORD lpOutputBufferSize,
1051     LPDWORD lpInputBufferSize, LPDWORD lpMaxInstances)
1052 {
1053     BOOL ret;
1054
1055     TRACE("%p %p %p %p %p\n", hNamedPipe, lpFlags,
1056           lpOutputBufferSize, lpInputBufferSize, lpMaxInstances);
1057
1058     SERVER_START_REQ( get_named_pipe_info )
1059     {
1060         req->handle = hNamedPipe;
1061         ret = !wine_server_call_err( req );
1062         if(lpFlags) *lpFlags = reply->flags;
1063         if(lpOutputBufferSize) *lpOutputBufferSize = reply->outsize;
1064         if(lpInputBufferSize) *lpInputBufferSize = reply->outsize;
1065         if(lpMaxInstances) *lpMaxInstances = reply->maxinstances;
1066     }
1067     SERVER_END_REQ;
1068
1069     return ret;
1070 }
1071
1072 /***********************************************************************
1073  *           GetNamedPipeHandleStateA  (KERNEL32.@)
1074  */
1075 BOOL WINAPI GetNamedPipeHandleStateA(
1076     HANDLE hNamedPipe, LPDWORD lpState, LPDWORD lpCurInstances,
1077     LPDWORD lpMaxCollectionCount, LPDWORD lpCollectDataTimeout,
1078     LPSTR lpUsername, DWORD nUsernameMaxSize)
1079 {
1080     FIXME("%p %p %p %p %p %p %ld\n",
1081           hNamedPipe, lpState, lpCurInstances,
1082           lpMaxCollectionCount, lpCollectDataTimeout,
1083           lpUsername, nUsernameMaxSize);
1084
1085     return FALSE;
1086 }
1087
1088 /***********************************************************************
1089  *           GetNamedPipeHandleStateW  (KERNEL32.@)
1090  */
1091 BOOL WINAPI GetNamedPipeHandleStateW(
1092     HANDLE hNamedPipe, LPDWORD lpState, LPDWORD lpCurInstances,
1093     LPDWORD lpMaxCollectionCount, LPDWORD lpCollectDataTimeout,
1094     LPWSTR lpUsername, DWORD nUsernameMaxSize)
1095 {
1096     FIXME("%p %p %p %p %p %p %ld\n",
1097           hNamedPipe, lpState, lpCurInstances,
1098           lpMaxCollectionCount, lpCollectDataTimeout,
1099           lpUsername, nUsernameMaxSize);
1100
1101     return FALSE;
1102 }
1103
1104 /***********************************************************************
1105  *           SetNamedPipeHandleState  (KERNEL32.@)
1106  */
1107 BOOL WINAPI SetNamedPipeHandleState(
1108     HANDLE hNamedPipe, LPDWORD lpMode, LPDWORD lpMaxCollectionCount,
1109     LPDWORD lpCollectDataTimeout)
1110 {
1111     FIXME("%p %p %p %p\n",
1112           hNamedPipe, lpMode, lpMaxCollectionCount, lpCollectDataTimeout);
1113     return FALSE;
1114 }
1115
1116 /***********************************************************************
1117  *           CallNamedPipeA  (KERNEL32.@)
1118  */
1119 BOOL WINAPI CallNamedPipeA(
1120     LPCSTR lpNamedPipeName, LPVOID lpInput, DWORD lpInputSize,
1121     LPVOID lpOutput, DWORD lpOutputSize,
1122     LPDWORD lpBytesRead, DWORD nTimeout)
1123 {
1124     FIXME("%s %p %ld %p %ld %p %ld\n",
1125            debugstr_a(lpNamedPipeName), lpInput, lpInputSize,
1126            lpOutput, lpOutputSize, lpBytesRead, nTimeout);
1127     return FALSE;
1128 }
1129
1130 /***********************************************************************
1131  *           CallNamedPipeW  (KERNEL32.@)
1132  */
1133 BOOL WINAPI CallNamedPipeW(
1134     LPCWSTR lpNamedPipeName, LPVOID lpInput, DWORD lpInputSize,
1135     LPVOID lpOutput, DWORD lpOutputSize,
1136     LPDWORD lpBytesRead, DWORD nTimeout)
1137 {
1138     FIXME("%s %p %ld %p %ld %p %ld\n",
1139            debugstr_w(lpNamedPipeName), lpInput, lpInputSize,
1140            lpOutput, lpOutputSize, lpBytesRead, nTimeout);
1141     return FALSE;
1142 }
1143
1144 /******************************************************************
1145  *              CreatePipe (KERNEL32.@)
1146  *
1147  */
1148 BOOL WINAPI CreatePipe( PHANDLE hReadPipe, PHANDLE hWritePipe,
1149                         LPSECURITY_ATTRIBUTES sa, DWORD size )
1150 {
1151     static unsigned  index = 0;
1152     char        name[64];
1153     HANDLE      hr, hw;
1154     unsigned    in_index = index;
1155
1156     *hReadPipe = *hWritePipe = INVALID_HANDLE_VALUE;
1157     /* generate a unique pipe name (system wide) */
1158     do
1159     {
1160         sprintf(name, "\\\\.\\pipe\\Win32.Pipes.%08lu.%08u", GetCurrentProcessId(), ++index);
1161         hr = CreateNamedPipeA(name, PIPE_ACCESS_INBOUND, 
1162                               PIPE_TYPE_BYTE | PIPE_WAIT, 1, size, size, 
1163                               NMPWAIT_USE_DEFAULT_WAIT, sa);
1164     } while (hr == INVALID_HANDLE_VALUE && index != in_index);
1165     /* from completion sakeness, I think system resources might be exhausted before this happens !! */
1166     if (hr == INVALID_HANDLE_VALUE) return FALSE;
1167
1168     hw = CreateFileA(name, GENERIC_WRITE, 0, sa, OPEN_EXISTING, 0, 0);
1169     if (hw == INVALID_HANDLE_VALUE) 
1170     {
1171         CloseHandle(hr);
1172         return FALSE;
1173     }
1174
1175     *hReadPipe = hr;
1176     *hWritePipe = hw;
1177     return TRUE;
1178 }
1179
1180
1181 /******************************************************************************
1182  * CreateMailslotA [KERNEL32.@]
1183  */
1184 HANDLE WINAPI CreateMailslotA( LPCSTR lpName, DWORD nMaxMessageSize,
1185                                DWORD lReadTimeout, LPSECURITY_ATTRIBUTES sa )
1186 {
1187     DWORD len;
1188     HANDLE handle;
1189     LPWSTR name = NULL;
1190
1191     TRACE("%s %ld %ld %p\n", debugstr_a(lpName),
1192           nMaxMessageSize, lReadTimeout, sa);
1193
1194     if( lpName )
1195     {
1196         len = MultiByteToWideChar( CP_ACP, 0, lpName, -1, NULL, 0 );
1197         name = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
1198         MultiByteToWideChar( CP_ACP, 0, lpName, -1, name, len );
1199     }
1200
1201     handle = CreateMailslotW( name, nMaxMessageSize, lReadTimeout, sa );
1202
1203     if( name )
1204         HeapFree( GetProcessHeap(), 0, name );
1205
1206     return handle;
1207 }
1208
1209
1210 /******************************************************************************
1211  * CreateMailslotW [KERNEL32.@]  Creates a mailslot with specified name
1212  *
1213  * PARAMS
1214  *    lpName          [I] Pointer to string for mailslot name
1215  *    nMaxMessageSize [I] Maximum message size
1216  *    lReadTimeout    [I] Milliseconds before read time-out
1217  *    sa              [I] Pointer to security structure
1218  *
1219  * RETURNS
1220  *    Success: Handle to mailslot
1221  *    Failure: INVALID_HANDLE_VALUE
1222  */
1223 HANDLE WINAPI CreateMailslotW( LPCWSTR lpName, DWORD nMaxMessageSize,
1224                                DWORD lReadTimeout, LPSECURITY_ATTRIBUTES sa )
1225 {
1226     FIXME("(%s,%ld,%ld,%p): stub\n", debugstr_w(lpName),
1227           nMaxMessageSize, lReadTimeout, sa);
1228     return (HANDLE)1;
1229 }
1230
1231
1232 /******************************************************************************
1233  * GetMailslotInfo [KERNEL32.@]  Retrieves info about specified mailslot
1234  *
1235  * PARAMS
1236  *    hMailslot        [I] Mailslot handle
1237  *    lpMaxMessageSize [O] Address of maximum message size
1238  *    lpNextSize       [O] Address of size of next message
1239  *    lpMessageCount   [O] Address of number of messages
1240  *    lpReadTimeout    [O] Address of read time-out
1241  *
1242  * RETURNS
1243  *    Success: TRUE
1244  *    Failure: FALSE
1245  */
1246 BOOL WINAPI GetMailslotInfo( HANDLE hMailslot, LPDWORD lpMaxMessageSize,
1247                                LPDWORD lpNextSize, LPDWORD lpMessageCount,
1248                                LPDWORD lpReadTimeout )
1249 {
1250     FIXME("(%p): stub\n",hMailslot);
1251     if (lpMaxMessageSize) *lpMaxMessageSize = (DWORD)NULL;
1252     if (lpNextSize) *lpNextSize = (DWORD)NULL;
1253     if (lpMessageCount) *lpMessageCount = (DWORD)NULL;
1254     if (lpReadTimeout) *lpReadTimeout = (DWORD)NULL;
1255     return TRUE;
1256 }
1257
1258
1259 /******************************************************************************
1260  * SetMailslotInfo [KERNEL32.@]  Sets the read timeout of a specified mailslot
1261  *
1262  * RETURNS
1263  *    Success: TRUE
1264  *    Failure: FALSE
1265  */
1266 BOOL WINAPI SetMailslotInfo( HANDLE hMailslot, DWORD dwReadTimeout)
1267 {
1268     FIXME("%p %ld: stub\n", hMailslot, dwReadTimeout);
1269     return TRUE;
1270 }
1271
1272
1273 #ifdef __i386__
1274
1275 /***********************************************************************
1276  *              InterlockedCompareExchange (KERNEL32.@)
1277  */
1278 /* LONG WINAPI InterlockedCompareExchange( PLONG dest, LONG xchg, LONG compare ); */
1279 __ASM_GLOBAL_FUNC(InterlockedCompareExchange,
1280                   "movl 12(%esp),%eax\n\t"
1281                   "movl 8(%esp),%ecx\n\t"
1282                   "movl 4(%esp),%edx\n\t"
1283                   "lock; cmpxchgl %ecx,(%edx)\n\t"
1284                   "ret $12");
1285
1286 /***********************************************************************
1287  *              InterlockedExchange (KERNEL32.@)
1288  */
1289 /* LONG WINAPI InterlockedExchange( PLONG dest, LONG val ); */
1290 __ASM_GLOBAL_FUNC(InterlockedExchange,
1291                   "movl 8(%esp),%eax\n\t"
1292                   "movl 4(%esp),%edx\n\t"
1293                   "lock; xchgl %eax,(%edx)\n\t"
1294                   "ret $8");
1295
1296 /***********************************************************************
1297  *              InterlockedExchangeAdd (KERNEL32.@)
1298  */
1299 /* LONG WINAPI InterlockedExchangeAdd( PLONG dest, LONG incr ); */
1300 __ASM_GLOBAL_FUNC(InterlockedExchangeAdd,
1301                   "movl 8(%esp),%eax\n\t"
1302                   "movl 4(%esp),%edx\n\t"
1303                   "lock; xaddl %eax,(%edx)\n\t"
1304                   "ret $8");
1305
1306 /***********************************************************************
1307  *              InterlockedIncrement (KERNEL32.@)
1308  */
1309 /* LONG WINAPI InterlockedIncrement( PLONG dest ); */
1310 __ASM_GLOBAL_FUNC(InterlockedIncrement,
1311                   "movl 4(%esp),%edx\n\t"
1312                   "movl $1,%eax\n\t"
1313                   "lock; xaddl %eax,(%edx)\n\t"
1314                   "incl %eax\n\t"
1315                   "ret $4");
1316
1317 /***********************************************************************
1318  *              InterlockedDecrement (KERNEL32.@)
1319  */
1320 __ASM_GLOBAL_FUNC(InterlockedDecrement,
1321                   "movl 4(%esp),%edx\n\t"
1322                   "movl $-1,%eax\n\t"
1323                   "lock; xaddl %eax,(%edx)\n\t"
1324                   "decl %eax\n\t"
1325                   "ret $4");
1326
1327 #else  /* __i386__ */
1328
1329 /***********************************************************************
1330  *              InterlockedCompareExchange (KERNEL32.@)
1331  */
1332 LONG WINAPI InterlockedCompareExchange( PLONG dest, LONG xchg, LONG compare )
1333 {
1334     return interlocked_cmpxchg( dest, xchg, compare );
1335 }
1336
1337 /***********************************************************************
1338  *              InterlockedExchange (KERNEL32.@)
1339  */
1340 LONG WINAPI InterlockedExchange( PLONG dest, LONG val )
1341 {
1342     return interlocked_xchg( dest, val );
1343 }
1344
1345 /***********************************************************************
1346  *              InterlockedExchangeAdd (KERNEL32.@)
1347  */
1348 LONG WINAPI InterlockedExchangeAdd( PLONG dest, LONG incr )
1349 {
1350     return interlocked_xchg_add( dest, incr );
1351 }
1352
1353 /***********************************************************************
1354  *              InterlockedIncrement (KERNEL32.@)
1355  */
1356 LONG WINAPI InterlockedIncrement( PLONG dest )
1357 {
1358     return interlocked_xchg_add( dest, 1 ) + 1;
1359 }
1360
1361 /***********************************************************************
1362  *              InterlockedDecrement (KERNEL32.@)
1363  */
1364 LONG WINAPI InterlockedDecrement( PLONG dest )
1365 {
1366     return interlocked_xchg_add( dest, -1 ) - 1;
1367 }
1368
1369 #endif  /* __i386__ */