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