Zero rx_multi_lock before initializing it
[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     memset(mh, 0, sizeof(struct multi_handle));
46     mh->calls = calls;
47     mh->nextReady = mh->firstNotReady = mh->ready = ready;
48     mh->nReady = 0;
49     mh->nConns = nConns;
50
51 #ifdef RX_ENABLE_LOCKS
52     MUTEX_INIT(&mh->lock, "rx_multi_lock", MUTEX_DEFAULT, 0);
53     CV_INIT(&mh->cv, "rx_multi_cv", CV_DEFAULT, 0);
54 #endif /* RX_ENABLE_LOCKS */
55     for (i = 0; i < nConns; i++) {
56         struct rx_call *call;
57         call = mh->calls[i] = rx_NewCall(conns[i]);
58         rx_SetArrivalProc(call, multi_Ready, (void *) mh, i);
59     }
60     return mh;
61 }
62
63 /* Return the user's connection index of the most recently ready call; that is, a call that has received at least one reply packet */
64 int
65 multi_Select(struct multi_handle *mh)
66 {
67     int index;
68     SPLVAR;
69     NETPRI;
70 #ifdef RX_ENABLE_LOCKS
71     MUTEX_ENTER(&mh->lock);
72 #endif /* RX_ENABLE_LOCKS */
73     while (mh->nextReady == mh->firstNotReady) {
74         if (mh->nReady == mh->nConns) {
75 #ifdef RX_ENABLE_LOCKS
76             MUTEX_EXIT(&mh->lock);
77 #endif /* RX_ENABLE_LOCKS */
78             USERPRI;
79             return -1;
80         }
81 #ifdef RX_ENABLE_LOCKS
82         CV_WAIT(&mh->cv, &mh->lock);
83 #else /* RX_ENABLE_LOCKS */
84         osi_rxSleep(mh);
85 #endif /* RX_ENABLE_LOCKS */
86     }
87     index = *(mh->nextReady);
88     (mh->nextReady) += 1;
89 #ifdef RX_ENABLE_LOCKS
90     MUTEX_EXIT(&mh->lock);
91 #endif /* RX_ENABLE_LOCKS */
92     USERPRI;
93     return index;
94 }
95
96 /* Called by Rx when the first reply packet of a call is received, or the call is aborted. */
97 void
98 multi_Ready(struct rx_call *call, void *amh,
99             int index)
100 {
101     struct multi_handle *mh = (struct multi_handle *)amh;
102 #ifdef RX_ENABLE_LOCKS
103     MUTEX_ENTER(&mh->lock);
104 #endif /* RX_ENABLE_LOCKS */
105     *mh->firstNotReady++ = index;
106     mh->nReady++;
107 #ifdef RX_ENABLE_LOCKS
108     CV_SIGNAL(&mh->cv);
109     MUTEX_EXIT(&mh->lock);
110 #else /* RX_ENABLE_LOCKS */
111     osi_rxWakeup(mh);
112 #endif /* RX_ENABLE_LOCKS */
113 }
114
115 /* Called when the multi rx call is over, or when the user aborts it (by using the macro multi_Abort) */
116 void
117 multi_Finalize(struct multi_handle *mh)
118 {
119     int i;
120     int nCalls = mh->nConns;
121     for (i = 0; i < nCalls; i++) {
122         struct rx_call *call = mh->calls[i];
123         if (call)
124             rx_EndCall(call, RX_USER_ABORT);
125     }
126 #ifdef RX_ENABLE_LOCKS
127     MUTEX_DESTROY(&mh->lock);
128     CV_DESTROY(&mh->cv);
129 #endif /* RX_ENABLE_LOCKS */
130     osi_Free(mh->calls, sizeof(struct rx_call *) * nCalls);
131     osi_Free(mh->ready, sizeof(short *) * nCalls);
132     osi_Free(mh, sizeof(struct multi_handle));
133 }
134
135 /* ignores all remaining multiRx calls */
136 void
137 multi_Finalize_Ignore(struct multi_handle *mh)
138 {
139     int i;
140     int nCalls = mh->nConns;
141     for (i = 0; i < nCalls; i++) {
142         struct rx_call *call = mh->calls[i];
143         if (call)
144             rx_EndCall(call, 0);
145     }
146 #ifdef RX_ENABLE_LOCKS
147     MUTEX_DESTROY(&mh->lock);
148     CV_DESTROY(&mh->cv);
149 #endif /* RX_ENABLE_LOCKS */
150     osi_Free(mh->calls, sizeof(struct rx_call *) * nCalls);
151     osi_Free(mh->ready, sizeof(short *) * nCalls);
152     osi_Free(mh, sizeof(struct multi_handle));
153 }