ee858d592436555224f56bb29427e6b7fbe7fa1d
[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 #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         struct rx_call *call;
58         call = mh->calls[i] = rx_NewCall(conns[i]);
59         rx_SetArrivalProc(call, multi_Ready, (void *) mh, i);
60     }
61     return mh;
62 }
63
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 */
65 int
66 multi_Select(struct multi_handle *mh)
67 {
68     int index;
69     SPLVAR;
70     NETPRI;
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 */
79             USERPRI;
80             return -1;
81         }
82 #ifdef RX_ENABLE_LOCKS
83         CV_WAIT(&mh->cv, &mh->lock);
84 #else /* RX_ENABLE_LOCKS */
85         osi_rxSleep(mh);
86 #endif /* RX_ENABLE_LOCKS */
87     }
88     index = *(mh->nextReady);
89     (mh->nextReady) += 1;
90 #ifdef RX_ENABLE_LOCKS
91     MUTEX_EXIT(&mh->lock);
92 #endif /* RX_ENABLE_LOCKS */
93     USERPRI;
94     return index;
95 }
96
97 /* Called by Rx when the first reply packet of a call is received, or the call is aborted. */
98 void
99 multi_Ready(struct rx_call *call, void *amh,
100             int index)
101 {
102     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;
107     mh->nReady++;
108 #ifdef RX_ENABLE_LOCKS
109     CV_SIGNAL(&mh->cv);
110     MUTEX_EXIT(&mh->lock);
111 #else /* RX_ENABLE_LOCKS */
112     osi_rxWakeup(mh);
113 #endif /* RX_ENABLE_LOCKS */
114 }
115
116 /* Called when the multi rx call is over, or when the user aborts it (by using the macro multi_Abort) */
117 void
118 multi_Finalize(struct multi_handle *mh)
119 {
120     int i;
121     int nCalls = mh->nConns;
122     for (i = 0; i < nCalls; i++) {
123         struct rx_call *call = mh->calls[i];
124         if (call)
125             rx_EndCall(call, RX_USER_ABORT);
126     }
127 #ifdef RX_ENABLE_LOCKS
128     MUTEX_DESTROY(&mh->lock);
129     CV_DESTROY(&mh->cv);
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));
134 }
135
136 /* ignores all remaining multiRx calls */
137 void
138 multi_Finalize_Ignore(struct multi_handle *mh)
139 {
140     int i;
141     int nCalls = mh->nConns;
142     for (i = 0; i < nCalls; i++) {
143         struct rx_call *call = mh->calls[i];
144         if (call)
145             rx_EndCall(call, 0);
146     }
147 #ifdef RX_ENABLE_LOCKS
148     MUTEX_DESTROY(&mh->lock);
149     CV_DESTROY(&mh->cv);
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));
154 }