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 "rx/rx_kernel.h"
18 #include "rx/rx_multi.h"
21 # include "rx_multi.h"
24 /* multi.c and multi.h, together with some rxgen hooks, provide a way of making multiple, but similar, rx calls to multiple hosts simultaneously */
27 multi_Init(struct rx_connection **conns, register int nConns)
29 register struct rx_call **calls;
30 register short *ready;
31 register struct multi_handle *mh;
33 /* Note: all structures that are possibly referenced by other processes must be allocated. In some kernels variables allocated on a process stack will not be accessible to other processes */
34 calls = (struct rx_call **)osi_Alloc(sizeof(struct rx_call *) * nConns);
35 ready = (short *)osi_Alloc(sizeof(short *) * nConns);
36 mh = (struct multi_handle *)osi_Alloc(sizeof(struct multi_handle));
37 if (!calls || !ready || !mh)
38 osi_Panic("multi_Rx: no mem\n");
40 mh->nextReady = mh->firstNotReady = mh->ready = ready;
43 #ifdef RX_ENABLE_LOCKS
44 MUTEX_INIT(&mh->lock, "rx_multi_lock", MUTEX_DEFAULT, 0);
45 CV_INIT(&mh->cv, "rx_multi_cv", CV_DEFAULT, 0);
46 #endif /* RX_ENABLE_LOCKS */
47 for (i = 0; i < nConns; i++) {
48 register struct rx_call *call;
49 call = mh->calls[i] = rx_NewCall(conns[i]);
50 rx_SetArrivalProc(call, multi_Ready, (VOID *) mh, (VOID *) i);
55 /* Return the user's connection index of the most recently ready call; that is, a call that has received at least one reply packet */
57 multi_Select(register struct multi_handle *mh)
62 #ifdef RX_ENABLE_LOCKS
63 MUTEX_ENTER(&mh->lock);
64 #endif /* RX_ENABLE_LOCKS */
65 while (mh->nextReady == mh->firstNotReady) {
66 if (mh->nReady == mh->nConns) {
67 #ifdef RX_ENABLE_LOCKS
68 MUTEX_EXIT(&mh->lock);
69 #endif /* RX_ENABLE_LOCKS */
73 #ifdef RX_ENABLE_LOCKS
74 CV_WAIT(&mh->cv, &mh->lock);
75 #else /* RX_ENABLE_LOCKS */
77 #endif /* RX_ENABLE_LOCKS */
79 index = *(mh->nextReady);
81 #ifdef RX_ENABLE_LOCKS
82 MUTEX_EXIT(&mh->lock);
83 #endif /* RX_ENABLE_LOCKS */
88 /* Called by Rx when the first reply packet of a call is received, or the call is aborted. */
90 multi_Ready(register struct rx_call *call, register struct multi_handle *mh,
93 #ifdef RX_ENABLE_LOCKS
94 MUTEX_ENTER(&mh->lock);
95 #endif /* RX_ENABLE_LOCKS */
96 *mh->firstNotReady++ = index;
98 #ifdef RX_ENABLE_LOCKS
100 MUTEX_EXIT(&mh->lock);
101 #else /* RX_ENABLE_LOCKS */
103 #endif /* RX_ENABLE_LOCKS */
106 /* Called when the multi rx call is over, or when the user aborts it (by using the macro multi_Abort) */
108 multi_Finalize(register struct multi_handle *mh)
111 register int nCalls = mh->nConns;
112 for (i = 0; i < nCalls; i++) {
113 register struct rx_call *call = mh->calls[i];
115 rx_EndCall(call, RX_USER_ABORT);
117 #ifdef RX_ENABLE_LOCKS
118 MUTEX_DESTROY(&mh->lock);
120 #endif /* RX_ENABLE_LOCKS */
121 osi_Free(mh->calls, sizeof(struct rx_call *) * nCalls);
122 osi_Free(mh->ready, sizeof(short *) * nCalls);
123 osi_Free(mh, sizeof(struct multi_handle));
126 /* ignores all remaining multiRx calls */
128 multi_Finalize_Ignore(register struct multi_handle *mh)
131 register int nCalls = mh->nConns;
132 for (i = 0; i < nCalls; i++) {
133 register struct rx_call *call = mh->calls[i];
137 #ifdef RX_ENABLE_LOCKS
138 MUTEX_DESTROY(&mh->lock);
140 #endif /* RX_ENABLE_LOCKS */
141 osi_Free(mh->calls, sizeof(struct rx_call *) * nCalls);
142 osi_Free(mh->ready, sizeof(short *) * nCalls);
143 osi_Free(mh, sizeof(struct multi_handle));