Formerly ../hurd/hurd.h.~29~
[kopensolaris-gnu/glibc.git] / hurd / hurd.h
1 /* Copyright (C) 1992 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);                                       \
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_proc, _hurd_auth;
135 extern struct _hurd_port _hurd_ccdir, _hurd_cwdir, _hurd_crdir;
136 extern volatile mode_t _hurd_umask;
137
138 extern struct mutex _hurd_ctty_lock;
139 extern int _hurd_ctty_fstype;
140 extern fsid_t _hurd_ctty_fsid;
141 extern ino_t _hurd_ctty_fileid;
142
143 extern vm_address_t _hurd_stack_low, _hurd_stack_high; /* Not locked.  */
144
145 extern thread_t _hurd_msgport_thread;
146 extern mach_port_t _hurd_msgport; /* Locked by _hurd_siglock.  */
147
148 /* Not locked.  If we are using a real dtable,
149    these are turned into that and then cleared at startup.
150    If not, these are never changed after startup.  */
151 extern mach_port_t *_hurd_init_dtable;
152 extern size_t _hurd_init_dtablesize;
153 \f
154 /* File descriptor table.  */
155 struct _hurd_fd
156   {
157     struct _hurd_port port;
158     int flags;                  /* fcntl flags; locked by port.lock.  */
159
160     /* Normal port to the ctty.  Also locked by port.lock.
161        (The ctty.lock is only ever used when the port.lock is held.)  */
162     struct _hurd_port ctty;
163   };
164
165 struct _hurd_dtable
166   {
167     int size;                   /* Number of elts in `d' array.  */
168
169     /* Uses of individual descriptors are not locked.  It is up to the user
170        to synchronize descriptor operations on a single descriptor.  */
171
172     struct _hurd_fd *d;
173   };
174 extern struct mutex _hurd_dtable_lock; /* Locks next two.  */
175 extern struct _hurd_dtable _hurd_dtable;
176 extern int _hurd_dtable_rlimit;
177
178 /* If not NULL, pointed-to word is set when _hurd_dtable.d changes.
179    User who set `user_dealloc' should free the _hurd_dtable.d value
180    he used if his word is set when he is finished.
181    If NULL, the old value of _hurd_dtable.d is freed by the setter.  */
182 int *_hurd_dtable_user_dealloc;
183
184 static inline struct _hurd_dtable
185 _hurd_dtable_use (int *dealloc)
186 {
187   struct _hurd_dtable dtable;
188   __mutex_lock (&_hurd_dtable_lock);
189   _hurd_dtable_user_dealloc = dealloc;
190   dtable = _hurd_dtable;
191   __mutex_unlock (&_hurd_dtable_lock);
192   return dtable;
193 }
194
195 struct _hurd_dtable_resizes
196   {
197     size_t n;
198     void (*free) (void *);
199     void *terminator;
200   };
201 extern const struct _hurd_dtable_resizes _hurd_dtable_resizes;
202
203 static inline void
204 _hurd_dtable_done (struct _hurd_dtable dtable, int *dealloc)
205 {
206   __mutex_lock (&_hurd_dtable_lock);
207   if (_hurd_dtable_user_dealloc == dealloc)
208     _hurd_dtable_user_dealloc = NULL;
209   __mutex_unlock (&_hurd_dtable_lock);
210   if (*dealloc)
211     /* _hurd_dtable_resizes is a symbol set.
212        setdtablesize.c gives it one element: free.
213        If setdtablesize is not linked in, *DEALLOC
214        will never get set, so we will never get here.
215        This hair avoids linking in free if we don't need it.  */
216     (*_hurd_dtable_resizes.free) (dtable);
217 }
218
219
220 /* Allocate a new file descriptor and set it to PORT.
221    If the table is full, deallocate PORT, set errno, and return -1.  */
222 static inline int
223 _hurd_dalloc (io_t port, io_t ctty, int flags)
224 {
225   int i;
226   __mutex_lock (&hurd_dtable_lock);
227   for (i = 0; i < _hurd_dtable.size; ++i)
228     {
229       struct _hurd_fd *d = &_hurd_dtable.d[i];
230       __spin_lock (&d->port.lock);
231       if (d->port.port == MACH_PORT_NULL)
232         {
233           d->port.port = port;
234           d->port.user_dealloc = NULL;
235           d->ctty.port = ctty;
236           d->ctty.user_dealloc = NULL;
237           d->flags = flags;
238           __spin_unlock (&d->port.lock);
239           __mutex_unlock (&hurd_dtable_lock);
240           return i;
241         }
242       __spin_unlock (&d->port.lock);
243     }
244   __mutex_unlock (&hurd_dtable_lock);
245   __mach_port_deallocate (__mach_task_self (), port);
246   __mach_port_deallocate (__mach_task_self (), ctty);
247   errno = EMFILE;
248   return -1;
249 }
250
251 /* Returns the descriptor cell for FD in DTABLE, locked.  */
252 static inline struct _hurd_fd *
253 _hurd_dtable_fd (int fd, struct _hurd_dtable dtable)
254 {
255   if (fd < 0 || fd >= dtable.size)
256     return NULL;
257   else
258     {
259       struct _hurd_fd *cell = &dtable.d[fd];
260       __spin_lock (&cell->port.lock);
261       if (cell->port.port == MACH_PORT_NULL)
262         {
263           __spin_unlock (&cell->port.lock);
264           return NULL;
265         }
266       return cell;
267     }
268 }
269
270 struct _hurd_fd_user
271   {
272     struct _hurd_dtable dtable;
273     struct _hurd_fd *d;
274   };
275
276 /* Returns the descriptor cell for FD, locked.  */
277 static inline struct _hurd_fd_user
278 _hurd_fd (int fd, int *dealloc)
279 {
280   struct _hurd_fd_user d;
281   d.dtable = _hurd_dtable_use (dealloc);
282   d.d = _hurd_dtable_fd (fd, dtable);
283   if (d.d == NULL)
284     _hurd_dtable_done (d.dtable, dealloc);
285   return d;
286 }
287
288 static inline void
289 _hurd_fd_done (struct _hurd_fd_user d, int *dealloc)
290 {
291   _hurd_dtable_done (d->dtable, dealloc);n
292 }
293
294 /* Evaluate EXPR with the variable `port' bound to the port to FD,
295    and `ctty' bound to the ctty port.  */
296    
297 #define _HURD_DPORT_USE(fd, expr)                                             \
298   ({ int __dealloc_dt;                                                        \
299      struct _hurd_fd_user __d = _hurd_fd (fd, &__dealloc_dt);                 \
300      if (__cell.d == NULL)                                                    \
301        EBADF;                                                                 \
302      else                                                                     \
303        {                                                                      \
304          int __dealloc = 0, __dealloc_ctty = 0;                               \
305          io_t port = _hurd_port_locked_get (&__d.d->port, &__dealloc);        \
306          io_t ctty = _hurd_port_locked_get (&__d.d->ctty, &__dealloc_ctty);   \
307          __typeof (expr) __result;                                            \
308          __result = (expr);                                                   \
309          _hurd_port_free (&__d.d->port, port, &__dealloc);                    \
310          if (ctty != MACH_PORT_NULL)                                          \
311            _hurd_port_free (&__d.d->ctty, ctty, &__dealloc_ctty);             \
312          _hurd_fd_done (__d, &__dealloc_dt);                                  \
313          __result;                                                            \
314        }                                                                      \
315    })                                                                         \
316
317 static inline int
318 _hurd_dfail (int fd, error_t err)
319 {
320   int signo;
321   switch (err)
322     {
323     case MACH_SEND_INVALID_DEST: /* The server has disappeared!  */
324       _hurd_raise_signal (NULL, SIGLOST, fd);
325       break;
326     case EPIPE:
327       _hurd_raise_signal (NULL, SIGPIPE, fd);
328       break;
329     }
330   return __hurd_fail (err);
331 }
332 \f
333 /* Return the socket server for sockaddr domain DOMAIN.  */
334 extern socket_t _hurd_socket_server (int domain);
335
336 /* Return a receive right which will not be sent to.  */
337 extern mach_port_t _hurd_dead_recv (void);
338
339
340 /* Current process IDs.  */
341 extern pid_t _hurd_pid, _hurd_ppid, _hurd_pgrp;
342 extern int _hurd_orphaned;
343
344
345 /* User and group IDs.  */
346 extern mutex_t _hurd_idlock;
347 extern int _hurd_id_valid;      /* Nonzero if _hurd_id is valid.  */
348 extern idblock_t _hurd_id;
349 extern auth_t _hurd_rid_auth;   /* Cache used by access.  */
350
351
352 /* Unix `data break', for brk and sbrk.
353    If brk and sbrk are not used, this info will not be initialized or used.  */
354 extern vm_address_t _hurd_brk;  /* Data break.  */
355 extern vm_address_t _hurd_data_end; /* End of allocated space.  */
356 extern struct mutex _hurd_brk_lock; /* Locks brk and data_end.  */
357 extern int _hurd_set_data_limit (const struct rlimit *);
358
359 /* Set the data break; the brk lock must
360    be held, and is released on return.  */
361 extern int _hurd_set_brk (vm_address_t newbrk);
362
363 /* Resource limit on core file size.  Enforced by hurdsig.c.  */
364 extern int _hurd_core_limit;
365 \f
366 #include <signal.h>
367
368 /* Per-thread signal state.  */
369 struct _hurd_sigstate
370   {
371     thread_t thread;
372     struct _hurd_sigstate *next; /* Linked-list of thread sigstates.  */
373
374     struct mutex lock;          /* Locks the rest of this structure.  */
375     sigset_t blocked;
376     sigset_t pending;
377     struct sigaction actions[NSIG];
378     struct sigaltstack sigaltstack;
379     int sigcodes[NSIG];         /* Codes for pending signals.  */
380
381     int suspended;              /* If nonzero, sig_post signals `arrived'.  */
382     struct condition arrived;
383
384 #if 0
385     int vforked;                /* Nonzero if this thread is a vfork child.  */
386     struct
387       {
388         process_t proc;
389         file_t ccdir, cwdir, crdir, auth;
390         mode_t umask;
391         int ctty_fstype;
392         fsid_t ctty_fsid;
393         ino_t ctty_fileid;
394         struct _hurd_dtable *dtable;
395         jmp_buf continuation;
396       } *vfork_saved;
397 #endif
398
399     /* Not locked.  Used only by this thread,
400        or by signal thread with this thread suspended.  */
401     volatile mach_port_t intr_port; /* Port interruptible RPC was sent on.  */
402     volatile int intr_restart;  /* If nonzero, restart interrupted RPC.  */
403   };
404 /* Linked list of states of all threads
405    whose state has been inquired about.  */
406 extern struct _hurd_sigstate *_hurd_sigstates;
407 extern struct mutex _hurd_siglock; /* Locks _hurd_sigstates.  */
408 /* Get the sigstate of a given thread, taking its lock.  */
409 extern struct _hurd_sigstate *_hurd_thread_sigstate (thread_t);
410
411 /* Thread to receive process-global signals.  */
412 extern thread_t _hurd_sigthread;
413
414 /* Called by the machine-dependent exception handler.  */
415 extern void _hurd_exc_post_signal (thread_t, int sig, int code);
416
417 /* SS->lock is held on entry, and released before return.  */
418 extern void _hurd_internal_post_signal (struct _hurd_sigstate *ss,
419                                         int signo, int sigcode,
420                                         sigset_t *restore_blocked);
421
422 /* Function run by the signal thread to receive from the signal port.  */
423 extern void _hurd_msgport_receive (void);
424
425
426 /* Perform interruptible RPC CALL on PORT.
427    The args in CALL should be constant or local variable refs.
428    They may be evaluated many times, and must not change.
429    PORT must not be deallocated before this RPC is finished.  */
430 #define HURD_EINTR_RPC(port, call) \
431   ({
432     error_t __err;
433     struct _hurd_sigstate *__ss
434       = _hurd_thread_sigstate (__mach_thread_self ());
435     __mutex_unlock (&__ss->lock); /* Lock not needed.  */
436     /* If we get a signal and should return EINTR, the signal thread will
437        clear this.  The RPC might return EINTR when some other thread gets
438        a signal, in which case we want to restart our call.  */
439     __ss->intr_restart = 1;
440     /* This one needs to be last.  A signal can arrive before here,
441        and if intr_port were set before intr_restart is
442        initialized, the signal thread would get confused.  */
443     __ss->intr_port = (port);
444     /* A signal may arrive here, after intr_port is set,
445        but before the mach_msg system call.  The signal handler might do an
446        interruptible RPC, and clobber intr_port; then it would not be set
447        properly when we actually did send the RPC, and a later signal
448        wouldn't interrupt that RPC.  So, _hurd_run_sighandler saves
449        intr_port in the sigcontext, and sigreturn restores it.  */
450   __do_call:
451     switch (__err = (call))
452       {
453       case EINTR:               /* RPC went out and was interrupted.  */
454       case MACH_SEND_INTERRUPTED: /* RPC didn't get out.  */
455         if (__ss->intr_restart)
456           /* Restart the interrupted call.  */
457           goto __do_call;
458         /* FALLTHROUGH */
459       case MACH_RCV_PORT_DIED:
460         /* Server didn't respond to interrupt_operation,
461            so the signal thread destroyed the reply port.  */
462         __err = EINTR;
463         break;
464       }
465     __ss->intr_port = MACH_PORT_NULL;
466     __err;
467   })
468 \f
469 /* Calls to get and set basic ports.  */
470 extern process_t getproc (void);
471 extern file_t getccdir (void), getcwdir (void), getcrdir (void);
472 extern auth_t getauth (void);
473 extern int setproc (process_t);
474 extern int setccdir (file_t), setcwdir (file_t), setcrdir (file_t);
475
476 /* Does reauth with the proc server and fd io servers.  */
477 extern int __setauth (auth_t), setauth (auth_t);
478 #define setauth __setauth
479
480
481 extern error_t __hurd_path_split (file_t crdir, file_t cwdir,
482                                   const char *file,
483                                   file_t *dir, const char **name);
484 #define hurd_path_split __hurd_path_split
485 extern error_t __hurd_path_lookup (file_t crdir, file_t cwdir,
486                                    const char *file,
487                                    int flags, mode_t mode,
488                                    file_t *file);
489 #define hurd_path_lookup __hurd_path_lookup
490
491 /* Returns a port to the directory, and sets *NAME to the file name.  */
492 extern file_t __path_split (const char *file, const char **name);
493 #define path_split      __path_split
494
495 /* Looks up FILE with the given FLAGS and MODE (as for dir_pathtrans).  */
496 extern file_t __path_lookup (const char *file, int flags, mode_t mode);
497 #define path_lookup __path_lookup
498
499 /* Open a file descriptor on a port.  */
500 extern int openport (io_t port);
501
502 /* Inform the proc server we have exitted with STATUS, and kill the
503    task thoroughly.  This function never returns, no matter what.  */
504 extern volatile void _hurd_exit (int status);
505
506
507 #endif  /* hurd.h */