Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[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.2 2003/06/17 04:26:48 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                 }
126                 else {
127                         /* Check if a stdio descriptor: */
128                         if ((fd < 3) && (_pthread_stdio_flags[fd] != -1))
129                                 /*
130                                  * Use the stdio flags read by
131                                  * _pthread_init() to avoid
132                                  * mistaking the non-blocking
133                                  * flag that, when set on one
134                                  * stdio fd, is set on all stdio
135                                  * fds.
136                                  */
137                                 entry->flags = _pthread_stdio_flags[fd];
138
139                         /*
140                          * Make the file descriptor non-blocking.
141                          * This might fail if the device driver does
142                          * not support non-blocking calls, or if the
143                          * driver is naturally non-blocking.
144                          */
145                         saved_errno = errno;
146                         __sys_fcntl(fd, F_SETFL,
147                             entry->flags | O_NONBLOCK);
148                         errno = saved_errno;
149
150                         /* Lock the file descriptor table: */
151                         _SPINLOCK(&fd_table_lock);
152
153                         /*
154                          * Check if another thread allocated the
155                          * file descriptor entry while this thread
156                          * was doing the same thing. The table wasn't
157                          * kept locked during this operation because
158                          * it has the potential to recurse.
159                          */
160                         if (_thread_fd_table[fd] == NULL) {
161                                 /* This thread wins: */
162                                 _thread_fd_table[fd] = entry;
163                                 entry = NULL;
164                         }
165
166                         /* Unlock the file descriptor table: */
167                         _SPINUNLOCK(&fd_table_lock);
168                 }
169
170                 /*
171                  * Check if another thread initialised the table entry
172                  * before this one could:
173                  */
174                 if (entry != NULL)
175                         /*
176                          * Throw away the table entry that this thread
177                          * prepared. The other thread wins.
178                          */
179                         free(entry);
180         }
181
182         /* Return the completion status: */
183         return (ret);
184 }
185
186 int
187 _thread_fd_getflags(int fd)
188 {
189         if (_thread_fd_table[fd] != NULL)
190                 return (_thread_fd_table[fd]->flags);
191         else
192                 return (0);
193 }
194
195 void
196 _thread_fd_setflags(int fd, int flags)
197 {
198         if (_thread_fd_table[fd] != NULL)
199                 _thread_fd_table[fd]->flags = flags;
200 }
201
202 #ifdef _FDLOCKS_ENABLED
203 void
204 _thread_fd_unlock(int fd, int lock_type)
205 {
206         struct pthread  *curthread = _get_curthread();
207         int     ret;
208
209         /*
210          * Check that the file descriptor table is initialised for this
211          * entry: 
212          */
213         if ((ret = _thread_fd_table_init(fd)) == 0) {
214                 /*
215                  * Defer signals to protect the scheduling queues from
216                  * access by the signal handler:
217                  */
218                 _thread_kern_sig_defer();
219
220                 /*
221                  * Lock the file descriptor table entry to prevent
222                  * other threads for clashing with the current
223                  * thread's accesses:
224                  */
225                 _SPINLOCK(&_thread_fd_table[fd]->lock);
226
227                 /* Check if the running thread owns the read lock: */
228                 if (_thread_fd_table[fd]->r_owner == curthread) {
229                         /* Check the file descriptor and lock types: */
230                         if (lock_type == FD_READ || lock_type == FD_RDWR) {
231                                 /*
232                                  * Decrement the read lock count for the
233                                  * running thread: 
234                                  */
235                                 _thread_fd_table[fd]->r_lockcount--;
236
237                                 /*
238                                  * Check if the running thread still has read
239                                  * locks on this file descriptor: 
240                                  */
241                                 if (_thread_fd_table[fd]->r_lockcount != 0) {
242                                 }
243                                 /*
244                                  * Get the next thread in the queue for a
245                                  * read lock on this file descriptor: 
246                                  */
247                                 else if ((_thread_fd_table[fd]->r_owner = fd_next_reader(fd)) == NULL) {
248                                 } else {
249                                         /* Remove this thread from the queue: */
250                                         FDQ_REMOVE(&_thread_fd_table[fd]->r_queue,
251                                             _thread_fd_table[fd]->r_owner);
252
253                                         /*
254                                          * Set the state of the new owner of
255                                          * the thread to running: 
256                                          */
257                                         PTHREAD_NEW_STATE(_thread_fd_table[fd]->r_owner,PS_RUNNING);
258
259                                         /*
260                                          * Reset the number of read locks.
261                                          * This will be incremented by the
262                                          * new owner of the lock when it sees
263                                          * that it has the lock.                           
264                                          */
265                                         _thread_fd_table[fd]->r_lockcount = 0;
266                                 }
267                         }
268                 }
269                 /* Check if the running thread owns the write lock: */
270                 if (_thread_fd_table[fd]->w_owner == curthread) {
271                         /* Check the file descriptor and lock types: */
272                         if (lock_type == FD_WRITE || lock_type == FD_RDWR) {
273                                 /*
274                                  * Decrement the write lock count for the
275                                  * running thread: 
276                                  */
277                                 _thread_fd_table[fd]->w_lockcount--;
278
279                                 /*
280                                  * Check if the running thread still has
281                                  * write locks on this file descriptor: 
282                                  */
283                                 if (_thread_fd_table[fd]->w_lockcount != 0) {
284                                 }
285                                 /*
286                                  * Get the next thread in the queue for a
287                                  * write lock on this file descriptor: 
288                                  */
289                                 else if ((_thread_fd_table[fd]->w_owner = fd_next_writer(fd)) == NULL) {
290                                 } else {
291                                         /* Remove this thread from the queue: */
292                                         FDQ_REMOVE(&_thread_fd_table[fd]->w_queue,
293                                             _thread_fd_table[fd]->w_owner);
294
295                                         /*
296                                          * Set the state of the new owner of
297                                          * the thread to running: 
298                                          */
299                                         PTHREAD_NEW_STATE(_thread_fd_table[fd]->w_owner,PS_RUNNING);
300
301                                         /*
302                                          * Reset the number of write locks.
303                                          * This will be incremented by the
304                                          * new owner of the lock when it  
305                                          * sees that it has the lock.
306                                          */
307                                         _thread_fd_table[fd]->w_lockcount = 0;
308                                 }
309                         }
310                 }
311
312                 /* Unlock the file descriptor table entry: */
313                 _SPINUNLOCK(&_thread_fd_table[fd]->lock);
314
315                 /*
316                  * Undefer and handle pending signals, yielding if
317                  * necessary:
318                  */
319                 _thread_kern_sig_undefer();
320         }
321 }
322
323 int
324 _thread_fd_lock(int fd, int lock_type, struct timespec * timeout)
325 {
326         struct pthread  *curthread = _get_curthread();
327         int     ret;
328
329         /*
330          * Check that the file descriptor table is initialised for this
331          * entry: 
332          */
333         if ((ret = _thread_fd_table_init(fd)) == 0) {
334                 /* Clear the interrupted flag: */
335                 curthread->interrupted = 0;
336
337                 /*
338                  * Lock the file descriptor table entry to prevent
339                  * other threads for clashing with the current
340                  * thread's accesses:
341                  */
342                 _SPINLOCK(&_thread_fd_table[fd]->lock);
343
344                 /* Check the file descriptor and lock types: */
345                 if (lock_type == FD_READ || lock_type == FD_RDWR) {
346                         /*
347                          * Wait for the file descriptor to be locked
348                          * for read for the current thread: 
349                          */
350                         while ((_thread_fd_table[fd]->r_owner != curthread) &&
351                             (curthread->interrupted == 0)) {
352                                 /*
353                                  * Check if the file descriptor is locked by
354                                  * another thread: 
355                                  */
356                                 if (_thread_fd_table[fd]->r_owner != NULL) {
357                                         /*
358                                          * Another thread has locked the file
359                                          * descriptor for read, so join the
360                                          * queue of threads waiting for a  
361                                          * read lock on this file descriptor: 
362                                          */
363                                         FDQ_INSERT(&_thread_fd_table[fd]->r_queue, curthread);
364
365                                         /*
366                                          * Save the file descriptor details
367                                          * in the thread structure for the
368                                          * running thread: 
369                                          */
370                                         curthread->data.fd.fd = fd;
371
372                                         /* Set the timeout: */
373                                         _thread_kern_set_timeout(timeout);
374
375                                         /*
376                                          * Unlock the file descriptor
377                                          * table entry:
378                                          */
379                                         _SPINUNLOCK(&_thread_fd_table[fd]->lock);
380
381                                         /*
382                                          * Schedule this thread to wait on
383                                          * the read lock. It will only be
384                                          * woken when it becomes the next in
385                                          * the   queue and is granted access
386                                          * to the lock by the       thread
387                                          * that is unlocking the file
388                                          * descriptor.        
389                                          */
390                                         _thread_kern_sched_state(PS_FDLR_WAIT, __FILE__, __LINE__);
391
392                                         /*
393                                          * Lock the file descriptor
394                                          * table entry again:
395                                          */
396                                         _SPINLOCK(&_thread_fd_table[fd]->lock);
397
398                                         if (curthread->interrupted != 0) {
399                                                 FDQ_REMOVE(&_thread_fd_table[fd]->r_queue,
400                                                     curthread);
401                                         }
402                                 } else {
403                                         /*
404                                          * The running thread now owns the
405                                          * read lock on this file descriptor: 
406                                          */
407                                         _thread_fd_table[fd]->r_owner = curthread;
408
409                                         /*
410                                          * Reset the number of read locks for
411                                          * this file descriptor: 
412                                          */
413                                         _thread_fd_table[fd]->r_lockcount = 0;
414                                 }
415                         }
416
417                         if (_thread_fd_table[fd]->r_owner == curthread)
418                                 /* Increment the read lock count: */
419                                 _thread_fd_table[fd]->r_lockcount++;
420                 }
421
422                 /* Check the file descriptor and lock types: */
423                 if (curthread->interrupted == 0 &&
424                     (lock_type == FD_WRITE || lock_type == FD_RDWR)) {
425                         /*
426                          * Wait for the file descriptor to be locked
427                          * for write for the current thread: 
428                          */
429                         while ((_thread_fd_table[fd]->w_owner != curthread) &&
430                             (curthread->interrupted == 0)) {
431                                 /*
432                                  * Check if the file descriptor is locked by
433                                  * another thread: 
434                                  */
435                                 if (_thread_fd_table[fd]->w_owner != NULL) {
436                                         /*
437                                          * Another thread has locked the file
438                                          * descriptor for write, so join the
439                                          * queue of threads waiting for a 
440                                          * write lock on this file
441                                          * descriptor: 
442                                          */
443                                         FDQ_INSERT(&_thread_fd_table[fd]->w_queue, curthread);
444
445                                         /*
446                                          * Save the file descriptor details
447                                          * in the thread structure for the
448                                          * running thread: 
449                                          */
450                                         curthread->data.fd.fd = fd;
451
452                                         /* Set the timeout: */
453                                         _thread_kern_set_timeout(timeout);
454
455                                         /*
456                                          * Unlock the file descriptor
457                                          * table entry:
458                                          */
459                                         _SPINUNLOCK(&_thread_fd_table[fd]->lock);
460
461                                         /*
462                                          * Schedule this thread to wait on
463                                          * the write lock. It will only be
464                                          * woken when it becomes the next in
465                                          * the queue and is granted access to
466                                          * the lock by the thread that is
467                                          * unlocking the file descriptor.        
468                                          */
469                                         _thread_kern_sched_state(PS_FDLW_WAIT, __FILE__, __LINE__);
470
471                                         /*
472                                          * Lock the file descriptor
473                                          * table entry again:
474                                          */
475                                         _SPINLOCK(&_thread_fd_table[fd]->lock);
476
477                                         if (curthread->interrupted != 0) {
478                                                 FDQ_REMOVE(&_thread_fd_table[fd]->w_queue,
479                                                     curthread);
480                                         }
481                                 } else {
482                                         /*
483                                          * The running thread now owns the
484                                          * write lock on this   file
485                                          * descriptor: 
486                                          */
487                                         _thread_fd_table[fd]->w_owner = curthread;
488
489                                         /*
490                                          * Reset the number of write locks
491                                          * for this file descriptor: 
492                                          */
493                                         _thread_fd_table[fd]->w_lockcount = 0;
494                                 }
495                         }
496
497                         if (_thread_fd_table[fd]->w_owner == curthread)
498                                 /* Increment the write lock count: */
499                                 _thread_fd_table[fd]->w_lockcount++;
500                 }
501
502                 /* Unlock the file descriptor table entry: */
503                 _SPINUNLOCK(&_thread_fd_table[fd]->lock);
504
505                 if (curthread->interrupted != 0) {
506                         ret = -1;
507                         errno = EINTR;
508                         if (curthread->continuation != NULL)
509                                 curthread->continuation((void *)curthread);
510                 }
511         }
512
513         /* Return the completion status: */
514         return (ret);
515 }
516
517 void
518 _thread_fd_unlock_debug(int fd, int lock_type, char *fname, int lineno)
519 {
520         struct pthread  *curthread = _get_curthread();
521         int     ret;
522
523         /*
524          * Check that the file descriptor table is initialised for this
525          * entry: 
526          */
527         if ((ret = _thread_fd_table_init(fd)) == 0) {
528                 /*
529                  * Defer signals to protect the scheduling queues from
530                  * access by the signal handler:
531                  */
532                 _thread_kern_sig_defer();
533
534                 /*
535                  * Lock the file descriptor table entry to prevent
536                  * other threads for clashing with the current
537                  * thread's accesses:
538                  */
539                 _spinlock_debug(&_thread_fd_table[fd]->lock, fname, lineno);
540
541                 /* Check if the running thread owns the read lock: */
542                 if (_thread_fd_table[fd]->r_owner == curthread) {
543                         /* Check the file descriptor and lock types: */
544                         if (lock_type == FD_READ || lock_type == FD_RDWR) {
545                                 /*
546                                  * Decrement the read lock count for the
547                                  * running thread: 
548                                  */
549                                 _thread_fd_table[fd]->r_lockcount--;
550
551                                 /*
552                                  * Check if the running thread still has read
553                                  * locks on this file descriptor: 
554                                  */
555                                 if (_thread_fd_table[fd]->r_lockcount != 0) {
556                                 }
557                                 /*
558                                  * Get the next thread in the queue for a
559                                  * read lock on this file descriptor: 
560                                  */
561                                 else if ((_thread_fd_table[fd]->r_owner = fd_next_reader(fd)) == NULL) {
562                                 } else {
563                                         /* Remove this thread from the queue: */
564                                         FDQ_REMOVE(&_thread_fd_table[fd]->r_queue,
565                                             _thread_fd_table[fd]->r_owner);
566
567                                         /*
568                                          * Set the state of the new owner of
569                                          * the thread to  running: 
570                                          */
571                                         PTHREAD_NEW_STATE(_thread_fd_table[fd]->r_owner,PS_RUNNING);
572
573                                         /*
574                                          * Reset the number of read locks.
575                                          * This will be incremented by the
576                                          * new owner of the lock when it sees
577                                          * that it has the lock.                           
578                                          */
579                                         _thread_fd_table[fd]->r_lockcount = 0;
580                                 }
581                         }
582                 }
583                 /* Check if the running thread owns the write lock: */
584                 if (_thread_fd_table[fd]->w_owner == curthread) {
585                         /* Check the file descriptor and lock types: */
586                         if (lock_type == FD_WRITE || lock_type == FD_RDWR) {
587                                 /*
588                                  * Decrement the write lock count for the
589                                  * running thread: 
590                                  */
591                                 _thread_fd_table[fd]->w_lockcount--;
592
593                                 /*
594                                  * Check if the running thread still has
595                                  * write locks on this file descriptor: 
596                                  */
597                                 if (_thread_fd_table[fd]->w_lockcount != 0) {
598                                 }
599                                 /*
600                                  * Get the next thread in the queue for a
601                                  * write lock on this file descriptor: 
602                                  */
603                                 else if ((_thread_fd_table[fd]->w_owner = fd_next_writer(fd)) == NULL) {
604                                 } else {
605                                         /* Remove this thread from the queue: */
606                                         FDQ_REMOVE(&_thread_fd_table[fd]->w_queue,
607                                             _thread_fd_table[fd]->w_owner);
608
609                                         /*
610                                          * Set the state of the new owner of
611                                          * the thread to running: 
612                                          */
613                                         PTHREAD_NEW_STATE(_thread_fd_table[fd]->w_owner,PS_RUNNING);
614
615                                         /*
616                                          * Reset the number of write locks.
617                                          * This will be incremented by the
618                                          * new owner of the lock when it  
619                                          * sees that it has the lock.
620                                          */
621                                         _thread_fd_table[fd]->w_lockcount = 0;
622                                 }
623                         }
624                 }
625
626                 /* Unlock the file descriptor table entry: */
627                 _SPINUNLOCK(&_thread_fd_table[fd]->lock);
628
629                 /*
630                  * Undefer and handle pending signals, yielding if
631                  * necessary.
632                  */
633                 _thread_kern_sig_undefer();
634         }
635 }
636
637 int
638 _thread_fd_lock_debug(int fd, int lock_type, struct timespec * timeout,
639                 char *fname, int lineno)
640 {
641         struct pthread  *curthread = _get_curthread();
642         int     ret;
643
644         /*
645          * Check that the file descriptor table is initialised for this
646          * entry: 
647          */
648         if ((ret = _thread_fd_table_init(fd)) == 0) {
649                 /* Clear the interrupted flag: */
650                 curthread->interrupted = 0;
651
652                 /*
653                  * Lock the file descriptor table entry to prevent
654                  * other threads for clashing with the current
655                  * thread's accesses:
656                  */
657                 _spinlock_debug(&_thread_fd_table[fd]->lock, fname, lineno);
658
659                 /* Check the file descriptor and lock types: */
660                 if (lock_type == FD_READ || lock_type == FD_RDWR) {
661                         /*
662                          * Wait for the file descriptor to be locked
663                          * for read for the current thread: 
664                          */
665                         while ((_thread_fd_table[fd]->r_owner != curthread) &&
666                             (curthread->interrupted == 0)) {
667                                 /*
668                                  * Check if the file descriptor is locked by
669                                  * another thread: 
670                                  */
671                                 if (_thread_fd_table[fd]->r_owner != NULL) {
672                                         /*
673                                          * Another thread has locked the file
674                                          * descriptor for read, so join the
675                                          * queue of threads waiting for a  
676                                          * read lock on this file descriptor: 
677                                          */
678                                         FDQ_INSERT(&_thread_fd_table[fd]->r_queue, curthread);
679
680                                         /*
681                                          * Save the file descriptor details
682                                          * in the thread structure for the
683                                          * running thread: 
684                                          */
685                                         curthread->data.fd.fd = fd;
686                                         curthread->data.fd.branch = lineno;
687                                         curthread->data.fd.fname = fname;
688
689                                         /* Set the timeout: */
690                                         _thread_kern_set_timeout(timeout);
691
692                                         /*
693                                          * Unlock the file descriptor
694                                          * table entry:
695                                          */
696                                         _SPINUNLOCK(&_thread_fd_table[fd]->lock);
697
698                                         /*
699                                          * Schedule this thread to wait on
700                                          * the read lock. It will only be
701                                          * woken when it becomes the next in
702                                          * the   queue and is granted access
703                                          * to the lock by the       thread
704                                          * that is unlocking the file
705                                          * descriptor.        
706                                          */
707                                         _thread_kern_sched_state(PS_FDLR_WAIT, __FILE__, __LINE__);
708
709                                         /*
710                                          * Lock the file descriptor
711                                          * table entry again:
712                                          */
713                                         _SPINLOCK(&_thread_fd_table[fd]->lock);
714
715                                         if (curthread->interrupted != 0) {
716                                                 FDQ_REMOVE(&_thread_fd_table[fd]->r_queue,
717                                                     curthread);
718                                         }
719                                 } else {
720                                         /*
721                                          * The running thread now owns the
722                                          * read lock on this file descriptor: 
723                                          */
724                                         _thread_fd_table[fd]->r_owner = curthread;
725
726                                         /*
727                                          * Reset the number of read locks for
728                                          * this file descriptor: 
729                                          */
730                                         _thread_fd_table[fd]->r_lockcount = 0;
731
732                                         /*
733                                          * Save the source file details for
734                                          * debugging: 
735                                          */
736                                         _thread_fd_table[fd]->r_fname = fname;
737                                         _thread_fd_table[fd]->r_lineno = lineno;
738                                 }
739                         }
740
741                         if (_thread_fd_table[fd]->r_owner == curthread)
742                                 /* Increment the read lock count: */
743                                 _thread_fd_table[fd]->r_lockcount++;
744                 }
745
746                 /* Check the file descriptor and lock types: */
747                 if (curthread->interrupted == 0 &&
748                     (lock_type == FD_WRITE || lock_type == FD_RDWR)) {
749                         /*
750                          * Wait for the file descriptor to be locked
751                          * for write for the current thread: 
752                          */
753                         while ((_thread_fd_table[fd]->w_owner != curthread) &&
754                             (curthread->interrupted == 0)) {
755                                 /*
756                                  * Check if the file descriptor is locked by
757                                  * another thread: 
758                                  */
759                                 if (_thread_fd_table[fd]->w_owner != NULL) {
760                                         /*
761                                          * Another thread has locked the file
762                                          * descriptor for write, so join the
763                                          * queue of threads waiting for a 
764                                          * write lock on this file
765                                          * descriptor: 
766                                          */
767                                         FDQ_INSERT(&_thread_fd_table[fd]->w_queue, curthread);
768
769                                         /*
770                                          * Save the file descriptor details
771                                          * in the thread structure for the
772                                          * running thread: 
773                                          */
774                                         curthread->data.fd.fd = fd;
775                                         curthread->data.fd.branch = lineno;
776                                         curthread->data.fd.fname = fname;
777
778                                         /* Set the timeout: */
779                                         _thread_kern_set_timeout(timeout);
780
781                                         /*
782                                          * Unlock the file descriptor
783                                          * table entry:
784                                          */
785                                         _SPINUNLOCK(&_thread_fd_table[fd]->lock);
786
787                                         /*
788                                          * Schedule this thread to wait on
789                                          * the write lock. It will only be
790                                          * woken when it becomes the next in
791                                          * the queue and is granted access to
792                                          * the lock by the thread that is
793                                          * unlocking the file descriptor.        
794                                          */
795                                         _thread_kern_sched_state(PS_FDLW_WAIT, __FILE__, __LINE__);
796
797                                         /*
798                                          * Lock the file descriptor
799                                          * table entry again:
800                                          */
801                                         _SPINLOCK(&_thread_fd_table[fd]->lock);
802
803                                         if (curthread->interrupted != 0) {
804                                                 FDQ_REMOVE(&_thread_fd_table[fd]->w_queue,
805                                                     curthread);
806                                         }
807                                 } else {
808                                         /*
809                                          * The running thread now owns the
810                                          * write lock on this   file
811                                          * descriptor: 
812                                          */
813                                         _thread_fd_table[fd]->w_owner = curthread;
814
815                                         /*
816                                          * Reset the number of write locks
817                                          * for this file descriptor: 
818                                          */
819                                         _thread_fd_table[fd]->w_lockcount = 0;
820
821                                         /*
822                                          * Save the source file details for
823                                          * debugging: 
824                                          */
825                                         _thread_fd_table[fd]->w_fname = fname;
826                                         _thread_fd_table[fd]->w_lineno = lineno;
827                                 }
828                         }
829
830                         if (_thread_fd_table[fd]->w_owner == curthread)
831                                 /* Increment the write lock count: */
832                                 _thread_fd_table[fd]->w_lockcount++;
833                 }
834
835                 /* Unlock the file descriptor table entry: */
836                 _SPINUNLOCK(&_thread_fd_table[fd]->lock);
837
838                 if (curthread->interrupted != 0) {
839                         ret = -1;
840                         errno = EINTR;
841                         if (curthread->continuation != NULL)
842                                 curthread->continuation((void *)curthread);
843                 }
844         }
845
846         /* Return the completion status: */
847         return (ret);
848 }
849
850 void
851 _thread_fd_unlock_owned(pthread_t pthread)
852 {
853         int fd;
854
855         for (fd = 0; fd < _thread_dtablesize; fd++) {
856                 if ((_thread_fd_table[fd] != NULL) &&
857                     ((_thread_fd_table[fd]->r_owner == pthread) ||
858                     (_thread_fd_table[fd]->w_owner == pthread))) {
859                         /*
860                          * Defer signals to protect the scheduling queues
861                          * from access by the signal handler:
862                          */
863                         _thread_kern_sig_defer();
864
865                         /*
866                          * Lock the file descriptor table entry to prevent
867                          * other threads for clashing with the current
868                          * thread's accesses:
869                          */
870                         _SPINLOCK(&_thread_fd_table[fd]->lock);
871
872                         /* Check if the thread owns the read lock: */
873                         if (_thread_fd_table[fd]->r_owner == pthread) {
874                                 /* Clear the read lock count: */
875                                 _thread_fd_table[fd]->r_lockcount = 0;
876
877                                 /*
878                                  * Get the next thread in the queue for a
879                                  * read lock on this file descriptor: 
880                                  */
881                                 if ((_thread_fd_table[fd]->r_owner = fd_next_reader(fd)) != NULL) {
882                                         /* Remove this thread from the queue: */
883                                         FDQ_REMOVE(&_thread_fd_table[fd]->r_queue,
884                                             _thread_fd_table[fd]->r_owner);
885
886                                         /*
887                                          * Set the state of the new owner of
888                                          * the thread to running: 
889                                          */
890                                         PTHREAD_NEW_STATE(_thread_fd_table[fd]->r_owner,PS_RUNNING);
891                                 }
892                         }
893
894                         /* Check if the thread owns the write lock: */
895                         if (_thread_fd_table[fd]->w_owner == pthread) {
896                                 /* Clear the write lock count: */
897                                 _thread_fd_table[fd]->w_lockcount = 0;
898
899                                 /*
900                                  * Get the next thread in the queue for a
901                                  * write lock on this file descriptor: 
902                                  */
903                                 if ((_thread_fd_table[fd]->w_owner = fd_next_writer(fd)) != NULL) {
904                                         /* Remove this thread from the queue: */
905                                         FDQ_REMOVE(&_thread_fd_table[fd]->w_queue,
906                                             _thread_fd_table[fd]->w_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]->w_owner,PS_RUNNING);
913
914                                 }
915                         }
916
917                         /* Unlock the file descriptor table entry: */
918                         _SPINUNLOCK(&_thread_fd_table[fd]->lock);
919
920                         /*
921                          * Undefer and handle pending signals, yielding if
922                          * necessary.
923                          */
924                         _thread_kern_sig_undefer();
925                 }
926         }
927 }
928
929 void
930 _fd_lock_backout(pthread_t pthread)
931 {
932         int     fd;
933
934         /*
935          * Defer signals to protect the scheduling queues
936          * from access by the signal handler:
937          */
938         _thread_kern_sig_defer();
939
940         switch (pthread->state) {
941
942         case PS_FDLR_WAIT:
943                 fd = pthread->data.fd.fd;
944
945                 /*
946                  * Lock the file descriptor table entry to prevent
947                  * other threads for clashing with the current
948                  * thread's accesses:
949                  */
950                 _SPINLOCK(&_thread_fd_table[fd]->lock);
951
952                 /* Remove the thread from the waiting queue: */
953                 FDQ_REMOVE(&_thread_fd_table[fd]->r_queue, pthread);
954                 break;
955
956         case PS_FDLW_WAIT:
957                 fd = pthread->data.fd.fd;
958
959                 /*
960                  * Lock the file descriptor table entry to prevent
961                  * other threads from clashing with the current
962                  * thread's accesses:
963                  */
964                 _SPINLOCK(&_thread_fd_table[fd]->lock);
965
966                 /* Remove the thread from the waiting queue: */
967                 FDQ_REMOVE(&_thread_fd_table[fd]->w_queue, pthread);
968                 break;
969
970         default:
971                 break;
972         }
973
974         /*
975          * Undefer and handle pending signals, yielding if
976          * necessary.
977          */
978         _thread_kern_sig_undefer();
979 }
980
981 static inline pthread_t
982 fd_next_reader(int fd)
983 {
984         pthread_t pthread;
985
986         while (((pthread = TAILQ_FIRST(&_thread_fd_table[fd]->r_queue)) != NULL) &&
987             (pthread->interrupted != 0)) {
988                 /*
989                  * This thread has either been interrupted by a signal or
990                  * it has been canceled.  Remove it from the queue.
991                  */
992                 FDQ_REMOVE(&_thread_fd_table[fd]->r_queue, pthread);
993         }
994
995         return (pthread);
996 }
997
998 static inline pthread_t
999 fd_next_writer(int fd)
1000 {
1001         pthread_t pthread;
1002
1003         while (((pthread = TAILQ_FIRST(&_thread_fd_table[fd]->w_queue)) != NULL) &&
1004             (pthread->interrupted != 0)) {
1005                 /*
1006                  * This thread has either been interrupted by a signal or
1007                  * it has been canceled.  Remove it from the queue.
1008                  */
1009                 FDQ_REMOVE(&_thread_fd_table[fd]->w_queue, pthread);
1010         }
1011
1012         return (pthread);
1013 }
1014
1015 #else
1016
1017 void
1018 _thread_fd_unlock(int fd, int lock_type)
1019 {
1020 }
1021
1022 int
1023 _thread_fd_lock(int fd, int lock_type, struct timespec * timeout)
1024 {
1025         /*
1026          * Insure that the file descriptor table is initialized for this
1027          * entry: 
1028          */
1029         return (_thread_fd_table_init(fd));
1030 }
1031
1032 void
1033 _thread_fd_unlock_debug(int fd, int lock_type, char *fname, int lineno)
1034 {
1035 }
1036
1037 int
1038 _thread_fd_lock_debug(int fd, int lock_type, struct timespec * timeout,
1039                 char *fname, int lineno)
1040 {
1041         /*
1042          * Insure that the file descriptor table is initialized for this
1043          * entry: 
1044          */
1045         return (_thread_fd_table_init(fd));
1046 }
1047
1048 void
1049 _thread_fd_unlock_owned(pthread_t pthread)
1050 {
1051 }
1052
1053 void
1054 _fd_lock_backout(pthread_t pthread)
1055 {
1056 }
1057
1058 #endif