2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include <afs/param.h>
17 #include "afs/sysincludes.h"
18 #include "rx/rx_internal.h"
20 #include "rx/rx_globals.h"
22 # include "rx_internal.h"
24 # include "rx_globals.h"
28 * multi.c and multi.h, together with some rxgen hooks, provide a way of
29 * making multiple, but similar, rx calls to multiple hosts simultaneously
33 multi_Init(struct rx_connection **conns, int nConns)
35 struct rx_call **calls;
37 struct multi_handle *mh;
41 * Note: all structures that are possibly referenced by other
42 * processes must be allocated. In some kernels variables allocated on
43 * a process stack will not be accessible to other processes
46 calls = (struct rx_call **)osi_Alloc(sizeof(struct rx_call *) * nConns);
47 ready = (short *)osi_Alloc(sizeof(short *) * nConns);
48 mh = (struct multi_handle *)osi_Alloc(sizeof(struct multi_handle));
49 if (!calls || !ready || !mh)
50 osi_Panic("multi_Rx: no mem\n");
52 mh->nextReady = mh->firstNotReady = mh->ready = ready;
56 #ifdef RX_ENABLE_LOCKS
57 MUTEX_INIT(&mh->lock, "rx_multi_lock", MUTEX_DEFAULT, 0);
58 CV_INIT(&mh->cv, "rx_multi_cv", CV_DEFAULT, 0);
59 #endif /* RX_ENABLE_LOCKS */
60 for (i = 0; i < nConns; i++) {
62 call = mh->calls[i] = rx_NewCall(conns[i]);
63 rx_SetArrivalProc(call, multi_Ready, (void *) mh, i);
68 /* Return the user's connection index of the most recently ready call; that is, a call that has received at least one reply packet */
70 multi_Select(struct multi_handle *mh)
75 #ifdef RX_ENABLE_LOCKS
76 MUTEX_ENTER(&mh->lock);
77 #endif /* RX_ENABLE_LOCKS */
78 while (mh->nextReady == mh->firstNotReady) {
79 if (mh->nReady == mh->nConns) {
80 #ifdef RX_ENABLE_LOCKS
81 MUTEX_EXIT(&mh->lock);
82 #endif /* RX_ENABLE_LOCKS */
86 #ifdef RX_ENABLE_LOCKS
87 CV_WAIT(&mh->cv, &mh->lock);
88 #else /* RX_ENABLE_LOCKS */
90 #endif /* RX_ENABLE_LOCKS */
92 index = *(mh->nextReady);
94 #ifdef RX_ENABLE_LOCKS
95 MUTEX_EXIT(&mh->lock);
96 #endif /* RX_ENABLE_LOCKS */
101 /* Called by Rx when the first reply packet of a call is received, or the call is aborted. */
103 multi_Ready(struct rx_call *call, void *amh,
106 struct multi_handle *mh = (struct multi_handle *)amh;
107 #ifdef RX_ENABLE_LOCKS
108 MUTEX_ENTER(&mh->lock);
109 #endif /* RX_ENABLE_LOCKS */
110 *mh->firstNotReady++ = index;
112 #ifdef RX_ENABLE_LOCKS
114 MUTEX_EXIT(&mh->lock);
115 #else /* RX_ENABLE_LOCKS */
117 #endif /* RX_ENABLE_LOCKS */
120 /* Called when the multi rx call is over, or when the user aborts it (by using the macro multi_Abort) */
122 multi_Finalize(struct multi_handle *mh)
125 int nCalls = mh->nConns;
126 for (i = 0; i < nCalls; i++) {
127 struct rx_call *call = mh->calls[i];
129 rx_EndCall(call, RX_USER_ABORT);
131 #ifdef RX_ENABLE_LOCKS
132 MUTEX_DESTROY(&mh->lock);
134 #endif /* RX_ENABLE_LOCKS */
135 osi_Free(mh->calls, sizeof(struct rx_call *) * nCalls);
136 osi_Free(mh->ready, sizeof(short *) * nCalls);
137 osi_Free(mh, sizeof(struct multi_handle));
140 /* ignores all remaining multiRx calls */
142 multi_Finalize_Ignore(struct multi_handle *mh)
145 int nCalls = mh->nConns;
146 for (i = 0; i < nCalls; i++) {
147 struct rx_call *call = mh->calls[i];
151 #ifdef RX_ENABLE_LOCKS
152 MUTEX_DESTROY(&mh->lock);
154 #endif /* RX_ENABLE_LOCKS */
155 osi_Free(mh->calls, sizeof(struct rx_call *) * nCalls);
156 osi_Free(mh->ready, sizeof(short *) * nCalls);
157 osi_Free(mh, sizeof(struct multi_handle));