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