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"
24 * multi.c and multi.h, together with some rxgen hooks, provide a way of
25 * making multiple, but similar, rx calls to multiple hosts simultaneously
29 multi_Init(struct rx_connection **conns, register int nConns)
31 register struct rx_call **calls;
32 register short *ready;
33 register struct multi_handle *mh;
37 * Note: all structures that are possibly referenced by other
38 * processes must be allocated. In some kernels variables allocated on
39 * a process stack will not be accessible to other processes
42 calls = (struct rx_call **)osi_Alloc(sizeof(struct rx_call *) * nConns);
43 ready = (short *)osi_Alloc(sizeof(short *) * nConns);
44 mh = (struct multi_handle *)osi_Alloc(sizeof(struct multi_handle));
45 if (!calls || !ready || !mh)
46 osi_Panic("multi_Rx: no mem\n");
48 mh->nextReady = mh->firstNotReady = mh->ready = ready;
52 #ifdef RX_ENABLE_LOCKS
53 MUTEX_INIT(&mh->lock, "rx_multi_lock", MUTEX_DEFAULT, 0);
54 CV_INIT(&mh->cv, "rx_multi_cv", CV_DEFAULT, 0);
55 #endif /* RX_ENABLE_LOCKS */
56 for (i = 0; i < nConns; i++) {
57 register struct rx_call *call;
58 call = mh->calls[i] = rx_NewCall(conns[i]);
59 rx_SetArrivalProc(call, multi_Ready, (void *) mh, i);
64 /* Return the user's connection index of the most recently ready call; that is, a call that has received at least one reply packet */
66 multi_Select(register struct multi_handle *mh)
71 #ifdef RX_ENABLE_LOCKS
72 MUTEX_ENTER(&mh->lock);
73 #endif /* RX_ENABLE_LOCKS */
74 while (mh->nextReady == mh->firstNotReady) {
75 if (mh->nReady == mh->nConns) {
76 #ifdef RX_ENABLE_LOCKS
77 MUTEX_EXIT(&mh->lock);
78 #endif /* RX_ENABLE_LOCKS */
82 #ifdef RX_ENABLE_LOCKS
83 CV_WAIT(&mh->cv, &mh->lock);
84 #else /* RX_ENABLE_LOCKS */
86 #endif /* RX_ENABLE_LOCKS */
88 index = *(mh->nextReady);
90 #ifdef RX_ENABLE_LOCKS
91 MUTEX_EXIT(&mh->lock);
92 #endif /* RX_ENABLE_LOCKS */
97 /* Called by Rx when the first reply packet of a call is received, or the call is aborted. */
99 multi_Ready(register struct rx_call *call, register void *amh,
102 register struct multi_handle *mh = (struct multi_handle *)amh;
103 #ifdef RX_ENABLE_LOCKS
104 MUTEX_ENTER(&mh->lock);
105 #endif /* RX_ENABLE_LOCKS */
106 *mh->firstNotReady++ = index;
108 #ifdef RX_ENABLE_LOCKS
110 MUTEX_EXIT(&mh->lock);
111 #else /* RX_ENABLE_LOCKS */
113 #endif /* RX_ENABLE_LOCKS */
116 /* Called when the multi rx call is over, or when the user aborts it (by using the macro multi_Abort) */
118 multi_Finalize(register struct multi_handle *mh)
121 register int nCalls = mh->nConns;
122 for (i = 0; i < nCalls; i++) {
123 register struct rx_call *call = mh->calls[i];
125 rx_EndCall(call, RX_USER_ABORT);
127 #ifdef RX_ENABLE_LOCKS
128 MUTEX_DESTROY(&mh->lock);
130 #endif /* RX_ENABLE_LOCKS */
131 osi_Free(mh->calls, sizeof(struct rx_call *) * nCalls);
132 osi_Free(mh->ready, sizeof(short *) * nCalls);
133 osi_Free(mh, sizeof(struct multi_handle));
136 /* ignores all remaining multiRx calls */
138 multi_Finalize_Ignore(register struct multi_handle *mh)
141 register int nCalls = mh->nConns;
142 for (i = 0; i < nCalls; i++) {
143 register struct rx_call *call = mh->calls[i];
147 #ifdef RX_ENABLE_LOCKS
148 MUTEX_DESTROY(&mh->lock);
150 #endif /* RX_ENABLE_LOCKS */
151 osi_Free(mh->calls, sizeof(struct rx_call *) * nCalls);
152 osi_Free(mh->ready, sizeof(short *) * nCalls);
153 osi_Free(mh, sizeof(struct multi_handle));