(add_name_to_object): Don't translate strings.
[kopensolaris-gnu/glibc.git] / hurd / intr-msg.c
1 /* Replacement for mach_msg used in interruptible Hurd RPCs.
2    Copyright (C) 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 #include <mach.h>
21 #include <mach/mig_errors.h>
22 #include <mach/mig_support.h>
23 #include <hurd/signal.h>
24
25 #include "intr-msg.h"
26
27
28 error_t
29 _hurd_intr_rpc_mach_msg (mach_msg_header_t *msg,
30                          mach_msg_option_t option,
31                          mach_msg_size_t send_size,
32                          mach_msg_size_t rcv_size,
33                          mach_port_t rcv_name,
34                          mach_msg_timeout_t timeout,
35                          mach_port_t notify)
36 {
37   struct hurd_sigstate *ss = _hurd_self_sigstate ();
38   error_t err;
39   /* Notice now if the user requested a timeout.  OPTION may have the bit
40      added by interruption semantics, and we must distinguish.  */
41   int user_timeout = option & MACH_RCV_TIMEOUT;
42
43   /* Tell the signal thread that we are doing an interruptible RPC on
44      this port.  If we get a signal and should return EINTR, the signal
45      thread will set this variable to MACH_PORT_NULL.  The RPC might
46      return EINTR when some other thread gets a signal, in which case we
47      want to restart our call.  */
48   ss->intr_port = msg->msgh_remote_port;
49
50   /* A signal may arrive here, after intr_port is set, but before
51      the mach_msg system call.  The signal handler might do an
52      interruptible RPC, and clobber intr_port; then it would not be
53      set properly when we actually did send the RPC, and a later
54      signal wouldn't interrupt that RPC.  So,
55      _hurd_setup_sighandler saves intr_port in the sigcontext, and
56      sigreturn restores it.  */
57
58  message:
59
60   if (ss->cancel)
61     {
62       /* We have been cancelled.  Don't do an RPC at all.  */
63       ss->intr_port = MACH_PORT_NULL;
64       ss->cancel = 0;
65       return EINTR;
66     }
67
68   err = INTR_MSG_TRAP (msg, option, send_size,
69                        rcv_size, rcv_name, timeout, notify);
70
71   switch (err)
72     {
73     case MACH_RCV_TIMED_OUT:
74       if (user_timeout)
75         /* The real user RPC timed out.  */
76         break;
77       else
78         /* The operation was supposedly interrupted, but still has
79            not returned.  Declare it interrupted.  */
80         goto interrupted;
81
82     case MACH_SEND_INTERRUPTED: /* RPC didn't get out.  */
83     case EINTR:                 /* Server not cooperating with interrupt.  */
84       if (ss->intr_port != MACH_PORT_NULL)
85         /* If this signal was for us and it should interrupt calls, the
86            signal thread will have cleared SS->intr_port.
87            Since it's not cleared, the signal was for another thread,
88            or SA_RESTART is set.  Restart the interrupted call.  */
89         {
90         restart:
91           if (rcv_name != MACH_PORT_NULL)
92             /* Make sure we have a valid reply port.  The one we were using
93                may have been destroyed by interruption.  */
94             msg->msgh_local_port = rcv_name = __mig_get_reply_port ();
95           goto message;
96         }
97       /* FALLTHROUGH */
98
99     case MACH_RCV_PORT_DIED:
100       /* Server didn't respond to interrupt_operation,
101          so the signal thread destroyed the reply port.  */
102       /* FALLTHROUGH */
103
104     interrupted:
105       err = EINTR;
106
107       /* The EINTR return indicates cancellation, so clear the flag.  */
108       ss->cancel = 0;
109       break;
110
111     case MACH_RCV_INTERRUPTED:  /* RPC sent; no reply.  */
112       option &= ~MACH_SEND_MSG; /* Don't send again.  */
113       if (ss->intr_port == MACH_PORT_NULL)
114         {
115           /* This signal or cancellation was for us.  We need to wait for
116              the reply, but not hang forever.  */
117           option |= MACH_RCV_TIMEOUT;
118           /* Never decrease the user's timeout.  */
119           if (!user_timeout || timeout > _hurd_interrupted_rpc_timeout)
120             timeout = _hurd_interrupted_rpc_timeout;
121         }
122       goto message;             /* Retry the receive.  */
123
124     case MACH_MSG_SUCCESS:
125       if (option & MACH_RCV_MSG)
126         {
127           /* We got a reply.  Was it EINTR?  */
128           mig_reply_header_t *const reply = (void *) msg;
129           const union
130             {
131               mach_msg_type_t t;
132               int i;
133             } check =
134               { t: {
135                 MACH_MSG_TYPE_INTEGER_T,
136                 MACH_MSG_TYPE_INTEGER_T,
137                 1,
138                 TRUE,
139                 FALSE,
140                 FALSE,
141                 0
142               } };
143           if (msg->msgh_size == sizeof *reply &&
144               !(msg->msgh_bits & MACH_MSGH_BITS_COMPLEX) &&
145               *(int *) &reply->RetCodeType == check.i &&
146               reply->RetCode == EINTR)
147             {
148               /* It is indeed EINTR.  Is the interrupt for us?  */
149               if (ss->intr_port != MACH_PORT_NULL)
150                 /* Nope; repeat the RPC.
151                    XXX Resources moved? */
152                 goto restart;
153               else
154                 /* The EINTR return indicates cancellation, so clear the
155                    flag.  */
156                 ss->cancel = 0;
157             }
158         }
159       break;
160
161     default:                    /* Quiet -Wswitch-enum.  */
162     }
163
164   ss->intr_port = MACH_PORT_NULL;
165
166   return err;
167 }