fdwalk should return 0 on an empty directory
[kopensolaris-gnu/glibc.git] / nptl / sysdeps / unix / sysv / linux / i386 / i486 / lowlevellock.S
1 /* Copyright (C) 2002, 2003, 2004, 2006, 2007 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #include <sysdep.h>
21 #include <pthread-errnos.h>
22 #include <kernel-features.h>
23 #include <lowlevellock.h>
24
25         .text
26
27 #ifdef __ASSUME_PRIVATE_FUTEX
28 # define LOAD_PRIVATE_FUTEX_WAIT(reg) \
29         movl    $(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), reg
30 # define LOAD_PRIVATE_FUTEX_WAKE(reg) \
31         movl    $(FUTEX_WAKE | FUTEX_PRIVATE_FLAG), reg
32 # define LOAD_FUTEX_WAIT(reg) \
33         xorl    $(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), reg
34 # define LOAD_FUTEX_WAKE(reg) \
35         xorl    $(FUTEX_WAKE | FUTEX_PRIVATE_FLAG), reg
36 #else
37 # if FUTEX_WAIT == 0
38 #  define LOAD_PRIVATE_FUTEX_WAIT(reg) \
39         movl    %gs:PRIVATE_FUTEX, reg
40 # else
41 #  define LOAD_PRIVATE_FUTEX_WAIT(reg) \
42         movl    %gs:PRIVATE_FUTEX, reg ; \
43         orl     $FUTEX_WAIT, reg
44 # endif
45 # define LOAD_PRIVATE_FUTEX_WAKE(reg) \
46         movl    %gs:PRIVATE_FUTEX, reg ; \
47         orl     $FUTEX_WAKE, reg
48 # if FUTEX_WAIT == 0
49 #  define LOAD_FUTEX_WAIT(reg) \
50         xorl    $FUTEX_PRIVATE_FLAG, reg ; \
51         andl    %gs:PRIVATE_FUTEX, reg
52 # else
53 #  define LOAD_FUTEX_WAIT(reg) \
54         xorl    $FUTEX_PRIVATE_FLAG, reg ; \
55         andl    %gs:PRIVATE_FUTEX, reg ; \
56         orl     $FUTEX_WAIT, reg
57 # endif
58 # define LOAD_FUTEX_WAKE(reg) \
59         xorl    $FUTEX_PRIVATE_FLAG, reg ; \
60         andl    %gs:PRIVATE_FUTEX, reg ; \
61         orl     $FUTEX_WAKE, reg
62 #endif
63
64         .globl  __lll_lock_wait_private
65         .type   __lll_lock_wait_private,@function
66         .hidden __lll_lock_wait_private
67         .align  16
68 __lll_lock_wait_private:
69         cfi_startproc
70         pushl   %edx
71         cfi_adjust_cfa_offset(4)
72         pushl   %ebx
73         cfi_adjust_cfa_offset(4)
74         pushl   %esi
75         cfi_adjust_cfa_offset(4)
76         cfi_offset(%edx, -8)
77         cfi_offset(%ebx, -12)
78         cfi_offset(%esi, -16)
79
80         movl    $2, %edx
81         movl    %ecx, %ebx
82         xorl    %esi, %esi      /* No timeout.  */
83         LOAD_PRIVATE_FUTEX_WAIT (%ecx)
84
85         cmpl    %edx, %eax      /* NB:   %edx == 2 */
86         jne 2f
87
88 1:      movl    $SYS_futex, %eax
89         ENTER_KERNEL
90
91 2:      movl    %edx, %eax
92         xchgl   %eax, (%ebx)    /* NB:   lock is implied */
93
94         testl   %eax, %eax
95         jnz     1b
96
97         popl    %esi
98         cfi_adjust_cfa_offset(-4)
99         cfi_restore(%esi)
100         popl    %ebx
101         cfi_adjust_cfa_offset(-4)
102         cfi_restore(%ebx)
103         popl    %edx
104         cfi_adjust_cfa_offset(-4)
105         cfi_restore(%edx)
106         ret
107         cfi_endproc
108         .size   __lll_lock_wait_private,.-__lll_lock_wait_private
109
110 #ifdef NOT_IN_libc
111         .globl  __lll_lock_wait
112         .type   __lll_lock_wait,@function
113         .hidden __lll_lock_wait
114         .align  16
115 __lll_lock_wait:
116         cfi_startproc
117         pushl   %edx
118         cfi_adjust_cfa_offset(4)
119         pushl   %ebx
120         cfi_adjust_cfa_offset(4)
121         pushl   %esi
122         cfi_adjust_cfa_offset(4)
123         cfi_offset(%edx, -8)
124         cfi_offset(%ebx, -12)
125         cfi_offset(%esi, -16)
126
127         movl    %edx, %ebx
128         movl    $2, %edx
129         xorl    %esi, %esi      /* No timeout.  */
130         LOAD_FUTEX_WAIT (%ecx)
131
132         cmpl    %edx, %eax      /* NB:   %edx == 2 */
133         jne 2f
134
135 1:      movl    $SYS_futex, %eax
136         ENTER_KERNEL
137
138 2:      movl    %edx, %eax
139         xchgl   %eax, (%ebx)    /* NB:   lock is implied */
140
141         testl   %eax, %eax
142         jnz     1b
143
144         popl    %esi
145         cfi_adjust_cfa_offset(-4)
146         cfi_restore(%esi)
147         popl    %ebx
148         cfi_adjust_cfa_offset(-4)
149         cfi_restore(%ebx)
150         popl    %edx
151         cfi_adjust_cfa_offset(-4)
152         cfi_restore(%edx)
153         ret
154         cfi_endproc
155         .size   __lll_lock_wait,.-__lll_lock_wait
156
157         .globl  __lll_timedlock_wait
158         .type   __lll_timedlock_wait,@function
159         .hidden __lll_timedlock_wait
160         .align  16
161 __lll_timedlock_wait:
162         cfi_startproc
163         /* Check for a valid timeout value.  */
164         cmpl    $1000000000, 4(%edx)
165         jae     3f
166
167         pushl   %edi
168         cfi_adjust_cfa_offset(4)
169         pushl   %esi
170         cfi_adjust_cfa_offset(4)
171         pushl   %ebx
172         cfi_adjust_cfa_offset(4)
173         pushl   %ebp
174         cfi_adjust_cfa_offset(4)
175         cfi_offset(%edi, -8)
176         cfi_offset(%esi, -12)
177         cfi_offset(%ebx, -16)
178         cfi_offset(%ebp, -20)
179
180         /* Stack frame for the timespec and timeval structs.  */
181         subl    $8, %esp
182         cfi_adjust_cfa_offset(8)
183
184         movl    %ecx, %ebp
185         movl    %edx, %edi
186
187 1:
188         /* Get current time.  */
189         movl    %esp, %ebx
190         xorl    %ecx, %ecx
191         movl    $__NR_gettimeofday, %eax
192         ENTER_KERNEL
193
194         /* Compute relative timeout.  */
195         movl    4(%esp), %eax
196         movl    $1000, %edx
197         mul     %edx            /* Milli seconds to nano seconds.  */
198         movl    (%edi), %ecx
199         movl    4(%edi), %edx
200         subl    (%esp), %ecx
201         subl    %eax, %edx
202         jns     4f
203         addl    $1000000000, %edx
204         subl    $1, %ecx
205 4:      testl   %ecx, %ecx
206         js      5f              /* Time is already up.  */
207
208         /* Store relative timeout.  */
209         movl    %ecx, (%esp)
210         movl    %edx, 4(%esp)
211
212         movl    %ebp, %ebx
213
214         movl    $1, %eax
215         movl    $2, %edx
216         LOCK
217         cmpxchgl %edx, (%ebx)
218
219         testl   %eax, %eax
220         je      8f
221
222         /* Futex call.  */
223         movl    %esp, %esi
224         movl    16(%esp), %ecx
225         LOAD_FUTEX_WAIT (%ecx)
226         movl    $SYS_futex, %eax
227         ENTER_KERNEL
228         movl    %eax, %ecx
229
230 8:                              /* NB: %edx == 2 */
231         xorl    %eax, %eax
232         LOCK
233         cmpxchgl %edx, (%ebx)
234
235         jnz     7f
236
237 6:      addl    $8, %esp
238         cfi_adjust_cfa_offset(-8)
239         popl    %ebp
240         cfi_adjust_cfa_offset(-4)
241         cfi_restore(%ebp)
242         popl    %ebx
243         cfi_adjust_cfa_offset(-4)
244         cfi_restore(%ebx)
245         popl    %esi
246         cfi_adjust_cfa_offset(-4)
247         cfi_restore(%esi)
248         popl    %edi
249         cfi_adjust_cfa_offset(-4)
250         cfi_restore(%edi)
251         ret
252
253 3:      movl    $EINVAL, %eax
254         ret
255
256         cfi_adjust_cfa_offset(24)
257         cfi_offset(%edi, -8)
258         cfi_offset(%esi, -12)
259         cfi_offset(%ebx, -16)
260         cfi_offset(%ebp, -20)
261         /* Check whether the time expired.  */
262 7:      cmpl    $-ETIMEDOUT, %ecx
263         je      5f
264
265         /* Make sure the current holder knows we are going to sleep.  */
266         movl    %edx, %eax
267         xchgl   %eax, (%ebx)
268         testl   %eax, %eax
269         jz      6b
270         jmp     1b
271
272 5:      movl    $ETIMEDOUT, %eax
273         jmp     6b
274         cfi_endproc
275         .size   __lll_timedlock_wait,.-__lll_timedlock_wait
276 #endif
277
278         .globl  __lll_unlock_wake_private
279         .type   __lll_unlock_wake_private,@function
280         .hidden __lll_unlock_wake_private
281         .align  16
282 __lll_unlock_wake_private:
283         cfi_startproc
284         pushl   %ebx
285         cfi_adjust_cfa_offset(4)
286         pushl   %ecx
287         cfi_adjust_cfa_offset(4)
288         pushl   %edx
289         cfi_adjust_cfa_offset(4)
290         cfi_offset(%ebx, -8)
291         cfi_offset(%ecx, -12)
292         cfi_offset(%edx, -16)
293
294         movl    %eax, %ebx
295         movl    $0, (%eax)
296         LOAD_PRIVATE_FUTEX_WAKE (%ecx)
297         movl    $1, %edx        /* Wake one thread.  */
298         movl    $SYS_futex, %eax
299         ENTER_KERNEL
300
301         popl    %edx
302         cfi_adjust_cfa_offset(-4)
303         cfi_restore(%edx)
304         popl    %ecx
305         cfi_adjust_cfa_offset(-4)
306         cfi_restore(%ecx)
307         popl    %ebx
308         cfi_adjust_cfa_offset(-4)
309         cfi_restore(%ebx)
310         ret
311         cfi_endproc
312         .size   __lll_unlock_wake_private,.-__lll_unlock_wake_private
313
314 #ifdef NOT_IN_libc
315         .globl  __lll_unlock_wake
316         .type   __lll_unlock_wake,@function
317         .hidden __lll_unlock_wake
318         .align  16
319 __lll_unlock_wake:
320         cfi_startproc
321         pushl   %ebx
322         cfi_adjust_cfa_offset(4)
323         pushl   %ecx
324         cfi_adjust_cfa_offset(4)
325         pushl   %edx
326         cfi_adjust_cfa_offset(4)
327         cfi_offset(%ebx, -8)
328         cfi_offset(%ecx, -12)
329         cfi_offset(%edx, -16)
330
331         movl    %eax, %ebx
332         movl    $0, (%eax)
333         LOAD_FUTEX_WAKE (%ecx)
334         movl    $1, %edx        /* Wake one thread.  */
335         movl    $SYS_futex, %eax
336         ENTER_KERNEL
337
338         popl    %edx
339         cfi_adjust_cfa_offset(-4)
340         cfi_restore(%edx)
341         popl    %ecx
342         cfi_adjust_cfa_offset(-4)
343         cfi_restore(%ecx)
344         popl    %ebx
345         cfi_adjust_cfa_offset(-4)
346         cfi_restore(%ebx)
347         ret
348         cfi_endproc
349         .size   __lll_unlock_wake,.-__lll_unlock_wake
350
351         .globl  __lll_timedwait_tid
352         .type   __lll_timedwait_tid,@function
353         .hidden __lll_timedwait_tid
354         .align  16
355 __lll_timedwait_tid:
356         pushl   %edi
357         pushl   %esi
358         pushl   %ebx
359         pushl   %ebp
360
361         movl    %eax, %ebp
362         movl    %edx, %edi
363         subl    $8, %esp
364
365         /* Get current time.  */
366 2:      movl    %esp, %ebx
367         xorl    %ecx, %ecx
368         movl    $__NR_gettimeofday, %eax
369         ENTER_KERNEL
370
371         /* Compute relative timeout.  */
372         movl    4(%esp), %eax
373         movl    $1000, %edx
374         mul     %edx            /* Milli seconds to nano seconds.  */
375         movl    (%edi), %ecx
376         movl    4(%edi), %edx
377         subl    (%esp), %ecx
378         subl    %eax, %edx
379         jns     5f
380         addl    $1000000000, %edx
381         subl    $1, %ecx
382 5:      testl   %ecx, %ecx
383         js      6f              /* Time is already up.  */
384
385         movl    %ecx, (%esp)    /* Store relative timeout.  */
386         movl    %edx, 4(%esp)
387
388         movl    (%ebp), %edx
389         testl   %edx, %edx
390         jz      4f
391
392         movl    %esp, %esi
393         /* XXX The kernel so far uses global futex for the wakeup at
394            all times.  */
395         xorl    %ecx, %ecx      /* movl $FUTEX_WAIT, %ecx */
396         movl    %ebp, %ebx
397         movl    $SYS_futex, %eax
398         ENTER_KERNEL
399
400         cmpl    $0, (%ebx)
401         jne     1f
402 4:      xorl    %eax, %eax
403
404 3:      addl    $8, %esp
405         popl    %ebp
406         popl    %ebx
407         popl    %esi
408         popl    %edi
409         ret
410
411 1:      cmpl    $-ETIMEDOUT, %eax
412         jne     2b
413 6:      movl    $ETIMEDOUT, %eax
414         jmp     3b
415         .size   __lll_timedwait_tid,.-__lll_timedwait_tid
416 #endif