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