Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / rx / rx_multi.c
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
8 */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 #ifdef KERNEL
14 # include "afs/sysincludes.h"
15 #else /* KERNEL */
16 # include <roken.h>
17 # include <afs/opr.h>
18 #endif /* KERNEL */
19
20 #include "rx.h"
21
22 /*
23 * multi.c and multi.h, together with some rxgen hooks, provide a way of
24 * making multiple, but similar, rx calls to multiple hosts simultaneously
25 */
26
27 struct multi_handle *
28 multi_Init(struct rx_connection **conns, int nConns)
29 {
30 struct rx_call **calls;
31 short *ready;
32 struct multi_handle *mh;
33 int i;
34
35 /*
36 * Note: all structures that are possibly referenced by other
37 * processes must be allocated. In some kernels variables allocated on
38 * a process stack will not be accessible to other processes
39 */
40
41 calls = osi_Alloc(sizeof(struct rx_call *) * nConns);
42 ready = osi_Alloc(sizeof(short) * nConns);
43 mh = osi_Alloc(sizeof(struct multi_handle));
44 if (!calls || !ready || !mh)
45 osi_Panic("multi_Rx: no mem\n");
46 memset(mh, 0, sizeof(struct multi_handle));
47 mh->calls = calls;
48 mh->nextReady = mh->firstNotReady = mh->ready = ready;
49 mh->nReady = 0;
50 mh->nConns = nConns;
51
52 MUTEX_INIT(&mh->lock, "rx_multi_lock", MUTEX_DEFAULT, 0);
53 CV_INIT(&mh->cv, "rx_multi_cv", CV_DEFAULT, 0);
54 for (i = 0; i < nConns; i++) {
55 struct rx_call *call;
56 call = mh->calls[i] = rx_NewCall(conns[i]);
57 rx_SetArrivalProc(call, multi_Ready, (void *) mh, i);
58 }
59 return mh;
60 }
61
62 /* Return the user's connection index of the most recently ready call; that is, a call that has received at least one reply packet */
63 int
64 multi_Select(struct multi_handle *mh)
65 {
66 int index;
67 SPLVAR;
68 NETPRI;
69 MUTEX_ENTER(&mh->lock);
70 while (mh->nextReady == mh->firstNotReady) {
71 if (mh->nReady == mh->nConns) {
72 MUTEX_EXIT(&mh->lock);
73 USERPRI;
74 return -1;
75 }
76 #ifdef RX_ENABLE_LOCKS
77 CV_WAIT(&mh->cv, &mh->lock);
78 #else /* RX_ENABLE_LOCKS */
79 osi_rxSleep(mh);
80 #endif /* RX_ENABLE_LOCKS */
81 }
82 index = *(mh->nextReady);
83 (mh->nextReady) += 1;
84 MUTEX_EXIT(&mh->lock);
85 USERPRI;
86 return index;
87 }
88
89 /* Called by Rx when the first reply packet of a call is received, or the call is aborted. */
90 void
91 multi_Ready(struct rx_call *call, void *amh,
92 int index)
93 {
94 struct multi_handle *mh = (struct multi_handle *)amh;
95 MUTEX_ENTER(&mh->lock);
96 *mh->firstNotReady++ = index;
97 mh->nReady++;
98 #ifdef RX_ENABLE_LOCKS
99 CV_SIGNAL(&mh->cv);
100 #else /* RX_ENABLE_LOCKS */
101 osi_rxWakeup(mh);
102 #endif /* RX_ENABLE_LOCKS */
103 MUTEX_EXIT(&mh->lock);
104 }
105
106 /* Called when the multi rx call is over, or when the user aborts it (by using the macro multi_Abort) */
107 void
108 multi_Finalize(struct multi_handle *mh)
109 {
110 int i;
111 int nCalls = mh->nConns;
112 for (i = 0; i < nCalls; i++) {
113 struct rx_call *call = mh->calls[i];
114 if (call)
115 rx_EndCall(call, RX_USER_ABORT);
116 }
117 MUTEX_DESTROY(&mh->lock);
118 CV_DESTROY(&mh->cv);
119 osi_Free(mh->calls, sizeof(struct rx_call *) * nCalls);
120 osi_Free(mh->ready, sizeof(short) * nCalls);
121 osi_Free(mh, sizeof(struct multi_handle));
122 }
123
124 /* ignores all remaining multiRx calls */
125 void
126 multi_Finalize_Ignore(struct multi_handle *mh)
127 {
128 int i;
129 int nCalls = mh->nConns;
130 for (i = 0; i < nCalls; i++) {
131 struct rx_call *call = mh->calls[i];
132 if (call)
133 rx_EndCall(call, 0);
134 }
135 MUTEX_DESTROY(&mh->lock);
136 CV_DESTROY(&mh->cv);
137 osi_Free(mh->calls, sizeof(struct rx_call *) * nCalls);
138 osi_Free(mh->ready, sizeof(short) * nCalls);
139 osi_Free(mh, sizeof(struct multi_handle));
140 }