revert-dont-spawn-kernel-thread-for-rxk-listener-20020426
[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("$Header$");
14
15 #ifdef  KERNEL
16 #include "../rx/rx_kernel.h"
17 #include "../rx/rx_multi.h"
18 #else /* KERNEL */
19 # include "rx_user.h"
20 # include "rx_multi.h"
21 # include "rx_internal.h"
22 #endif /* KERNEL */
23
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 */
25
26 struct multi_handle *multi_Init(conns, nConns)
27     struct rx_connection **conns;
28     register int nConns;
29 {
30     void multi_Ready();
31     register struct rx_call **calls;
32     register short *ready;
33     register struct multi_handle *mh;
34     register int i;
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");
40     mh->calls = calls;
41     mh->nextReady = mh->firstNotReady = mh->ready = ready;
42     mh->nReady = 0;
43     mh->nConns = nConns;
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);
52     }
53     return mh;
54 }
55
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 */
57 int multi_Select(mh)
58     register struct multi_handle *mh;
59 {
60     int index;
61     SPLVAR;
62     NETPRI;
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 */
71             USERPRI;
72             return -1;
73         }
74 #ifdef RX_ENABLE_LOCKS
75         CV_WAIT(&mh->cv, &mh->lock);
76 #else /* RX_ENABLE_LOCKS */
77         osi_rxSleep(mh);
78 #endif /* RX_ENABLE_LOCKS */
79     }
80     index = *(mh->nextReady);
81     (mh->nextReady) += 1;
82 #ifdef RX_ENABLE_LOCKS
83     MUTEX_EXIT(&mh->lock);
84 #endif /* RX_ENABLE_LOCKS */
85     USERPRI;
86     return index;
87 }
88
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;
93     register int index;
94 {
95 #ifdef RX_ENABLE_LOCKS
96     MUTEX_ENTER(&mh->lock);
97 #endif /* RX_ENABLE_LOCKS */
98     *mh->firstNotReady++ = index;
99     mh->nReady++;
100 #ifdef RX_ENABLE_LOCKS
101     CV_SIGNAL(&mh->cv);
102     MUTEX_EXIT(&mh->lock);
103 #else /* RX_ENABLE_LOCKS */
104     osi_rxWakeup(mh);
105 #endif /* RX_ENABLE_LOCKS */
106 }
107
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;
111 {
112     register int i;
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);
117     }
118 #ifdef RX_ENABLE_LOCKS
119     MUTEX_DESTROY(&mh->lock);
120     CV_DESTROY(&mh->cv);
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));
125 }
126
127 /* ignores all remaining multiRx calls */
128 void multi_Finalize_Ignore(mh)
129 register struct multi_handle *mh;
130 {
131     register int i;
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);
136     }
137 #ifdef RX_ENABLE_LOCKS
138     MUTEX_DESTROY(&mh->lock);
139     CV_DESTROY(&mh->cv);
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));
144 }