a2e3bdf8962bb3fb23afdf1c48d84584661ceea1
[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 #endif /* KERNEL */
18
19 #include "rx.h"
20
21 /*
22  * multi.c and multi.h, together with some rxgen hooks, provide a way of
23  * making multiple, but similar, rx calls to multiple hosts simultaneously
24  */
25
26 struct multi_handle *
27 multi_Init(struct rx_connection **conns, int nConns)
28 {
29     struct rx_call **calls;
30     short *ready;
31     struct multi_handle *mh;
32     int i;
33
34     /*
35      * Note: all structures that are possibly referenced by other
36      * processes must be allocated.  In some kernels variables allocated on
37      * a process stack will not be accessible to other processes
38      */
39
40     calls = (struct rx_call **)osi_Alloc(sizeof(struct rx_call *) * nConns);
41     ready = (short *)osi_Alloc(sizeof(short *) * nConns);
42     mh = (struct multi_handle *)osi_Alloc(sizeof(struct multi_handle));
43     if (!calls || !ready || !mh)
44         osi_Panic("multi_Rx: no mem\n");
45     mh->calls = calls;
46     mh->nextReady = mh->firstNotReady = mh->ready = ready;
47     mh->nReady = 0;
48     mh->nConns = nConns;
49
50 #ifdef RX_ENABLE_LOCKS
51     MUTEX_INIT(&mh->lock, "rx_multi_lock", MUTEX_DEFAULT, 0);
52     CV_INIT(&mh->cv, "rx_multi_cv", CV_DEFAULT, 0);
53 #endif /* RX_ENABLE_LOCKS */
54     for (i = 0; i < nConns; i++) {
55         struct rx_call *call;
56         call = mh->calls[i] = rx_NewCall(conns[i]);
57         rx_SetArrivalProc(call, multi_Ready, (void *) mh, i);
58     }
59     return mh;
60 }
61
62 /* Return the user's connection index of the most recently ready call; that is, a call that has received at least one reply packet */
63 int
64 multi_Select(struct multi_handle *mh)
65 {
66     int index;
67     SPLVAR;
68     NETPRI;
69 #ifdef RX_ENABLE_LOCKS
70     MUTEX_ENTER(&mh->lock);
71 #endif /* RX_ENABLE_LOCKS */
72     while (mh->nextReady == mh->firstNotReady) {
73         if (mh->nReady == mh->nConns) {
74 #ifdef RX_ENABLE_LOCKS
75             MUTEX_EXIT(&mh->lock);
76 #endif /* RX_ENABLE_LOCKS */
77             USERPRI;
78             return -1;
79         }
80 #ifdef RX_ENABLE_LOCKS
81         CV_WAIT(&mh->cv, &mh->lock);
82 #else /* RX_ENABLE_LOCKS */
83         osi_rxSleep(mh);
84 #endif /* RX_ENABLE_LOCKS */
85     }
86     index = *(mh->nextReady);
87     (mh->nextReady) += 1;
88 #ifdef RX_ENABLE_LOCKS
89     MUTEX_EXIT(&mh->lock);
90 #endif /* RX_ENABLE_LOCKS */
91     USERPRI;
92     return index;
93 }
94
95 /* Called by Rx when the first reply packet of a call is received, or the call is aborted. */
96 void
97 multi_Ready(struct rx_call *call, void *amh,
98             int index)
99 {
100     struct multi_handle *mh = (struct multi_handle *)amh;
101 #ifdef RX_ENABLE_LOCKS
102     MUTEX_ENTER(&mh->lock);
103 #endif /* RX_ENABLE_LOCKS */
104     *mh->firstNotReady++ = index;
105     mh->nReady++;
106 #ifdef RX_ENABLE_LOCKS
107     CV_SIGNAL(&mh->cv);
108     MUTEX_EXIT(&mh->lock);
109 #else /* RX_ENABLE_LOCKS */
110     osi_rxWakeup(mh);
111 #endif /* RX_ENABLE_LOCKS */
112 }
113
114 /* Called when the multi rx call is over, or when the user aborts it (by using the macro multi_Abort) */
115 void
116 multi_Finalize(struct multi_handle *mh)
117 {
118     int i;
119     int nCalls = mh->nConns;
120     for (i = 0; i < nCalls; i++) {
121         struct rx_call *call = mh->calls[i];
122         if (call)
123             rx_EndCall(call, RX_USER_ABORT);
124     }
125 #ifdef RX_ENABLE_LOCKS
126     MUTEX_DESTROY(&mh->lock);
127     CV_DESTROY(&mh->cv);
128 #endif /* RX_ENABLE_LOCKS */
129     osi_Free(mh->calls, sizeof(struct rx_call *) * nCalls);
130     osi_Free(mh->ready, sizeof(short *) * nCalls);
131     osi_Free(mh, sizeof(struct multi_handle));
132 }
133
134 /* ignores all remaining multiRx calls */
135 void
136 multi_Finalize_Ignore(struct multi_handle *mh)
137 {
138     int i;
139     int nCalls = mh->nConns;
140     for (i = 0; i < nCalls; i++) {
141         struct rx_call *call = mh->calls[i];
142         if (call)
143             rx_EndCall(call, 0);
144     }
145 #ifdef RX_ENABLE_LOCKS
146     MUTEX_DESTROY(&mh->lock);
147     CV_DESTROY(&mh->cv);
148 #endif /* RX_ENABLE_LOCKS */
149     osi_Free(mh->calls, sizeof(struct rx_call *) * nCalls);
150     osi_Free(mh->ready, sizeof(short *) * nCalls);
151     osi_Free(mh, sizeof(struct multi_handle));
152 }