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