Revert "rename amd64 architecture to x86_64"
[dragonfly.git] / lib / libc_r / uthread / uthread_fd.c
1 /*
2  * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by John Birrell.
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $FreeBSD: src/lib/libc_r/uthread/uthread_fd.c,v 1.16.2.7 2002/10/22 14:44:03 fjoe Exp $
33  * $DragonFly: src/lib/libc_r/uthread/uthread_fd.c,v 1.3 2006/06/14 01:45:28 dillon Exp $
34  *
35  */
36 #include <errno.h>
37 #include <fcntl.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <pthread.h>
41 #include "pthread_private.h"
42
43 #define FDQ_INSERT(q,p)                                 \
44 do {                                                    \
45         TAILQ_INSERT_TAIL(q,p,qe);                      \
46         p->flags |= PTHREAD_FLAGS_IN_FDQ;               \
47 } while (0)
48
49 #define FDQ_REMOVE(q,p)                                 \
50 do {                                                    \
51         if ((p->flags & PTHREAD_FLAGS_IN_FDQ) != 0) {   \
52                 TAILQ_REMOVE(q,p,qe);                   \
53                 p->flags &= ~PTHREAD_FLAGS_IN_FDQ;      \
54         }                                               \
55 } while (0)
56
57
58 /* Static variables: */
59 static  spinlock_t      fd_table_lock   = _SPINLOCK_INITIALIZER;
60
61 /* Prototypes: */
62 #ifdef _FDLOCKS_ENABLED
63 static inline pthread_t fd_next_reader(int fd);
64 static inline pthread_t fd_next_writer(int fd);
65 #endif
66
67
68 /*
69  * This function *must* return -1 and set the thread specific errno
70  * as a system call. This is because the error return from this
71  * function is propagated directly back from thread-wrapped system
72  * calls.
73  */
74
75 int
76 _thread_fd_table_init(int fd)
77 {
78         int     ret = 0;
79         struct fd_table_entry *entry;
80         int     saved_errno;
81
82         if (_thread_initial == NULL)
83                 _thread_init();
84
85         /* Check if the file descriptor is out of range: */
86         if (fd < 0 || fd >= _thread_dtablesize) {
87                 /* Return a bad file descriptor error: */
88                 errno = EBADF;
89                 ret = -1;
90         }
91
92         /*
93          * Check if memory has already been allocated for this file
94          * descriptor: 
95          */
96         else if (_thread_fd_table[fd] != NULL) {
97                 /* Memory has already been allocated. */
98
99         /* Allocate memory for the file descriptor table entry: */
100         } else if ((entry = (struct fd_table_entry *)
101             malloc(sizeof(struct fd_table_entry))) == NULL) {
102                 /* Return an insufficient memory error: */
103                 errno = ENOMEM;
104                 ret = -1;
105         } else {
106                 /* Initialise the file locks: */
107                 memset(&entry->lock, 0, sizeof(entry->lock));
108                 entry->r_owner = NULL;
109                 entry->w_owner = NULL;
110                 entry->r_fname = NULL;
111                 entry->w_fname = NULL;
112                 entry->r_lineno = 0;
113                 entry->w_lineno = 0;
114                 entry->r_lockcount = 0;
115                 entry->w_lockcount = 0;
116
117                 /* Initialise the read/write queues: */
118                 TAILQ_INIT(&entry->r_queue);
119                 TAILQ_INIT(&entry->w_queue);
120
121                 /* Get the flags for the file: */
122                 if (((fd >= 3) || (_pthread_stdio_flags[fd] == -1)) &&
123                     (entry->flags = __sys_fcntl(fd, F_GETFL, 0)) == -1) {
124                         ret = -1;
125                 } else {
126                         /* Check if a stdio descriptor: */
127                         if ((fd < 3) && (_pthread_stdio_flags[fd] != -1)) {
128                                 /*
129                                  * Use the stdio flags read by
130                                  * _pthread_init() to avoid
131                                  * mistaking the non-blocking
132                                  * flag that, when set on one
133                                  * stdio fd, is set on all stdio
134                                  * fds.
135                                  */
136                                 entry->flags = _pthread_stdio_flags[fd];
137                         }
138
139                         /*
140                          * NOTE: We now use new system calls which allow
141                          * the non-blocking mode to be set on a per-I/O
142                          * basis, we no longer have to mess with the
143                          * file pointer (which can have unexpected side
144                          * effects since it might be shared with parent
145                          * processes such as, oh, gmake).
146                          */
147
148                         /* Lock the file descriptor table: */
149                         _SPINLOCK(&fd_table_lock);
150
151                         /*
152                          * Check if another thread allocated the
153                          * file descriptor entry while this thread
154                          * was doing the same thing. The table wasn't
155                          * kept locked during this operation because
156                          * it has the potential to recurse.
157                          */
158                         if (_thread_fd_table[fd] == NULL) {
159                                 /* This thread wins: */
160                                 _thread_fd_table[fd] = entry;
161                                 entry = NULL;
162                         }
163
164                         /* Unlock the file descriptor table: */
165                         _SPINUNLOCK(&fd_table_lock);
166                 }
167
168                 /*
169                  * Check if another thread initialised the table entry
170                  * before this one could:
171                  */
172                 if (entry != NULL)
173                         /*
174                          * Throw away the table entry that this thread
175                          * prepared. The other thread wins.
176                          */
177                         free(entry);
178         }
179
180         /* Return the completion status: */
181         return (ret);
182 }
183
184 int
185 _thread_fd_getflags(int fd)
186 {
187         if (_thread_fd_table[fd] != NULL)
188                 return (_thread_fd_table[fd]->flags);
189         else
190                 return (0);
191 }
192
193 void
194 _thread_fd_setflags(int fd, int flags)
195 {
196         if (_thread_fd_table[fd] != NULL)
197                 _thread_fd_table[fd]->flags = flags;
198 }
199
200 #ifdef _FDLOCKS_ENABLED
201 void
202 _thread_fd_unlock(int fd, int lock_type)
203 {
204         struct pthread  *curthread = _get_curthread();
205         int     ret;
206
207         /*
208          * Early return if magic descriptor used by "at" family of syscalls.
209          */
210         if (fd == AT_FDCWD)
211                 return (0);
212
213         /*
214          * Check that the file descriptor table is initialised for this
215          * entry: 
216          */
217         if ((ret = _thread_fd_table_init(fd)) == 0) {
218                 /*
219                  * Defer signals to protect the scheduling queues from
220                  * access by the signal handler:
221                  */
222                 _thread_kern_sig_defer();
223
224                 /*
225                  * Lock the file descriptor table entry to prevent
226                  * other threads for clashing with the current
227                  * thread's accesses:
228                  */
229                 _SPINLOCK(&_thread_fd_table[fd]->lock);
230
231                 /* Check if the running thread owns the read lock: */
232                 if (_thread_fd_table[fd]->r_owner == curthread) {
233                         /* Check the file descriptor and lock types: */
234                         if (lock_type == FD_READ || lock_type == FD_RDWR) {
235                                 /*
236                                  * Decrement the read lock count for the
237                                  * running thread: 
238                                  */
239                                 _thread_fd_table[fd]->r_lockcount--;
240
241                                 /*
242                                  * Check if the running thread still has read
243                                  * locks on this file descriptor: 
244                                  */
245                                 if (_thread_fd_table[fd]->r_lockcount != 0) {
246                                 }
247                                 /*
248                                  * Get the next thread in the queue for a
249                                  * read lock on this file descriptor: 
250                                  */
251                                 else if ((_thread_fd_table[fd]->r_owner = fd_next_reader(fd)) == NULL) {
252                                 } else {
253                                         /* Remove this thread from the queue: */
254                                         FDQ_REMOVE(&_thread_fd_table[fd]->r_queue,
255                                             _thread_fd_table[fd]->r_owner);
256
257                                         /*
258                                          * Set the state of the new owner of
259                                          * the thread to running: 
260                                          */
261                                         PTHREAD_NEW_STATE(_thread_fd_table[fd]->r_owner,PS_RUNNING);
262
263                                         /*
264                                          * Reset the number of read locks.
265                                          * This will be incremented by the
266                                          * new owner of the lock when it sees
267                                          * that it has the lock.                           
268                                          */
269                                         _thread_fd_table[fd]->r_lockcount = 0;
270                                 }
271                         }
272                 }
273                 /* Check if the running thread owns the write lock: */
274                 if (_thread_fd_table[fd]->w_owner == curthread) {
275                         /* Check the file descriptor and lock types: */
276                         if (lock_type == FD_WRITE || lock_type == FD_RDWR) {
277                                 /*
278                                  * Decrement the write lock count for the
279                                  * running thread: 
280                                  */
281                                 _thread_fd_table[fd]->w_lockcount--;
282
283                                 /*
284                                  * Check if the running thread still has
285                                  * write locks on this file descriptor: 
286                                  */
287                                 if (_thread_fd_table[fd]->w_lockcount != 0) {
288                                 }
289                                 /*
290                                  * Get the next thread in the queue for a
291                                  * write lock on this file descriptor: 
292                                  */
293                                 else if ((_thread_fd_table[fd]->w_owner = fd_next_writer(fd)) == NULL) {
294                                 } else {
295                                         /* Remove this thread from the queue: */
296                                         FDQ_REMOVE(&_thread_fd_table[fd]->w_queue,
297                                             _thread_fd_table[fd]->w_owner);
298
299                                         /*
300                                          * Set the state of the new owner of
301                                          * the thread to running: 
302                                          */
303                                         PTHREAD_NEW_STATE(_thread_fd_table[fd]->w_owner,PS_RUNNING);
304
305                                         /*
306                                          * Reset the number of write locks.
307                                          * This will be incremented by the
308                                          * new owner of the lock when it  
309                                          * sees that it has the lock.
310                                          */
311                                         _thread_fd_table[fd]->w_lockcount = 0;
312                                 }
313                         }
314                 }
315
316                 /* Unlock the file descriptor table entry: */
317                 _SPINUNLOCK(&_thread_fd_table[fd]->lock);
318
319                 /*
320                  * Undefer and handle pending signals, yielding if
321                  * necessary:
322                  */
323                 _thread_kern_sig_undefer();
324         }
325 }
326
327 int
328 _thread_fd_lock(int fd, int lock_type, struct timespec * timeout)
329 {
330         struct pthread  *curthread = _get_curthread();
331         int     ret;
332
333         /*
334          * Early return if magic descriptor used by "at" family of syscalls.
335          */
336         if (fd == AT_FDCWD)
337                 return (0);
338
339         /*
340          * Check that the file descriptor table is initialised for this
341          * entry: 
342          */
343         if ((ret = _thread_fd_table_init(fd)) == 0) {
344                 /* Clear the interrupted flag: */
345                 curthread->interrupted = 0;
346
347                 /*
348                  * Lock the file descriptor table entry to prevent
349                  * other threads for clashing with the current
350                  * thread's accesses:
351                  */
352                 _SPINLOCK(&_thread_fd_table[fd]->lock);
353
354                 /* Check the file descriptor and lock types: */
355                 if (lock_type == FD_READ || lock_type == FD_RDWR) {
356                         /*
357                          * Wait for the file descriptor to be locked
358                          * for read for the current thread: 
359                          */
360                         while ((_thread_fd_table[fd]->r_owner != curthread) &&
361                             (curthread->interrupted == 0)) {
362                                 /*
363                                  * Check if the file descriptor is locked by
364                                  * another thread: 
365                                  */
366                                 if (_thread_fd_table[fd]->r_owner != NULL) {
367                                         /*
368                                          * Another thread has locked the file
369                                          * descriptor for read, so join the
370                                          * queue of threads waiting for a  
371                                          * read lock on this file descriptor: 
372                                          */
373                                         FDQ_INSERT(&_thread_fd_table[fd]->r_queue, curthread);
374
375                                         /*
376                                          * Save the file descriptor details
377                                          * in the thread structure for the
378                                          * running thread: 
379                                          */
380                                         curthread->data.fd.fd = fd;
381
382                                         /* Set the timeout: */
383                                         _thread_kern_set_timeout(timeout);
384
385                                         /*
386                                          * Unlock the file descriptor
387                                          * table entry:
388                                          */
389                                         _SPINUNLOCK(&_thread_fd_table[fd]->lock);
390
391                                         /*
392                                          * Schedule this thread to wait on
393                                          * the read lock. It will only be
394                                          * woken when it becomes the next in
395                                          * the   queue and is granted access
396                                          * to the lock by the       thread
397                                          * that is unlocking the file
398                                          * descriptor.        
399                                          */
400                                         _thread_kern_sched_state(PS_FDLR_WAIT, __FILE__, __LINE__);
401
402                                         /*
403                                          * Lock the file descriptor
404                                          * table entry again:
405                                          */
406                                         _SPINLOCK(&_thread_fd_table[fd]->lock);
407
408                                         if (curthread->interrupted != 0) {
409                                                 FDQ_REMOVE(&_thread_fd_table[fd]->r_queue,
410                                                     curthread);
411                                         }
412                                 } else {
413                                         /*
414                                          * The running thread now owns the
415                                          * read lock on this file descriptor: 
416                                          */
417                                         _thread_fd_table[fd]->r_owner = curthread;
418
419                                         /*
420                                          * Reset the number of read locks for
421                                          * this file descriptor: 
422                                          */
423                                         _thread_fd_table[fd]->r_lockcount = 0;
424                                 }
425                         }
426
427                         if (_thread_fd_table[fd]->r_owner == curthread)
428                                 /* Increment the read lock count: */
429                                 _thread_fd_table[fd]->r_lockcount++;
430                 }
431
432                 /* Check the file descriptor and lock types: */
433                 if (curthread->interrupted == 0 &&
434                     (lock_type == FD_WRITE || lock_type == FD_RDWR)) {
435                         /*
436                          * Wait for the file descriptor to be locked
437                          * for write for the current thread: 
438                          */
439                         while ((_thread_fd_table[fd]->w_owner != curthread) &&
440                             (curthread->interrupted == 0)) {
441                                 /*
442                                  * Check if the file descriptor is locked by
443                                  * another thread: 
444                                  */
445                                 if (_thread_fd_table[fd]->w_owner != NULL) {
446                                         /*
447                                          * Another thread has locked the file
448                                          * descriptor for write, so join the
449                                          * queue of threads waiting for a 
450                                          * write lock on this file
451                                          * descriptor: 
452                                          */
453                                         FDQ_INSERT(&_thread_fd_table[fd]->w_queue, curthread);
454
455                                         /*
456                                          * Save the file descriptor details
457                                          * in the thread structure for the
458                                          * running thread: 
459                                          */
460                                         curthread->data.fd.fd = fd;
461
462                                         /* Set the timeout: */
463                                         _thread_kern_set_timeout(timeout);
464
465                                         /*
466                                          * Unlock the file descriptor
467                                          * table entry:
468                                          */
469                                         _SPINUNLOCK(&_thread_fd_table[fd]->lock);
470
471                                         /*
472                                          * Schedule this thread to wait on
473                                          * the write lock. It will only be
474                                          * woken when it becomes the next in
475                                          * the queue and is granted access to
476                                          * the lock by the thread that is
477                                          * unlocking the file descriptor.        
478                                          */
479                                         _thread_kern_sched_state(PS_FDLW_WAIT, __FILE__, __LINE__);
480
481                                         /*
482                                          * Lock the file descriptor
483                                          * table entry again:
484                                          */
485                                         _SPINLOCK(&_thread_fd_table[fd]->lock);
486
487                                         if (curthread->interrupted != 0) {
488                                                 FDQ_REMOVE(&_thread_fd_table[fd]->w_queue,
489                                                     curthread);
490                                         }
491                                 } else {
492                                         /*
493                                          * The running thread now owns the
494                                          * write lock on this   file
495                                          * descriptor: 
496                                          */
497                                         _thread_fd_table[fd]->w_owner = curthread;
498
499                                         /*
500                                          * Reset the number of write locks
501                                          * for this file descriptor: 
502                                          */
503                                         _thread_fd_table[fd]->w_lockcount = 0;
504                                 }
505                         }
506
507                         if (_thread_fd_table[fd]->w_owner == curthread)
508                                 /* Increment the write lock count: */
509                                 _thread_fd_table[fd]->w_lockcount++;
510                 }
511
512                 /* Unlock the file descriptor table entry: */
513                 _SPINUNLOCK(&_thread_fd_table[fd]->lock);
514
515                 if (curthread->interrupted != 0) {
516                         ret = -1;
517                         errno = EINTR;
518                         if (curthread->continuation != NULL)
519                                 curthread->continuation((void *)curthread);
520                 }
521         }
522
523         /* Return the completion status: */
524         return (ret);
525 }
526
527 void
528 _thread_fd_unlock_debug(int fd, int lock_type, char *fname, int lineno)
529 {
530         struct pthread  *curthread = _get_curthread();
531         int     ret;
532
533         /*
534          * Early return if magic descriptor used by "at" family of syscalls.
535          */
536         if (fd == AT_FDCWD)
537                 return (0);
538
539         /*
540          * Check that the file descriptor table is initialised for this
541          * entry: 
542          */
543         if ((ret = _thread_fd_table_init(fd)) == 0) {
544                 /*
545                  * Defer signals to protect the scheduling queues from
546                  * access by the signal handler:
547                  */
548                 _thread_kern_sig_defer();
549
550                 /*
551                  * Lock the file descriptor table entry to prevent
552                  * other threads for clashing with the current
553                  * thread's accesses:
554                  */
555                 _spinlock_debug(&_thread_fd_table[fd]->lock, fname, lineno);
556
557                 /* Check if the running thread owns the read lock: */
558                 if (_thread_fd_table[fd]->r_owner == curthread) {
559                         /* Check the file descriptor and lock types: */
560                         if (lock_type == FD_READ || lock_type == FD_RDWR) {
561                                 /*
562                                  * Decrement the read lock count for the
563                                  * running thread: 
564                                  */
565                                 _thread_fd_table[fd]->r_lockcount--;
566
567                                 /*
568                                  * Check if the running thread still has read
569                                  * locks on this file descriptor: 
570                                  */
571                                 if (_thread_fd_table[fd]->r_lockcount != 0) {
572                                 }
573                                 /*
574                                  * Get the next thread in the queue for a
575                                  * read lock on this file descriptor: 
576                                  */
577                                 else if ((_thread_fd_table[fd]->r_owner = fd_next_reader(fd)) == NULL) {
578                                 } else {
579                                         /* Remove this thread from the queue: */
580                                         FDQ_REMOVE(&_thread_fd_table[fd]->r_queue,
581                                             _thread_fd_table[fd]->r_owner);
582
583                                         /*
584                                          * Set the state of the new owner of
585                                          * the thread to  running: 
586                                          */
587                                         PTHREAD_NEW_STATE(_thread_fd_table[fd]->r_owner,PS_RUNNING);
588
589                                         /*
590                                          * Reset the number of read locks.
591                                          * This will be incremented by the
592                                          * new owner of the lock when it sees
593                                          * that it has the lock.                           
594                                          */
595                                         _thread_fd_table[fd]->r_lockcount = 0;
596                                 }
597                         }
598                 }
599                 /* Check if the running thread owns the write lock: */
600                 if (_thread_fd_table[fd]->w_owner == curthread) {
601                         /* Check the file descriptor and lock types: */
602                         if (lock_type == FD_WRITE || lock_type == FD_RDWR) {
603                                 /*
604                                  * Decrement the write lock count for the
605                                  * running thread: 
606                                  */
607                                 _thread_fd_table[fd]->w_lockcount--;
608
609                                 /*
610                                  * Check if the running thread still has
611                                  * write locks on this file descriptor: 
612                                  */
613                                 if (_thread_fd_table[fd]->w_lockcount != 0) {
614                                 }
615                                 /*
616                                  * Get the next thread in the queue for a
617                                  * write lock on this file descriptor: 
618                                  */
619                                 else if ((_thread_fd_table[fd]->w_owner = fd_next_writer(fd)) == NULL) {
620                                 } else {
621                                         /* Remove this thread from the queue: */
622                                         FDQ_REMOVE(&_thread_fd_table[fd]->w_queue,
623                                             _thread_fd_table[fd]->w_owner);
624
625                                         /*
626                                          * Set the state of the new owner of
627                                          * the thread to running: 
628                                          */
629                                         PTHREAD_NEW_STATE(_thread_fd_table[fd]->w_owner,PS_RUNNING);
630
631                                         /*
632                                          * Reset the number of write locks.
633                                          * This will be incremented by the
634                                          * new owner of the lock when it  
635                                          * sees that it has the lock.
636                                          */
637                                         _thread_fd_table[fd]->w_lockcount = 0;
638                                 }
639                         }
640                 }
641
642                 /* Unlock the file descriptor table entry: */
643                 _SPINUNLOCK(&_thread_fd_table[fd]->lock);
644
645                 /*
646                  * Undefer and handle pending signals, yielding if
647                  * necessary.
648                  */
649                 _thread_kern_sig_undefer();
650         }
651 }
652
653 int
654 _thread_fd_lock_debug(int fd, int lock_type, struct timespec * timeout,
655                 char *fname, int lineno)
656 {
657         struct pthread  *curthread = _get_curthread();
658         int     ret;
659
660         /*
661          * Early return if magic descriptor used by "at" family of syscalls.
662          */
663         if (fd == AT_FDCWD)
664                 return (0);
665
666         /*
667          * Check that the file descriptor table is initialised for this
668          * entry: 
669          */
670         if ((ret = _thread_fd_table_init(fd)) == 0) {
671                 /* Clear the interrupted flag: */
672                 curthread->interrupted = 0;
673
674                 /*
675                  * Lock the file descriptor table entry to prevent
676                  * other threads for clashing with the current
677                  * thread's accesses:
678                  */
679                 _spinlock_debug(&_thread_fd_table[fd]->lock, fname, lineno);
680
681                 /* Check the file descriptor and lock types: */
682                 if (lock_type == FD_READ || lock_type == FD_RDWR) {
683                         /*
684                          * Wait for the file descriptor to be locked
685                          * for read for the current thread: 
686                          */
687                         while ((_thread_fd_table[fd]->r_owner != curthread) &&
688                             (curthread->interrupted == 0)) {
689                                 /*
690                                  * Check if the file descriptor is locked by
691                                  * another thread: 
692                                  */
693                                 if (_thread_fd_table[fd]->r_owner != NULL) {
694                                         /*
695                                          * Another thread has locked the file
696                                          * descriptor for read, so join the
697                                          * queue of threads waiting for a  
698                                          * read lock on this file descriptor: 
699                                          */
700                                         FDQ_INSERT(&_thread_fd_table[fd]->r_queue, curthread);
701
702                                         /*
703                                          * Save the file descriptor details
704                                          * in the thread structure for the
705                                          * running thread: 
706                                          */
707                                         curthread->data.fd.fd = fd;
708                                         curthread->data.fd.branch = lineno;
709                                         curthread->data.fd.fname = fname;
710
711                                         /* Set the timeout: */
712                                         _thread_kern_set_timeout(timeout);
713
714                                         /*
715                                          * Unlock the file descriptor
716                                          * table entry:
717                                          */
718                                         _SPINUNLOCK(&_thread_fd_table[fd]->lock);
719
720                                         /*
721                                          * Schedule this thread to wait on
722                                          * the read lock. It will only be
723                                          * woken when it becomes the next in
724                                          * the   queue and is granted access
725                                          * to the lock by the       thread
726                                          * that is unlocking the file
727                                          * descriptor.        
728                                          */
729                                         _thread_kern_sched_state(PS_FDLR_WAIT, __FILE__, __LINE__);
730
731                                         /*
732                                          * Lock the file descriptor
733                                          * table entry again:
734                                          */
735                                         _SPINLOCK(&_thread_fd_table[fd]->lock);
736
737                                         if (curthread->interrupted != 0) {
738                                                 FDQ_REMOVE(&_thread_fd_table[fd]->r_queue,
739                                                     curthread);
740                                         }
741                                 } else {
742                                         /*
743                                          * The running thread now owns the
744                                          * read lock on this file descriptor: 
745                                          */
746                                         _thread_fd_table[fd]->r_owner = curthread;
747
748                                         /*
749                                          * Reset the number of read locks for
750                                          * this file descriptor: 
751                                          */
752                                         _thread_fd_table[fd]->r_lockcount = 0;
753
754                                         /*
755                                          * Save the source file details for
756                                          * debugging: 
757                                          */
758                                         _thread_fd_table[fd]->r_fname = fname;
759                                         _thread_fd_table[fd]->r_lineno = lineno;
760                                 }
761                         }
762
763                         if (_thread_fd_table[fd]->r_owner == curthread)
764                                 /* Increment the read lock count: */
765                                 _thread_fd_table[fd]->r_lockcount++;
766                 }
767
768                 /* Check the file descriptor and lock types: */
769                 if (curthread->interrupted == 0 &&
770                     (lock_type == FD_WRITE || lock_type == FD_RDWR)) {
771                         /*
772                          * Wait for the file descriptor to be locked
773                          * for write for the current thread: 
774                          */
775                         while ((_thread_fd_table[fd]->w_owner != curthread) &&
776                             (curthread->interrupted == 0)) {
777                                 /*
778                                  * Check if the file descriptor is locked by
779                                  * another thread: 
780                                  */
781                                 if (_thread_fd_table[fd]->w_owner != NULL) {
782                                         /*
783                                          * Another thread has locked the file
784                                          * descriptor for write, so join the
785                                          * queue of threads waiting for a 
786                                          * write lock on this file
787                                          * descriptor: 
788                                          */
789                                         FDQ_INSERT(&_thread_fd_table[fd]->w_queue, curthread);
790
791                                         /*
792                                          * Save the file descriptor details
793                                          * in the thread structure for the
794                                          * running thread: 
795                                          */
796                                         curthread->data.fd.fd = fd;
797                                         curthread->data.fd.branch = lineno;
798                                         curthread->data.fd.fname = fname;
799
800                                         /* Set the timeout: */
801                                         _thread_kern_set_timeout(timeout);
802
803                                         /*
804                                          * Unlock the file descriptor
805                                          * table entry:
806                                          */
807                                         _SPINUNLOCK(&_thread_fd_table[fd]->lock);
808
809                                         /*
810                                          * Schedule this thread to wait on
811                                          * the write lock. It will only be
812                                          * woken when it becomes the next in
813                                          * the queue and is granted access to
814                                          * the lock by the thread that is
815                                          * unlocking the file descriptor.        
816                                          */
817                                         _thread_kern_sched_state(PS_FDLW_WAIT, __FILE__, __LINE__);
818
819                                         /*
820                                          * Lock the file descriptor
821                                          * table entry again:
822                                          */
823                                         _SPINLOCK(&_thread_fd_table[fd]->lock);
824
825                                         if (curthread->interrupted != 0) {
826                                                 FDQ_REMOVE(&_thread_fd_table[fd]->w_queue,
827                                                     curthread);
828                                         }
829                                 } else {
830                                         /*
831                                          * The running thread now owns the
832                                          * write lock on this   file
833                                          * descriptor: 
834                                          */
835                                         _thread_fd_table[fd]->w_owner = curthread;
836
837                                         /*
838                                          * Reset the number of write locks
839                                          * for this file descriptor: 
840                                          */
841                                         _thread_fd_table[fd]->w_lockcount = 0;
842
843                                         /*
844                                          * Save the source file details for
845                                          * debugging: 
846                                          */
847                                         _thread_fd_table[fd]->w_fname = fname;
848                                         _thread_fd_table[fd]->w_lineno = lineno;
849                                 }
850                         }
851
852                         if (_thread_fd_table[fd]->w_owner == curthread)
853                                 /* Increment the write lock count: */
854                                 _thread_fd_table[fd]->w_lockcount++;
855                 }
856
857                 /* Unlock the file descriptor table entry: */
858                 _SPINUNLOCK(&_thread_fd_table[fd]->lock);
859
860                 if (curthread->interrupted != 0) {
861                         ret = -1;
862                         errno = EINTR;
863                         if (curthread->continuation != NULL)
864                                 curthread->continuation((void *)curthread);
865                 }
866         }
867
868         /* Return the completion status: */
869         return (ret);
870 }
871
872 void
873 _thread_fd_unlock_owned(pthread_t pthread)
874 {
875         int fd;
876
877         for (fd = 0; fd < _thread_dtablesize; fd++) {
878                 if ((_thread_fd_table[fd] != NULL) &&
879                     ((_thread_fd_table[fd]->r_owner == pthread) ||
880                     (_thread_fd_table[fd]->w_owner == pthread))) {
881                         /*
882                          * Defer signals to protect the scheduling queues
883                          * from access by the signal handler:
884                          */
885                         _thread_kern_sig_defer();
886
887                         /*
888                          * Lock the file descriptor table entry to prevent
889                          * other threads for clashing with the current
890                          * thread's accesses:
891                          */
892                         _SPINLOCK(&_thread_fd_table[fd]->lock);
893
894                         /* Check if the thread owns the read lock: */
895                         if (_thread_fd_table[fd]->r_owner == pthread) {
896                                 /* Clear the read lock count: */
897                                 _thread_fd_table[fd]->r_lockcount = 0;
898
899                                 /*
900                                  * Get the next thread in the queue for a
901                                  * read lock on this file descriptor: 
902                                  */
903                                 if ((_thread_fd_table[fd]->r_owner = fd_next_reader(fd)) != NULL) {
904                                         /* Remove this thread from the queue: */
905                                         FDQ_REMOVE(&_thread_fd_table[fd]->r_queue,
906                                             _thread_fd_table[fd]->r_owner);
907
908                                         /*
909                                          * Set the state of the new owner of
910                                          * the thread to running: 
911                                          */
912                                         PTHREAD_NEW_STATE(_thread_fd_table[fd]->r_owner,PS_RUNNING);
913                                 }
914                         }
915
916                         /* Check if the thread owns the write lock: */
917                         if (_thread_fd_table[fd]->w_owner == pthread) {
918                                 /* Clear the write lock count: */
919                                 _thread_fd_table[fd]->w_lockcount = 0;
920
921                                 /*
922                                  * Get the next thread in the queue for a
923                                  * write lock on this file descriptor: 
924                                  */
925                                 if ((_thread_fd_table[fd]->w_owner = fd_next_writer(fd)) != NULL) {
926                                         /* Remove this thread from the queue: */
927                                         FDQ_REMOVE(&_thread_fd_table[fd]->w_queue,
928                                             _thread_fd_table[fd]->w_owner);
929
930                                         /*
931                                          * Set the state of the new owner of
932                                          * the thread to running: 
933                                          */
934                                         PTHREAD_NEW_STATE(_thread_fd_table[fd]->w_owner,PS_RUNNING);
935
936                                 }
937                         }
938
939                         /* Unlock the file descriptor table entry: */
940                         _SPINUNLOCK(&_thread_fd_table[fd]->lock);
941
942                         /*
943                          * Undefer and handle pending signals, yielding if
944                          * necessary.
945                          */
946                         _thread_kern_sig_undefer();
947                 }
948         }
949 }
950
951 void
952 _fd_lock_backout(pthread_t pthread)
953 {
954         int     fd;
955
956         /*
957          * Defer signals to protect the scheduling queues
958          * from access by the signal handler:
959          */
960         _thread_kern_sig_defer();
961
962         switch (pthread->state) {
963
964         case PS_FDLR_WAIT:
965                 fd = pthread->data.fd.fd;
966
967                 /*
968                  * Lock the file descriptor table entry to prevent
969                  * other threads for clashing with the current
970                  * thread's accesses:
971                  */
972                 _SPINLOCK(&_thread_fd_table[fd]->lock);
973
974                 /* Remove the thread from the waiting queue: */
975                 FDQ_REMOVE(&_thread_fd_table[fd]->r_queue, pthread);
976                 break;
977
978         case PS_FDLW_WAIT:
979                 fd = pthread->data.fd.fd;
980
981                 /*
982                  * Lock the file descriptor table entry to prevent
983                  * other threads from clashing with the current
984                  * thread's accesses:
985                  */
986                 _SPINLOCK(&_thread_fd_table[fd]->lock);
987
988                 /* Remove the thread from the waiting queue: */
989                 FDQ_REMOVE(&_thread_fd_table[fd]->w_queue, pthread);
990                 break;
991
992         default:
993                 break;
994         }
995
996         /*
997          * Undefer and handle pending signals, yielding if
998          * necessary.
999          */
1000         _thread_kern_sig_undefer();
1001 }
1002
1003 static inline pthread_t
1004 fd_next_reader(int fd)
1005 {
1006         pthread_t pthread;
1007
1008         while (((pthread = TAILQ_FIRST(&_thread_fd_table[fd]->r_queue)) != NULL) &&
1009             (pthread->interrupted != 0)) {
1010                 /*
1011                  * This thread has either been interrupted by a signal or
1012                  * it has been canceled.  Remove it from the queue.
1013                  */
1014                 FDQ_REMOVE(&_thread_fd_table[fd]->r_queue, pthread);
1015         }
1016
1017         return (pthread);
1018 }
1019
1020 static inline pthread_t
1021 fd_next_writer(int fd)
1022 {
1023         pthread_t pthread;
1024
1025         while (((pthread = TAILQ_FIRST(&_thread_fd_table[fd]->w_queue)) != NULL) &&
1026             (pthread->interrupted != 0)) {
1027                 /*
1028                  * This thread has either been interrupted by a signal or
1029                  * it has been canceled.  Remove it from the queue.
1030                  */
1031                 FDQ_REMOVE(&_thread_fd_table[fd]->w_queue, pthread);
1032         }
1033
1034         return (pthread);
1035 }
1036
1037 #else
1038
1039 void
1040 _thread_fd_unlock(int fd, int lock_type)
1041 {
1042 }
1043
1044 int
1045 _thread_fd_lock(int fd, int lock_type, struct timespec * timeout)
1046 {
1047         /*
1048          * Insure that the file descriptor table is initialized for this
1049          * entry except if magic descriptor used by "at" family of syscalls.
1050          */
1051         return ((fd != AT_FDCWD) ? _thread_fd_table_init(fd) : 0);
1052 }
1053
1054 void
1055 _thread_fd_unlock_debug(int fd, int lock_type, char *fname, int lineno)
1056 {
1057 }
1058
1059 int
1060 _thread_fd_lock_debug(int fd, int lock_type, struct timespec * timeout,
1061                 char *fname, int lineno)
1062 {
1063         /*
1064          * Insure that the file descriptor table is initialized for this
1065          * entry except if magic descriptor used by "at" family of syscalls.
1066          */
1067         return ((fd != AT_FDCWD) ? _thread_fd_table_init(fd) : 0);
1068 }
1069
1070 void
1071 _thread_fd_unlock_owned(pthread_t pthread)
1072 {
1073 }
1074
1075 void
1076 _fd_lock_backout(pthread_t pthread)
1077 {
1078 }
1079
1080 #endif