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