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>
16 #include "../rx/rx_kernel.h"
17 #include "../rx/rx_multi.h"
20 # include "rx_multi.h"
21 # include "rx_internal.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 */
26 struct multi_handle *multi_Init(conns, nConns)
27 struct rx_connection **conns;
31 register struct rx_call **calls;
32 register short *ready;
33 register struct multi_handle *mh;
35 /* 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 */
36 calls = (struct rx_call **)osi_Alloc(sizeof (struct rx_call *) * nConns);
37 ready = (short *) osi_Alloc(sizeof(short *) * nConns);
38 mh = (struct multi_handle *) osi_Alloc(sizeof (struct multi_handle));
39 if (!calls || !ready || !mh) osi_Panic("multi_Rx: no mem\n");
41 mh->nextReady = mh->firstNotReady = mh->ready = ready;
44 #ifdef RX_ENABLE_LOCKS
45 MUTEX_INIT(&mh->lock, "rx_multi_lock", MUTEX_DEFAULT, 0);
46 CV_INIT(&mh->cv, "rx_multi_cv", CV_DEFAULT, 0);
47 #endif /* RX_ENABLE_LOCKS */
48 for (i=0; i<nConns; i++) {
49 register struct rx_call *call;
50 call = mh->calls[i] = rx_NewCall(conns[i]);
51 rx_SetArrivalProc(call, multi_Ready, (VOID *)mh, (VOID *)i);
56 /* Return the user's connection index of the most recently ready call; that is, a call that has received at least one reply packet */
58 register struct multi_handle *mh;
63 #ifdef RX_ENABLE_LOCKS
64 MUTEX_ENTER(&mh->lock);
65 #endif /* RX_ENABLE_LOCKS */
66 while (mh->nextReady == mh->firstNotReady) {
67 if (mh->nReady == mh->nConns) {
68 #ifdef RX_ENABLE_LOCKS
69 MUTEX_EXIT(&mh->lock);
70 #endif /* RX_ENABLE_LOCKS */
74 #ifdef RX_ENABLE_LOCKS
75 CV_WAIT(&mh->cv, &mh->lock);
76 #else /* RX_ENABLE_LOCKS */
78 #endif /* RX_ENABLE_LOCKS */
80 index = *(mh->nextReady);
82 #ifdef RX_ENABLE_LOCKS
83 MUTEX_EXIT(&mh->lock);
84 #endif /* RX_ENABLE_LOCKS */
89 /* Called by Rx when the first reply packet of a call is received, or the call is aborted. */
90 void multi_Ready(call, mh, index)
91 register struct rx_call *call;
92 register struct multi_handle *mh;
95 #ifdef RX_ENABLE_LOCKS
96 MUTEX_ENTER(&mh->lock);
97 #endif /* RX_ENABLE_LOCKS */
98 *mh->firstNotReady++ = index;
100 #ifdef RX_ENABLE_LOCKS
102 MUTEX_EXIT(&mh->lock);
103 #else /* RX_ENABLE_LOCKS */
105 #endif /* RX_ENABLE_LOCKS */
108 /* Called when the multi rx call is over, or when the user aborts it (by using the macro multi_Abort) */
109 void multi_Finalize(mh)
110 register struct multi_handle *mh;
113 register int nCalls = mh->nConns;
114 for (i=0; i<nCalls; i++) {
115 register struct rx_call *call = mh->calls[i];
116 if (call) rx_EndCall(call, RX_USER_ABORT);
118 #ifdef RX_ENABLE_LOCKS
119 MUTEX_DESTROY(&mh->lock);
121 #endif /* RX_ENABLE_LOCKS */
122 osi_Free(mh->calls, sizeof (struct rx_call *) * nCalls);
123 osi_Free(mh->ready, sizeof(short *) * nCalls);
124 osi_Free(mh, sizeof(struct multi_handle));
127 /* ignores all remaining multiRx calls */
128 void multi_Finalize_Ignore(mh)
129 register struct multi_handle *mh;
132 register int nCalls = mh->nConns;
133 for (i=0; i<nCalls; i++) {
134 register struct rx_call *call = mh->calls[i];
135 if (call) rx_EndCall(call, 0);
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));