369fc84f4a8a285f85b4fbc5546202a3640a2210
[kopensolaris-gnu/glibc.git] / hurd / hurd.h
1 /* Copyright (C) 1993 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB.  If
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, USA.  */
18
19 #ifndef _HURD_H
20
21 #define _HURD_H 1
22
23 #define _GNU_SOURCE
24 #include <features.h>
25
26 #include <mach.h>
27 #include <hurd/hurd_types.h>
28 #include <hurd/process.h>
29 #include <hurd/fs.h>
30 #include <hurd/io.h>
31 #include <errno.h>
32
33 #define __hurd_fail(err)        (errno = (err), -1)
34 \f
35 /* Lightweight user references for ports.  */
36
37 /* Structure describing a cell containing a port.
38    With the lock held, a user extracts PORT, and sets USER_DEALLOC to point
39    to a word in his local storage.  PORT can then safely be used.  When
40    PORT is no longer needed, with the lock held, the user examines
41    USER_DEALLOC.  If it is the same address that user stored there, he
42    extracts *USER_DEALLOC, clears USER_DEALLOC to NULL, and releases the
43    lock.  If *USER_DEALLOC is set, the user deallocates the port he used.  */
44 struct _hurd_port
45   {
46     spin_lock_t lock;           /* Locks rest.  */
47     mach_port_t port;           /* Port. */
48     int *user_dealloc;          /* If not NULL, points to user's flag word.  */
49   };
50
51 /* Evaluate EXPR with the variable `port' bound to the port in PORTCELL.  */
52 #define _HURD_PORT_USE(portcell, expr)                                        \
53   ({ struct _hurd_port *const __p = &(portcell);                              \
54      int __dealloc;                                                           \
55      const mach_port_t port = _hurd_port_get (__p, &__dealloc);               \
56      __typeof(expr) __result = (expr);                                        \
57      _hurd_port_free (__p, &__dealloc, port);                                 \
58      __result; })
59
60 /* Initialize *PORT to INIT.  */
61 static inline void
62 _hurd_port_init (struct _hurd_port *port, mach_port_t init)
63 {
64   __spin_lock_init (&port->lock);
65   port->port = init;
66   port->user_dealloc = NULL;
67 }
68
69 /* Get a reference to *PORT, which is locked.
70    Pass return value and MYFLAG to _hurd_port_free when done.  */
71 static inline mach_port_t
72 _hurd_port_locked_get (struct _hurd_port *port, int *myflag)
73 {
74   mach_port_t result;
75   result = port->port;
76   if (result != MACH_PORT_NULL)
77     {
78       port->user_dealloc = myflag;
79       *myflag = 0;
80     }
81   __spin_unlock (&port->lock);
82   return result;
83 }
84
85 /* Same, but locks PORT first.  */
86 static inline mach_port_t
87 _hurd_port_get (struct _hurd_port *port, int *myflag)
88 {
89   __spin_lock (&port->lock);
90   return _hurd_port_locked_get (port, myflag);
91 }
92
93 /* Free a reference gotten with
94    `USED_PORT = _hurd_port_get (PORT, MYFLAG);' */
95 static inline void
96 _hurd_port_free (struct _hurd_port *port,
97                  int *myflag, mach_port_t used_port)
98 {
99   __spin_lock (&port->lock);
100   if (port->user_dealloc == myflag)
101     port->user_dealloc = NULL;
102   __spin_unlock (&port->lock);
103   if (*myflag)
104     __mach_port_deallocate (__mach_task_self (), used_port);
105 }
106
107 /* Set *PORT's port to NEWPORT.  PORT is locked.  */
108 static inline void
109 _hurd_port_locked_set (struct _hurd_port *port, mach_port_t newport)
110 {
111   mach_port_t old;
112   if (port->user_dealloc == NULL)
113     old = port->port;
114   else
115     {
116       old = MACH_PORT_NULL;
117       *port->user_dealloc = 1;
118     }
119   port->port = newport;
120   __spin_unlock (&port->lock);
121   if (old != MACH_PORT_NULL)
122     __mach_port_deallocate (__mach_task_self (), old);
123 }
124
125 /* Same, but locks PORT first.  */
126 static inline void
127 _hurd_port_set (struct _hurd_port *port, mach_port_t newport)
128 {
129   __spin_lock (&port->lock);
130   return _hurd_port_locked_set (port, newport);
131 }
132 \f
133 /* Basic ports and info, initialized by startup.  */
134 extern struct _hurd_port *_hurd_ports;
135 extern unsigned int _hurd_nports;
136 extern volatile mode_t _hurd_umask;
137
138 extern vm_address_t _hurd_stack_low, _hurd_stack_high; /* Not locked.  */
139
140 extern thread_t _hurd_msgport_thread;
141 extern mach_port_t _hurd_msgport; /* Locked by _hurd_siglock.  */
142
143 /* Not locked.  If we are using a real dtable,
144    these are turned into that and then cleared at startup.
145    If not, these are never changed after startup.  */
146 extern mach_port_t *_hurd_init_dtable;
147 extern size_t _hurd_init_dtablesize;
148 \f
149 /* File descriptor table.  */
150 struct _hurd_fd
151   {
152     struct _hurd_port port;
153     int flags;                  /* fcntl flags; locked by port.lock.  */
154
155     /* Normal port to the ctty.  Also locked by port.lock.
156        (The ctty.lock is only ever used when the port.lock is held.)  */
157     struct _hurd_port ctty;
158   };
159
160 /* Set up *FD to have PORT its server port, doing appropriate ctty magic.
161    Does no locking or unlocking.  */
162 extern void _hurd_port2fd (struct _hurd_fd *fd, io_t port, int flags);
163
164 /* Allocate a new file descriptor and install PORT in it (including any
165    appropriate ctty magic). FLAGS are as for `open'; only O_NOCTTY is
166    meaningful, but all are saved.
167
168    If the descriptor table is full, set errno, and return -1.
169    If DEALLOC is nonzero, deallocate PORT first.  */
170 extern int _hurd_intern_fd (io_t port, int flags, int dealloc);
171
172 /* Allocate a new file descriptor and return it, locked.
173    The new descriptor will not be less than FIRST_FD.  */
174 extern struct _hurd_fd *_hurd_alloc_fd (int *fd_ptr, int first_fd);
175
176
177 struct _hurd_dtable
178   {
179     int size;                   /* Number of elts in `d' array.  */
180
181     /* Uses of individual descriptors are not locked.  It is up to the user
182        to synchronize descriptor operations on a single descriptor.  */
183
184     struct _hurd_fd *d;
185   };
186 extern struct mutex _hurd_dtable_lock; /* Locks next two.  */
187 extern struct _hurd_dtable _hurd_dtable;
188 extern int _hurd_dtable_rlimit;
189
190 /* If not NULL, pointed-to word is set when _hurd_dtable.d changes.
191    User who set `user_dealloc' should free the _hurd_dtable.d value
192    he used if his word is set when he is finished.
193    If NULL, the old value of _hurd_dtable.d is freed by the setter.  */
194 int *_hurd_dtable_user_dealloc;
195
196 static inline struct _hurd_dtable
197 _hurd_dtable_use (int *dealloc)
198 {
199   struct _hurd_dtable dtable;
200   __mutex_lock (&_hurd_dtable_lock);
201   _hurd_dtable_user_dealloc = dealloc;
202   dtable = _hurd_dtable;
203   __mutex_unlock (&_hurd_dtable_lock);
204   return dtable;
205 }
206
207 struct _hurd_dtable_resizes
208   {
209     size_t n;
210     void (*free) (void *);
211     void *terminator;
212   };
213 extern const struct _hurd_dtable_resizes _hurd_dtable_resizes;
214
215 static inline void
216 _hurd_dtable_done (struct _hurd_dtable dtable, int *dealloc)
217 {
218   __mutex_lock (&_hurd_dtable_lock);
219   if (_hurd_dtable_user_dealloc == dealloc)
220     _hurd_dtable_user_dealloc = NULL;
221   __mutex_unlock (&_hurd_dtable_lock);
222   if (*dealloc)
223     /* _hurd_dtable_resizes is a symbol set.
224        setdtablesize.c gives it one element: free.
225        If setdtablesize is not linked in, *DEALLOC
226        will never get set, so we will never get here.
227        This hair avoids linking in free if we don't need it.  */
228     (*_hurd_dtable_resizes.free) (dtable);
229 }
230
231 /* Return the descriptor cell for FD in DTABLE, locked.  */
232 static inline struct _hurd_fd *
233 _hurd_dtable_fd (int fd, struct _hurd_dtable dtable)
234 {
235   if (fd < 0 || fd >= dtable.size)
236     return NULL;
237   else
238     {
239       struct _hurd_fd *cell = &dtable.d[fd];
240       __spin_lock (&cell->port.lock);
241       if (cell->port.port == MACH_PORT_NULL)
242         {
243           __spin_unlock (&cell->port.lock);
244           return NULL;
245         }
246       return cell;
247     }
248 }
249
250 struct _hurd_fd_user
251   {
252     struct _hurd_dtable dtable;
253     struct _hurd_fd *d;
254   };
255
256 /* Returns the descriptor cell for FD, locked.  */
257 static inline struct _hurd_fd_user
258 _hurd_fd (int fd, int *dealloc)
259 {
260   struct _hurd_fd_user d;
261   d.dtable = _hurd_dtable_use (dealloc);
262   d.d = _hurd_dtable_fd (fd, dtable);
263   if (d.d == NULL)
264     _hurd_dtable_done (d.dtable, dealloc);
265   return d;
266 }
267
268 static inline void
269 _hurd_fd_done (struct _hurd_fd_user d, int *dealloc)
270 {
271   _hurd_dtable_done (d.dtable, dealloc);
272 }
273
274 /* Evaluate EXPR with the variable `port' bound to the port to FD,
275    and `ctty' bound to the ctty port.  */
276    
277 #define _HURD_DPORT_USE(fd, expr)                                             \
278   ({ int __dealloc_dt;                                                        \
279      struct _hurd_fd_user __d = _hurd_fd (fd, &__dealloc_dt);                 \
280      if (__d.cell == NULL)                                                    \
281        EBADF;                                                                 \
282      else                                                                     \
283        {                                                                      \
284          int __dealloc = 0, __dealloc_ctty = 0;                               \
285          io_t port = _hurd_port_locked_get (&__d.d->port, &__dealloc);        \
286          io_t ctty = _hurd_port_locked_get (&__d.d->ctty, &__dealloc_ctty);   \
287          __typeof (expr) __result;                                            \
288          __result = (expr);                                                   \
289          _hurd_port_free (&__d.d->port, &__dealloc, port);                    \
290          if (ctty != MACH_PORT_NULL)                                          \
291            _hurd_port_free (&__d.d->ctty, &__dealloc_ctty, port);             \
292          _hurd_fd_done (__d, &__dealloc_dt);                                  \
293          __result;                                                            \
294        }                                                                      \
295    })                                                                         \
296
297 static inline int
298 _hurd_dfail (int fd, error_t err)
299 {
300   switch (err)
301     {
302     case MACH_SEND_INVALID_DEST: /* The server has disappeared!  */
303       _hurd_raise_signal (NULL, SIGLOST, fd);
304       break;
305     case EPIPE:
306       _hurd_raise_signal (NULL, SIGPIPE, fd);
307       break;
308     default:
309       return __hurd_fail (err);
310     }
311 }
312 \f
313 /* Return the socket server for sockaddr domain DOMAIN.  */
314 extern socket_t _hurd_socket_server (int domain);
315
316 /* Return a receive right which will not be sent to.  */
317 extern mach_port_t _hurd_dead_recv (void);
318
319
320 /* Current process IDs.  */
321 extern pid_t _hurd_pid, _hurd_ppid, _hurd_pgrp;
322 extern int _hurd_orphaned;
323 extern struct mutex _hurd_pid_lock; /* Locks above.  */
324
325
326 /* User and group IDs.  */
327 extern mutex_t _hurd_idlock;
328 extern int _hurd_id_valid;      /* If _hurd_uid and _hurd_gid are valid.  */
329 extern struct idlist *_hurd_uid, *_hurd_gid;
330 extern unsigned int _hurd_nuids, _hurd_ngids;
331 extern auth_t _hurd_rid_auth;   /* Cache used by access.  */
332
333
334 /* Unix `data break', for brk and sbrk.
335    If brk and sbrk are not used, this info will not be initialized or used.  */
336 extern vm_address_t _hurd_brk;  /* Data break.  */
337 extern vm_address_t _hurd_data_end; /* End of allocated space.  */
338 extern struct mutex _hurd_brk_lock; /* Locks brk and data_end.  */
339 extern int _hurd_set_data_limit (const struct rlimit *);
340
341 /* Set the data break; the brk lock must
342    be held, and is released on return.  */
343 extern int _hurd_set_brk (vm_address_t newbrk);
344
345 /* Resource limit on core file size.  Enforced by hurdsig.c.  */
346 extern int _hurd_core_limit;
347 \f
348 #ifdef notyet
349
350 #include <signal.h>
351
352 /* Per-thread signal state.  */
353 struct _hurd_sigstate
354   {
355     thread_t thread;
356     struct _hurd_sigstate *next; /* Linked-list of thread sigstates.  */
357
358     struct mutex lock;          /* Locks the rest of this structure.  */
359     sigset_t blocked;
360     sigset_t pending;
361     struct sigaction actions[NSIG];
362     struct sigaltstack sigaltstack;
363     int sigcodes[NSIG];         /* Codes for pending signals.  */
364
365     int suspended;              /* If nonzero, sig_post signals `arrived'.  */
366     struct condition arrived;
367
368 #if 0
369     int vforked;                /* Nonzero if this thread is a vfork child.  */
370     struct
371       {
372         process_t proc;
373         file_t ccdir, cwdir, crdir, auth;
374         mode_t umask;
375         int ctty_fstype;
376         fsid_t ctty_fsid;
377         ino_t ctty_fileid;
378         struct _hurd_dtable *dtable;
379         jmp_buf continuation;
380       } *vfork_saved;
381 #endif
382
383     /* Not locked.  Used only by this thread,
384        or by signal thread with this thread suspended.  */
385     volatile mach_port_t intr_port; /* Port interruptible RPC was sent on.  */
386     volatile int intr_restart;  /* If nonzero, restart interrupted RPC.  */
387   };
388 /* Linked list of states of all threads
389    whose state has been inquired about.  */
390 extern struct _hurd_sigstate *_hurd_sigstates;
391 extern struct mutex _hurd_siglock; /* Locks _hurd_sigstates.  */
392 /* Get the sigstate of a given thread, taking its lock.  */
393 extern struct _hurd_sigstate *_hurd_thread_sigstate (thread_t);
394
395 /* Thread to receive process-global signals.  */
396 extern thread_t _hurd_sigthread;
397
398 /* Called by the machine-dependent exception handler.  */
399 extern void _hurd_exc_post_signal (thread_t, int sig, int code);
400
401 /* SS->lock is held on entry, and released before return.  */
402 extern void _hurd_internal_post_signal (struct _hurd_sigstate *ss,
403                                         int signo, int sigcode,
404                                         sigset_t *restore_blocked);
405
406 /* Function run by the signal thread to receive from the signal port.  */
407 extern void _hurd_msgport_receive (void);
408
409
410 /* Perform interruptible RPC CALL on PORT.
411    The args in CALL should be constant or local variable refs.
412    They may be evaluated many times, and must not change.
413    PORT must not be deallocated before this RPC is finished.  */
414 #define HURD_EINTR_RPC(port, call) \
415   ({
416     error_t __err;
417     struct _hurd_sigstate *__ss
418       = _hurd_thread_sigstate (__mach_thread_self ());
419     __mutex_unlock (&__ss->lock); /* Lock not needed.  */
420     /* If we get a signal and should return EINTR, the signal thread will
421        clear this.  The RPC might return EINTR when some other thread gets
422        a signal, in which case we want to restart our call.  */
423     __ss->intr_restart = 1;
424     /* This one needs to be last.  A signal can arrive before here,
425        and if intr_port were set before intr_restart is
426        initialized, the signal thread would get confused.  */
427     __ss->intr_port = (port);
428     /* A signal may arrive here, after intr_port is set,
429        but before the mach_msg system call.  The signal handler might do an
430        interruptible RPC, and clobber intr_port; then it would not be set
431        properly when we actually did send the RPC, and a later signal
432        wouldn't interrupt that RPC.  So, _hurd_run_sighandler saves
433        intr_port in the sigcontext, and sigreturn restores it.  */
434   __do_call:
435     switch (__err = (call))
436       {
437       case EINTR:               /* RPC went out and was interrupted.  */
438       case MACH_SEND_INTERRUPTED: /* RPC didn't get out.  */
439         if (__ss->intr_restart)
440           /* Restart the interrupted call.  */
441           goto __do_call;
442         /* FALLTHROUGH */
443       case MACH_RCV_PORT_DIED:
444         /* Server didn't respond to interrupt_operation,
445            so the signal thread destroyed the reply port.  */
446         __err = EINTR;
447         break;
448       }
449     __ss->intr_port = MACH_PORT_NULL;
450     __err;
451   })
452
453 #endif /* notyet */
454 \f
455 /* Calls to get and set basic ports.  */
456 extern process_t getproc (void);
457 extern file_t getccdir (void), getcwdir (void), getcrdir (void);
458 extern auth_t getauth (void);
459 extern int setproc (process_t);
460 extern int setcwdir (file_t), setcrdir (file_t);
461
462 /* Does reauth with the proc server and fd io servers.  */
463 extern int __setauth (auth_t), setauth (auth_t);
464 #define setauth __setauth       /* XXX */
465
466
467 extern error_t __hurd_path_split (file_t crdir, file_t cwdir,
468                                   const char *file,
469                                   file_t *dir, const char **name);
470 extern error_t hurd_path_split (file_t crdir, file_t cwdir,
471                                 const char *file,
472                                 file_t *dir, const char **name);
473 #define hurd_path_split __hurd_path_split /* XXX */
474 extern error_t __hurd_path_lookup (file_t crdir, file_t cwdir,
475                                    const char *file,
476                                    int flags, mode_t mode,
477                                    file_t *file);
478 extern error_t hurd_path_lookup (file_t crdir, file_t cwdir,
479                                  const char *file,
480                                  int flags, mode_t mode,
481                                  file_t *file);
482 #define hurd_path_lookup __hurd_path_lookup /* XXX */
483
484 /* Returns a port to the directory, and sets *NAME to the file name.  */
485 extern file_t __path_split (const char *file, const char **name);
486 extern file_t path_split (const char *file, const char **name);
487 #define path_split      __path_split
488
489 /* Looks up FILE with the given FLAGS and MODE (as for dir_pathtrans).  */
490 extern file_t __path_lookup (const char *file, int flags, mode_t mode);
491 extern file_t path_lookup (const char *file, int flags, mode_t mode);
492 #define path_lookup __path_lookup /* XXX */
493
494 /* Open a file descriptor on a port.  */
495 extern int openport (io_t port, int flags);
496
497 /* Inform the proc server we have exitted with STATUS, and kill the
498    task thoroughly.  This function never returns, no matter what.  */
499 extern volatile void _hurd_exit (int status);
500
501
502 #endif  /* hurd.h */