Formerly ../hurd/hurd/threadvar.h.~4~
[kopensolaris-gnu/glibc.git] / hurd / hurd / fd.h
1 /* File descriptors.
2 Copyright (C) 1993, 1994 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB.  If
17 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
18 Cambridge, MA 02139, USA.  */
19
20 #ifndef _HURD_FD_H
21
22 #define _HURD_FD_H      1
23 #include <features.h>
24
25 #include <hurd/hurd_types.h>
26 #include <hurd/port.h>
27
28
29 /* Structure representing a file descriptor.  */
30
31 struct hurd_fd
32   {
33     struct hurd_port port;      /* io server port.  */
34     int flags;                  /* fcntl flags; locked by port.lock.  */
35
36     /* Normal port to the ctty.  When `port' is our ctty, this is a port to
37        the same io object but which never returns EBACKGROUND; when not,
38        this is nil.  */
39     struct hurd_port ctty;
40   };
41
42
43 /* Structure representing a file descriptor table.  */
44
45 struct hurd_dtable
46   {
47     int size;                   /* Number of elts in `d' array.  */
48
49     /* Uses of individual descriptors are not locked.  It is up to the user
50        to synchronize descriptor operations on a single descriptor.  */
51     struct hurd_fd **d;
52   };
53
54 /* Current file descriptor table.  */
55
56 extern struct hurd_dtable _hurd_dtable;
57
58 /* If not NULL, points to the chain of users of `_hurd_dtable'.
59    See <hurd/userlink.h>.  */
60
61 extern struct hurd_userlink *_hurd_dtable_users;
62
63 extern int _hurd_dtable_rlimit; /* RLIM_OFILES: number of file descriptors.  */
64
65 /* This locks _hurd_dtable, _hurd_dtable_users, and _hurd_dtable_rlimit.  */
66 extern struct mutex _hurd_dtable_lock;
67 \f
68 #include <lock-intern.h>
69
70 #ifndef _EXTERN_INLINE
71 #define _EXTERN_INLINE extern __inline
72 #endif
73
74 /* Get a descriptor table structure to use.
75    Pass this structure and ULINK to _hurd_dtable_free when done.  */
76
77 _EXTERN_INLINE struct hurd_dtable
78 _hurd_dtable_get (struct hurd_userlink *ulink)
79 {
80   struct hurd_dtable dtable;
81   __mutex_lock (&_hurd_dtable_lock);
82   _hurd_userlink_link (&_hurd_dtable_users, ulink);
83   dtable = _hurd_dtable;
84   __mutex_unlock (&_hurd_dtable_lock);
85   return dtable;
86 }
87
88
89 /* Function to deallocate a descriptor table's `struct hurd_fd' array.
90    This is expected to be either `free' or a null pointer.  */
91
92 extern void (*_hurd_dtable_deallocate) (void *);
93
94 /* Free a reference gotten with `DTABLE = _hurd_dtable_get (ULINK);' */
95
96 _EXTERN_INLINE void
97 _hurd_dtable_free (struct hurd_dtable dtable,
98                    struct hurd_userlink *ulink)
99 {
100   int dealloc;
101   __mutex_lock (&_hurd_dtable_lock);
102   dealloc = _hurd_userlink_unlink (ulink);
103   __mutex_unlock (&_hurd_dtable_lock);
104   if (dealloc && _hurd_dtable_deallocate)
105     (*_hurd_dtable_deallocate) (dtable.d);
106 }
107
108
109 /* Return the descriptor cell for FD in DTABLE, locked.
110    If FD is invalid or unused, return NULL.  */
111
112 _EXTERN_INLINE struct hurd_fd *
113 _hurd_dtable_fd (int fd, struct hurd_dtable dtable)
114 {
115   if (fd < 0 || fd >= dtable.size)
116     return NULL;
117   else
118     {
119       struct hurd_fd *cell = dtable.d[fd];
120       if (cell == NULL)
121         /* No descriptor allocated at this index.  */
122         return NULL;
123       __spin_lock (&cell->port.lock);
124       if (cell->port.port == MACH_PORT_NULL)
125         {
126           /* The descriptor at this index has no port in it.
127              This happens if it existed before but was closed.  */
128           __spin_unlock (&cell->port.lock);
129           return NULL;
130         }
131       return cell;
132     }
133 }
134
135 struct hurd_fd_user
136   {
137     struct hurd_dtable dtable;
138     struct hurd_fd *d;
139   };
140
141 /* Returns the descriptor cell for FD, locked.  The passed ULINK structure
142    and returned structure hold onto the descriptor table to it doesn't move
143    while you might be using a pointer into it.  */
144
145 _EXTERN_INLINE struct hurd_fd_user
146 _hurd_fd_get (int fd, struct hurd_userlink *ulink)
147 {
148   struct hurd_fd_user d;
149   d.dtable = _hurd_dtable_get (ulink);
150   d.d = _hurd_dtable_fd (fd, d.dtable);
151   if (d.d == NULL)
152     _hurd_dtable_free (d.dtable, ulink);
153   return d;
154 }
155
156 /* Free a reference gotten with `D = _hurd_fd_get (FD, ULINK);'.
157    The descriptor cell D.d should be unlocked before calling this function.  */
158
159 _EXTERN_INLINE void
160 _hurd_fd_free (struct hurd_fd_user d, struct hurd_userlink *ulink)
161 {
162   _hurd_dtable_free (d.dtable, ulink);
163 }
164
165
166 /* Evaluate EXPR with the variable `descriptor' bound to a pointer to the
167    locked file descriptor structure for FD.  */
168
169 #define HURD_FD_USE(fd, expr)                                                 \
170   ({ struct hurd_userlink __dt_ulink;                                         \
171      error_t __result;                                                        \
172      struct hurd_fd_user __d = _hurd_fd_get (fd, &__dt_ulink);                \
173      if (__d.d == NULL)                                                       \
174        __result = EBADF;                                                      \
175      else                                                                     \
176        {                                                                      \
177          struct hurd_fd *const descriptor = __d.d;                            \
178          __result = (expr);                                                   \
179          _hurd_fd_free (__d, &__dt_ulink);                                    \
180        }                                                                      \
181      __result; })
182
183 /* Evaluate EXPR with the variable `port' bound to the port to FD,
184    and `ctty' bound to the ctty port.  */
185
186 #define HURD_DPORT_USE(fd, expr) \
187   HURD_FD_USE ((fd), HURD_FD_PORT_USE (descriptor, (expr)))
188
189 /* Likewise, but FD is a pointer to the locked file descriptor structure.  */
190
191 #define HURD_FD_PORT_USE(fd, expr)                                            \
192   ({ error_t __result;                                                        \
193      struct hurd_fd *const __d = (fd);                                        \
194      struct hurd_userlink __ulink, __ctty_ulink;                              \
195      io_t port = _hurd_port_locked_get (&__d->port, &__ulink);                \
196      io_t ctty = _hurd_port_locked_get (&__d->ctty, &__ctty_ulink);           \
197      __result = (expr);                                                       \
198      _hurd_port_free (&__d->port, &__ulink, port);                            \
199      if (ctty != MACH_PORT_NULL)                                              \
200        _hurd_port_free (&__d->ctty, &__ctty_ulink, ctty);                     \
201      __result; })
202 \f
203 #include <errno.h>
204 #include <hurd/signal.h>
205
206 /* Handle an error from an RPC on a file descriptor's port.  You should
207    always use this function to handle errors from RPCs made on file
208    descriptor ports.  Some errors are translated into signals.  */   
209
210 _EXTERN_INLINE error_t
211 _hurd_fd_error (int fd, error_t err)
212 {
213   switch (err)
214     {
215     case MACH_SEND_INVALID_DEST: /* The server has disappeared!  */
216       _hurd_raise_signal (NULL, SIGLOST, fd);
217       break;
218     case EPIPE:
219       _hurd_raise_signal (NULL, SIGPIPE, fd);
220       break;
221     default:
222       /* Having a default case avoids -Wenum-switch warnings.  */
223       break;
224     }
225   return err;
226 }
227
228 /* Handle error code ERR from an RPC on file descriptor FD's port.
229    Set `errno' to the appropriate error code, and always return -1.  */
230
231 _EXTERN_INLINE int
232 __hurd_dfail (int fd, error_t err)
233 {
234   errno = _hurd_fd_error (fd, err);
235   return -1;
236 }
237 \f
238 /* Set up *FD to have PORT its server port, doing appropriate ctty magic.
239    Does no locking or unlocking.  */
240
241 extern void _hurd_port2fd (struct hurd_fd *fd, io_t port, int flags);
242
243 /* Allocate a new file descriptor and install PORT in it (doing any
244    appropriate ctty magic); consumes a user reference on PORT.  FLAGS are
245    as for `open'; only O_IGNORE_CTTY is meaningful, but all are saved.
246
247    If the descriptor table is full, set errno, and return -1.
248    If DEALLOC is nonzero, deallocate PORT first.  */
249
250 extern int _hurd_intern_fd (io_t port, int flags, int dealloc);
251
252 /* Allocate a new file descriptor in the table and return it, locked.  The
253    new descriptor number will be no less than FIRST_FD.  If the table is
254    full, set errno to EMFILE and return NULL.  If FIRST_FD is negative or
255    bigger than the size of the table, set errno to EINVAL and return NULL.  */
256
257 extern struct hurd_fd *_hurd_alloc_fd (int *fd_ptr, int first_fd);
258
259 /* Allocate a new file descriptor structure and initialize its port cells
260    with PORT and CTTY.  (This does not affect the descriptor table.)  */
261
262 extern struct hurd_fd *_hurd_new_fd (io_t port, io_t ctty);
263
264 /* Read and write data from a file descriptor; just like `read' and `write'.
265    If successful, stores the amount actually read or written in *NBYTES.  */
266
267 extern error_t _hurd_fd_read (struct hurd_fd *fd, void *buf, size_t *nbytes);
268 extern error_t _hurd_fd_write (struct hurd_fd *fd,
269                                const void *buf, size_t *nbytes);
270
271 \f
272 /* User-registered handlers for specific `ioctl' requests.  */
273
274 #define __need___va_list
275 #include <stdarg.h>
276
277 /* Structure that records an ioctl handler.  */
278
279 struct ioctl_handler
280   {
281     int first_request, last_request; /* Range of handled request values.  */
282
283     int (*handler) (int fd, int request, __gnuc_va_list);
284
285     struct ioctl_handler *next; /* Next handler.  */
286   };
287
288
289 /* Register HANDLER to handle ioctls with REQUEST values between
290    FIRST_REQUEST and LAST_REQUEST inclusive.  Returns zero if successful.
291    Return nonzero and sets `errno' for an error.  */
292
293 extern int hurd_register_ioctl_handler (int first_request, int last_request,
294                                         int (*handler) (int fd, int request,
295                                                         __gnuc_va_list));
296
297
298 /* Define a library-internal handler for ioctl commands
299    between FIRST and LAST inclusive.  */
300
301 #define _HURD_HANDLE_IOCTLS(handler, first, last)                             \
302   static const struct ioctl_handler handler##_ioctl_handler =                 \
303     { first, last, handler, NULL };                                           \
304   text_set_element (_hurd_ioctl_handler_lists, ##handler##_ioctl_handler)
305
306 /* Define a library-internal handler for a single ioctl command.  */
307
308 #define _HURD_HANDLE_IOCTL(handler, ioctl) \
309   _HURD_HANDLE_IOCTLS (handler, (ioctl), (ioctl))
310
311
312 #endif  /* hurd/fd.h */