1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
|
#include <minix/config.h>
#include <assert.h>
#include <sys/types.h>
#include <minix/const.h>
#include <minix/type.h>
#include <stdlib.h>
#include <unistd.h>
#include <minix/syslib.h>
#include <minix/sysutil.h>
#include <minix/sys_config.h>
#include <limits.h>
#include <errno.h>
#define ASYN_NR (2*_NR_PROCS)
static asynmsg_t msgtable[ASYN_NR];
static int first_slot = 0, next_slot = 0;
static int initialized = 0;
/*===========================================================================*
* asynsend3 *
*===========================================================================*/
int asynsend3(dst, mp, fl)
endpoint_t dst;
message *mp;
int fl;
{
int i, r, src_ind, dst_ind;
unsigned flags;
static int inside = 0;
int needack = 0;
/* Debug printf() causes asynchronous sends? */
if (inside) /* Panic will not work either then, so exit */
exit(1);
inside = 1;
if(!initialized) {
/* Initialize table by marking all entries empty */
for (i = 0; i < ASYN_NR; i++) msgtable[i].flags = AMF_EMPTY;
initialized = 1;
}
/* Update first_slot. That is, find the first not-completed slot by the
* kernel since the last time we sent this table (e.g., the receiving end of
* the message wasn't ready yet).
*/
for (; first_slot < next_slot; first_slot++) {
flags = msgtable[first_slot].flags;
if ((flags & (AMF_VALID|AMF_DONE)) == (AMF_VALID|AMF_DONE)) {
/* Marked in use by us (VALID) and processed by the kernel */
if (msgtable[first_slot].result != OK) {
#ifdef DEBUG
printf("asynsend: found entry %d with error %d\n",
first_slot, msgtable[first_slot].result);
#endif
needack = (flags & (AMF_NOTIFY|AMF_NOTIFY_ERR));
}
continue;
}
if (flags != AMF_EMPTY)
/* Found first not-completed table entry */
break;
}
/* Reset to the beginning of the table when all messages are completed */
if (first_slot >= next_slot && !needack)
next_slot = first_slot = 0;
/* Can the table handle one more message? */
if (next_slot >= ASYN_NR) {
/* We're full; tell the kernel to stop processing for now */
if ((r = ipc_senda(NULL, 0)) != OK)
panic("asynsend: ipc_senda failed: %d", r);
/* Move all unprocessed messages to the beginning */
dst_ind = 0;
for (src_ind = first_slot; src_ind < next_slot; src_ind++) {
flags = msgtable[src_ind].flags;
/* Skip empty entries */
if (flags == AMF_EMPTY) continue;
/* and completed entries only if result is OK or if error
* doesn't need to be acknowledged */
if ((flags & (AMF_VALID|AMF_DONE)) == (AMF_VALID|AMF_DONE)) {
if (msgtable[src_ind].result == OK)
continue;
else {
#ifdef DEBUG
printf(
"asynsend: found entry %d with error %d\n",
src_ind, msgtable[src_ind].result);
#endif
if (!(flags & (AMF_NOTIFY|AMF_NOTIFY_ERR)))
/* Don't need to ack this error */
continue;
}
}
/* Copy/move in use entry */
#ifdef DEBUG
printf("asynsend: copying entry %d to %d\n", src_ind, dst_ind);
#endif
if (src_ind != dst_ind) msgtable[dst_ind] = msgtable[src_ind];
dst_ind++;
}
/* Mark unused entries empty */
for (i = dst_ind; i < ASYN_NR; i++) msgtable[i].flags = AMF_EMPTY;
first_slot = 0;
next_slot = dst_ind;
if (next_slot >= ASYN_NR) /* Cleanup failed */
panic("asynsend: msgtable full");
}
fl |= AMF_VALID; /* Mark in use */
msgtable[next_slot].dst = dst;
msgtable[next_slot].msg = *mp;
__insn_barrier();
msgtable[next_slot].flags = fl; /* Has to be last. The kernel
* scans this table while we
* are sleeping.
*/
next_slot++;
/* Reload. */
inside = 0;
r = senda_reload();
return r;
}
/*===========================================================================*
* senda_reload *
*===========================================================================*/
int senda_reload()
{
int len;
assert(next_slot >= first_slot);
len = next_slot - first_slot;
assert(first_slot + len <= ASYN_NR);
assert(len >= 0);
/* Tell the kernel to rescan the table */
return ipc_senda(&msgtable[first_slot], len);
}
/*===========================================================================*
* asyn_geterror *
*===========================================================================*/
int asyn_geterror(endpoint_t *dst, message *msg, int *err)
{
int src_ind, flags, result;
if (!initialized) return(0);
for (src_ind = 0; src_ind < next_slot; src_ind++) {
flags = msgtable[src_ind].flags;
result = msgtable[src_ind].result;
/* Find a message that has been completed with an error */
if ((flags & (AMF_VALID|AMF_DONE)) == (AMF_VALID|AMF_DONE)) {
if (result != OK && (flags & (AMF_NOTIFY|AMF_NOTIFY_ERR))) {
/* Found one */
if (dst != NULL) *dst = msgtable[src_ind].dst;
if (msg != NULL) *msg = msgtable[src_ind].msg;
if (err != NULL) *err = result;
/* Acknowledge error so it can be cleaned up upon next
* asynsend */
msgtable[src_ind].result = OK;
return(1);
}
}
}
return(0);
}
|