10fd5630896fc88a6aa375b0a2c3260fbd212ec2
[platform/upstream/glibc.git] / hurd / hurd / fd.h
1 /* File descriptors.
2    Copyright (C) 1993, 1994, 1995, 1996, 1997 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 not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, 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 /* Current file descriptor table.  */
44
45 extern int _hurd_dtablesize;
46 extern struct hurd_fd **_hurd_dtable;
47 extern struct mutex _hurd_dtable_lock; /* Locks those two variables.  */
48 \f
49 #include <hurd/signal.h>
50 #include <lock-intern.h>
51
52 #ifndef _EXTERN_INLINE
53 #define _EXTERN_INLINE extern __inline
54 #endif
55
56 /* Returns the descriptor cell for FD.  If FD is invalid or unused, return
57    NULL.  The cell is unlocked; when ready to use it, lock it and check for
58    it being unused.  */
59
60 _EXTERN_INLINE struct hurd_fd *
61 _hurd_fd_get (int fd)
62 {
63   struct hurd_fd *descriptor;
64
65   __mutex_lock (&_hurd_dtable_lock);
66   if (fd < 0 || fd >= _hurd_dtablesize)
67     descriptor = NULL;
68   else
69     {
70       struct hurd_fd *cell = _hurd_dtable[fd];
71       if (cell == NULL)
72         /* No descriptor allocated at this index.  */
73         descriptor = NULL;
74       else
75         {
76           __spin_lock (&cell->port.lock);
77           if (cell->port.port == MACH_PORT_NULL)
78             /* The descriptor at this index has no port in it.
79                This happens if it existed before but was closed.  */
80             descriptor = NULL;
81           else
82             descriptor = cell;
83           __spin_unlock (&cell->port.lock);
84         }
85     }
86   __mutex_unlock (&_hurd_dtable_lock);
87
88   return descriptor;
89 }
90
91
92 /* Evaluate EXPR with the variable `descriptor' bound to a pointer to the
93    file descriptor structure for FD.   */
94
95 #define HURD_FD_USE(fd, expr)                                                 \
96   ({ struct hurd_fd *descriptor = _hurd_fd_get (fd);                          \
97      descriptor == NULL ? EBADF : (expr); })
98
99 /* Evaluate EXPR with the variable `port' bound to the port to FD, and
100    `ctty' bound to the ctty port.  */
101
102 #define HURD_DPORT_USE(fd, expr) \
103   HURD_FD_USE ((fd), HURD_FD_PORT_USE (descriptor, (expr)))
104
105 /* Likewise, but FD is a pointer to the file descriptor structure.  */
106
107 #define HURD_FD_PORT_USE(fd, expr)                                            \
108   ({ error_t __result;                                                        \
109      struct hurd_fd *const __d = (fd);                                        \
110      struct hurd_userlink __ulink, __ctty_ulink;                              \
111      io_t port, ctty;                                                         \
112      void *crit = _hurd_critical_section_lock ();                             \
113      __spin_lock (&__d->port.lock);                                           \
114      if (__d->port.port == MACH_PORT_NULL)                                    \
115        {                                                                      \
116          __spin_unlock (&__d->port.lock);                                     \
117          _hurd_critical_section_unlock (crit);                                \
118          __result = EBADF;                                                    \
119        }                                                                      \
120      else                                                                     \
121        {                                                                      \
122          ctty = _hurd_port_get (&__d->ctty, &__ctty_ulink);                   \
123          port = _hurd_port_locked_get (&__d->port, &__ulink);                 \
124          _hurd_critical_section_unlock (crit);                                \
125          __result = (expr);                                                   \
126          _hurd_port_free (&__d->port, &__ulink, port);                        \
127          if (ctty != MACH_PORT_NULL)                                          \
128            _hurd_port_free (&__d->ctty, &__ctty_ulink, ctty);                 \
129        }                                                                      \
130      __result; })
131 \f
132 #include <errno.h>
133
134 /* Check if ERR should generate a signal.
135    Returns the signal to take, or zero if none.  */
136
137 _EXTERN_INLINE error_t
138 _hurd_fd_error_signal (error_t err)
139 {
140   switch (err)
141     {
142     case EMACH_SEND_INVALID_DEST:
143     case EMIG_SERVER_DIED:
144       /* The server has disappeared!  */
145       return SIGLOST;
146     case EPIPE:
147       return SIGPIPE;
148     default:
149       /* Having a default case avoids -Wenum-switch warnings.  */
150       return 0;
151     }
152 }
153
154 /* Handle an error from an RPC on a file descriptor's port.  You should
155    always use this function to handle errors from RPCs made on file
156    descriptor ports.  Some errors are translated into signals.  */
157
158 _EXTERN_INLINE error_t
159 _hurd_fd_error (int fd, error_t err)
160 {
161   int signo = _hurd_fd_error_signal (err);
162   if (signo)
163     {
164       const struct hurd_signal_detail detail
165         = { code: fd, error: err, exc: 0 };
166       _hurd_raise_signal (NULL, signo, &detail);
167     }
168   return err;
169 }
170
171 /* Handle error code ERR from an RPC on file descriptor FD's port.
172    Set `errno' to the appropriate error code, and always return -1.  */
173
174 _EXTERN_INLINE int
175 __hurd_dfail (int fd, error_t err)
176 {
177   errno = _hurd_fd_error (fd, err);
178   return -1;
179 }
180 \f
181 /* Set up *FD to have PORT its server port, doing appropriate ctty magic.
182    Does no locking or unlocking.  */
183
184 extern void _hurd_port2fd (struct hurd_fd *fd, io_t port, int flags);
185
186 /* Allocate a new file descriptor and install PORT in it (doing any
187    appropriate ctty magic); consumes a user reference on PORT.  FLAGS are
188    as for `open'; only O_IGNORE_CTTY is meaningful, but all are saved.
189
190    If the descriptor table is full, set errno, and return -1.
191    If DEALLOC is nonzero, deallocate PORT first.  */
192
193 extern int _hurd_intern_fd (io_t port, int flags, int dealloc);
194
195 /* Allocate a new file descriptor in the table and return it, locked.  The
196    new descriptor number will be no less than FIRST_FD.  If the table is
197    full, set errno to EMFILE and return NULL.  If FIRST_FD is negative or
198    bigger than the size of the table, set errno to EINVAL and return NULL.  */
199
200 extern struct hurd_fd *_hurd_alloc_fd (int *fd_ptr, int first_fd);
201
202 /* Allocate a new file descriptor structure and initialize its port cells
203    with PORT and CTTY.  (This does not affect the descriptor table.)  */
204
205 extern struct hurd_fd *_hurd_new_fd (io_t port, io_t ctty);
206
207 /* Close a file descriptor, making it available for future reallocation.  */
208
209 extern error_t _hurd_fd_close (struct hurd_fd *fd);
210
211 /* Read and write data from a file descriptor; just like `read' and `write'.
212    If successful, stores the amount actually read or written in *NBYTES.  */
213
214 extern error_t _hurd_fd_read (struct hurd_fd *fd, void *buf, size_t *nbytes);
215 extern error_t _hurd_fd_write (struct hurd_fd *fd,
216                                const void *buf, size_t *nbytes);
217
218
219 /* Call *RPC on PORT and/or CTTY; if a call on CTTY returns EBACKGROUND,
220    generate SIGTTIN/SIGTTOU or EIO as appropriate.  */
221
222 extern error_t _hurd_ctty_input (io_t port, io_t ctty, error_t (*rpc) (io_t));
223 extern error_t _hurd_ctty_output (io_t port, io_t ctty, error_t (*rpc) (io_t));
224
225
226 #endif  /* hurd/fd.h */