2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include <afs/param.h>
14 # include "afs/sysincludes.h"
23 * multi.c and multi.h, together with some rxgen hooks, provide a way of
24 * making multiple, but similar, rx calls to multiple hosts simultaneously
28 multi_Init(struct rx_connection
**conns
, int nConns
)
30 struct rx_call
**calls
;
32 struct multi_handle
*mh
;
36 * Note: all structures that are possibly referenced by other
37 * processes must be allocated. In some kernels variables allocated on
38 * a process stack will not be accessible to other processes
41 calls
= osi_Alloc(sizeof(struct rx_call
*) * nConns
);
42 ready
= osi_Alloc(sizeof(short) * nConns
);
43 mh
= osi_Alloc(sizeof(struct multi_handle
));
44 if (!calls
|| !ready
|| !mh
)
45 osi_Panic("multi_Rx: no mem\n");
46 memset(mh
, 0, sizeof(struct multi_handle
));
48 mh
->nextReady
= mh
->firstNotReady
= mh
->ready
= ready
;
52 MUTEX_INIT(&mh
->lock
, "rx_multi_lock", MUTEX_DEFAULT
, 0);
53 CV_INIT(&mh
->cv
, "rx_multi_cv", CV_DEFAULT
, 0);
54 for (i
= 0; i
< nConns
; i
++) {
56 call
= mh
->calls
[i
] = rx_NewCall(conns
[i
]);
57 rx_SetArrivalProc(call
, multi_Ready
, (void *) mh
, i
);
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 */
64 multi_Select(struct multi_handle
*mh
)
69 MUTEX_ENTER(&mh
->lock
);
70 while (mh
->nextReady
== mh
->firstNotReady
) {
71 if (mh
->nReady
== mh
->nConns
) {
72 MUTEX_EXIT(&mh
->lock
);
76 #ifdef RX_ENABLE_LOCKS
77 CV_WAIT(&mh
->cv
, &mh
->lock
);
78 #else /* RX_ENABLE_LOCKS */
80 #endif /* RX_ENABLE_LOCKS */
82 index
= *(mh
->nextReady
);
84 MUTEX_EXIT(&mh
->lock
);
89 /* Called by Rx when the first reply packet of a call is received, or the call is aborted. */
91 multi_Ready(struct rx_call
*call
, void *amh
,
94 struct multi_handle
*mh
= (struct multi_handle
*)amh
;
95 MUTEX_ENTER(&mh
->lock
);
96 *mh
->firstNotReady
++ = index
;
98 #ifdef RX_ENABLE_LOCKS
100 #else /* RX_ENABLE_LOCKS */
102 #endif /* RX_ENABLE_LOCKS */
103 MUTEX_EXIT(&mh
->lock
);
106 /* Called when the multi rx call is over, or when the user aborts it (by using the macro multi_Abort) */
108 multi_Finalize(struct multi_handle
*mh
)
111 int nCalls
= mh
->nConns
;
112 for (i
= 0; i
< nCalls
; i
++) {
113 struct rx_call
*call
= mh
->calls
[i
];
115 rx_EndCall(call
, RX_USER_ABORT
);
117 MUTEX_DESTROY(&mh
->lock
);
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
));
124 /* ignores all remaining multiRx calls */
126 multi_Finalize_Ignore(struct multi_handle
*mh
)
129 int nCalls
= mh
->nConns
;
130 for (i
= 0; i
< nCalls
; i
++) {
131 struct rx_call
*call
= mh
->calls
[i
];
135 MUTEX_DESTROY(&mh
->lock
);
137 osi_Free(mh
->calls
, sizeof(struct rx_call
*) * nCalls
);
138 osi_Free(mh
->ready
, sizeof(short) * nCalls
);
139 osi_Free(mh
, sizeof(struct multi_handle
));