1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21: #include <mach.h>
22: #include <mach/mig_errors.h>
23: #include <mach/mig_support.h>
24: #include <hurd/signal.h>
25: #include <assert.h>
26:
27: #include "intr-msg.h"
28:
29: #ifdef NDR_CHAR_ASCII
30: # define mig_reply_header_t mig_reply_error_t
31: #endif
32:
33: error_t
34: _hurd_intr_rpc_mach_msg (mach_msg_header_t *msg,
35: mach_msg_option_t option,
36: mach_msg_size_t send_size,
37: mach_msg_size_t rcv_size,
38: mach_port_t rcv_name,
39: mach_msg_timeout_t timeout,
40: mach_port_t notify)
41: {
42: error_t err;
43: struct hurd_sigstate *ss;
44: const mach_msg_option_t user_option = option;
45: const mach_msg_timeout_t user_timeout = timeout;
46:
47: struct clobber
48: {
49: #ifdef NDR_CHAR_ASCII
50: NDR_record_t ndr;
51: #else
52: mach_msg_type_t type;
53: #endif
54: error_t err;
55: };
56: union msg
57: {
58: mach_msg_header_t header;
59: mig_reply_header_t reply;
60: struct
61: {
62: mach_msg_header_t header;
63: #ifdef NDR_CHAR_ASCII
64: NDR_record_t ndr;
65: #else
66: int type;
67: #endif
68: int code;
69: } check;
70: struct
71: {
72: mach_msg_header_t header;
73: struct clobber data;
74: } request;
75: };
76: union msg *const m = (void *) msg;
77: mach_msg_bits_t msgh_bits;
78: mach_port_t remote_port;
79: mach_msg_id_t msgid;
80: struct clobber save_data;
81:
82: if ((option & (MACH_SEND_MSG|MACH_RCV_MSG)) != (MACH_SEND_MSG|MACH_RCV_MSG)
83: || _hurd_msgport_thread == MACH_PORT_NULL)
84: {
85:
86:
87:
88:
89: return __mach_msg (&m->header, option, send_size, rcv_size, rcv_name,
90: timeout, notify);
91: }
92:
93: ss = _hurd_self_sigstate ();
94:
95:
96:
97: msgh_bits = m->header.msgh_bits;
98: remote_port = m->header.msgh_remote_port;
99: msgid = m->header.msgh_id;
100: assert (rcv_size >= sizeof m->request);
101: save_data = m->request.data;
102:
103:
104:
105:
106:
107:
108: ss->intr_port = m->header.msgh_remote_port;
109:
110:
111:
112:
113:
114:
115:
116:
117: message:
118:
119:
120:
121:
122:
123:
124:
125: if (ss->cancel)
126: {
127:
128: ss->intr_port = MACH_PORT_NULL;
129: ss->cancel = 0;
130: return EINTR;
131: }
132:
133:
134: err = INTR_MSG_TRAP (msg, option, send_size,
135: rcv_size, rcv_name, timeout, notify);
136:
137: switch (err)
138: {
139: case MACH_RCV_TIMED_OUT:
140: if (user_option & MACH_RCV_TIMEOUT)
141:
142: break;
143: else
144:
145:
146: goto interrupted;
147:
148: case MACH_SEND_INTERRUPTED:
149: if (!(option & MACH_SEND_MSG))
150: {
151:
152:
153:
154:
155:
156:
157:
158: goto retry_receive;
159: }
160:
161:
162:
163:
164: case MACH_SEND_TIMED_OUT:
165: case MACH_SEND_INVALID_NOTIFY:
166: #ifdef MACH_SEND_NO_NOTIFY
167: case MACH_SEND_NO_NOTIFY:
168: #endif
169: #ifdef MACH_SEND_NOTIFY_IN_PROGRESS
170: case MACH_SEND_NOTIFY_IN_PROGRESS:
171: #endif
172: if (MACH_MSGH_BITS_REMOTE (msg->msgh_bits) == MACH_MSG_TYPE_MOVE_SEND)
173: {
174: __mach_port_deallocate (__mach_task_self (), msg->msgh_remote_port);
175: msg->msgh_bits
176: = (MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND,
177: MACH_MSGH_BITS_LOCAL (msg->msgh_bits))
178: | MACH_MSGH_BITS_OTHER (msg->msgh_bits));
179: }
180: if (msg->msgh_bits & MACH_MSGH_BITS_COMPLEX)
181: {
182: #ifndef MACH_MSG_PORT_DESCRIPTOR
183:
184:
185:
186:
187:
188:
189:
190: mach_msg_type_long_t *ty = (void *) (msg + 1);
191: while ((void *) ty < (void *) msg + msg->msgh_size)
192: {
193: mach_msg_type_name_t name;
194: mach_msg_type_size_t size;
195: mach_msg_type_number_t number;
196:
197: inline void clean_ports (mach_port_t *ports, int dealloc)
198: {
199: mach_msg_type_number_t i;
200: switch (name)
201: {
202: case MACH_MSG_TYPE_MOVE_SEND:
203: for (i = 0; i < number; i++)
204: __mach_port_deallocate (__mach_task_self (), *ports++);
205: if (ty->msgtl_header.msgt_longform)
206: ty->msgtl_name = MACH_MSG_TYPE_COPY_SEND;
207: else
208: ty->msgtl_header.msgt_name = MACH_MSG_TYPE_COPY_SEND;
209: break;
210: case MACH_MSG_TYPE_COPY_SEND:
211: case MACH_MSG_TYPE_MOVE_RECEIVE:
212: break;
213: default:
214: if (MACH_MSG_TYPE_PORT_ANY (name))
215: assert (! "unexpected port type in interruptible RPC");
216: }
217: if (dealloc)
218: __vm_deallocate (__mach_task_self (),
219: (vm_address_t) ports,
220: number * sizeof (mach_port_t));
221: }
222:
223: if (ty->msgtl_header.msgt_longform)
224: {
225: name = ty->msgtl_name;
226: size = ty->msgtl_size;
227: number = ty->msgtl_number;
228: ty = (void *) ty + sizeof (mach_msg_type_long_t);
229: }
230: else
231: {
232: name = ty->msgtl_header.msgt_name;
233: size = ty->msgtl_header.msgt_size;
234: number = ty->msgtl_header.msgt_number;
235: ty = (void *) ty + sizeof (mach_msg_type_t);
236: }
237:
238: if (ty->msgtl_header.msgt_inline)
239: {
240: clean_ports ((void *) ty, 0);
241:
242: ty = (void *) ty + (((((number * size) + 7) >> 3)
243: + sizeof (mach_msg_type_t) - 1)
244: &~ (sizeof (mach_msg_type_t) - 1));
245: }
246: else
247: {
248: clean_ports (*(void **) ty,
249: ty->msgtl_header.msgt_deallocate);
250: ty = (void *) ty + sizeof (void *);
251: }
252: }
253: #else
254: mach_msg_body_t *body = (void *) (msg + 1);
255: mach_msg_descriptor_t *desc = (void *) (body + 1);
256: mach_msg_descriptor_t *desc_end = desc + body->msgh_descriptor_count;
257: for (; desc < desc_end; ++desc)
258: switch (desc->type.type)
259: {
260: case MACH_MSG_PORT_DESCRIPTOR:
261: switch (desc->port.disposition)
262: {
263: case MACH_MSG_TYPE_MOVE_SEND:
264: __mach_port_deallocate (mach_task_self (),
265: desc->port.name);
266: desc->port.disposition = MACH_MSG_TYPE_COPY_SEND;
267: break;
268: case MACH_MSG_TYPE_COPY_SEND:
269: case MACH_MSG_TYPE_MOVE_RECEIVE:
270: break;
271: default:
272: assert (! "unexpected port type in interruptible RPC");
273: }
274: break;
275: case MACH_MSG_OOL_DESCRIPTOR:
276: if (desc->out_of_line.deallocate)
277: __vm_deallocate (__mach_task_self (),
278: (vm_address_t) desc->out_of_line.address,
279: desc->out_of_line.size);
280: break;
281: case MACH_MSG_OOL_PORTS_DESCRIPTOR:
282: switch (desc->ool_ports.disposition)
283: {
284: case MACH_MSG_TYPE_MOVE_SEND:
285: {
286: mach_msg_size_t i;
287: const mach_port_t *ports = desc->ool_ports.address;
288: for (i = 0; i < desc->ool_ports.count; ++i)
289: __mach_port_deallocate (__mach_task_self (), ports[i]);
290: desc->ool_ports.disposition = MACH_MSG_TYPE_COPY_SEND;
291: break;
292: }
293: case MACH_MSG_TYPE_COPY_SEND:
294: case MACH_MSG_TYPE_MOVE_RECEIVE:
295: break;
296: default:
297: assert (! "unexpected port type in interruptible RPC");
298: }
299: if (desc->ool_ports.deallocate)
300: __vm_deallocate (__mach_task_self (),
301: (vm_address_t) desc->ool_ports.address,
302: desc->ool_ports.count
303: * sizeof (mach_port_t));
304: break;
305: default:
306: assert (! "unexpected descriptor type in interruptible RPC");
307: }
308: #endif
309: }
310: break;
311:
312: case EINTR:
313:
314:
315: if (ss->intr_port != MACH_PORT_NULL)
316:
317:
318:
319:
320: {
321:
322:
323: m->header.msgh_local_port = rcv_name = __mig_get_reply_port ();
324: m->header.msgh_bits = msgh_bits;
325: option = user_option;
326: timeout = user_timeout;
327: goto message;
328: }
329:
330:
331: case MACH_RCV_PORT_DIED:
332:
333:
334:
335:
336: interrupted:
337: err = EINTR;
338:
339:
340: ss->cancel = 0;
341: break;
342:
343: case MACH_RCV_INTERRUPTED:
344: option &= ~MACH_SEND_MSG;
345: retry_receive:
346: if (ss->intr_port == MACH_PORT_NULL)
347: {
348:
349:
350: option |= MACH_RCV_TIMEOUT;
351:
352: if (!(user_option & MACH_RCV_TIMEOUT)
353: || timeout > _hurd_interrupted_rpc_timeout)
354: timeout = _hurd_interrupted_rpc_timeout;
355: }
356: else
357: {
358: option = user_option;
359: timeout = user_timeout;
360: }
361: goto message;
362:
363: case MACH_MSG_SUCCESS:
364: {
365:
366: #ifdef MACH_MSG_TYPE_BIT
367: const union
368: {
369: mach_msg_type_t t;
370: int i;
371: } check =
372: { t: { MACH_MSG_TYPE_INTEGER_T, sizeof (integer_t) * 8,
373: 1, TRUE, FALSE, FALSE, 0 } };
374: #endif
375:
376: if (m->reply.RetCode == EINTR &&
377: m->header.msgh_size == sizeof m->reply &&
378: #ifdef MACH_MSG_TYPE_BIT
379: m->check.type == check.i &&
380: #endif
381: !(m->header.msgh_bits & MACH_MSGH_BITS_COMPLEX))
382: {
383:
384: if (ss->intr_port != MACH_PORT_NULL)
385: {
386:
387:
388:
389: assert (m->header.msgh_id == msgid + 100);
390:
391:
392:
393:
394:
395: m->header.msgh_local_port = rcv_name;
396: m->header.msgh_remote_port = remote_port;
397: m->header.msgh_id = msgid;
398: m->header.msgh_bits = msgh_bits;
399:
400: m->request.data = save_data;
401:
402:
403:
404:
405: option = user_option;
406: timeout = user_timeout;
407:
408:
409: goto message;
410: }
411: else
412:
413:
414: ss->cancel = 0;
415: }
416: }
417: break;
418:
419: default:
420: break;
421: }
422:
423: ss->intr_port = MACH_PORT_NULL;
424:
425: return err;
426: }