1433d6423SLionel Sambuc
2433d6423SLionel Sambuc #include <minix/config.h>
3433d6423SLionel Sambuc #include <assert.h>
4433d6423SLionel Sambuc #include <sys/types.h>
5433d6423SLionel Sambuc #include <minix/const.h>
6433d6423SLionel Sambuc #include <minix/type.h>
7433d6423SLionel Sambuc
8433d6423SLionel Sambuc #include <stdlib.h>
9433d6423SLionel Sambuc #include <unistd.h>
10433d6423SLionel Sambuc #include <minix/syslib.h>
11433d6423SLionel Sambuc #include <minix/sysutil.h>
12433d6423SLionel Sambuc #include <minix/sys_config.h>
13433d6423SLionel Sambuc
14433d6423SLionel Sambuc #include <limits.h>
15433d6423SLionel Sambuc #include <errno.h>
16433d6423SLionel Sambuc
17433d6423SLionel Sambuc #define ASYN_NR (2*_NR_PROCS)
18433d6423SLionel Sambuc static asynmsg_t msgtable[ASYN_NR];
19433d6423SLionel Sambuc static int first_slot = 0, next_slot = 0;
20433d6423SLionel Sambuc static int initialized = 0;
21433d6423SLionel Sambuc
22433d6423SLionel Sambuc /*===========================================================================*
23433d6423SLionel Sambuc * asynsend3 *
24433d6423SLionel Sambuc *===========================================================================*/
asynsend3(dst,mp,fl)25433d6423SLionel Sambuc int asynsend3(dst, mp, fl)
26433d6423SLionel Sambuc endpoint_t dst;
27433d6423SLionel Sambuc message *mp;
28433d6423SLionel Sambuc int fl;
29433d6423SLionel Sambuc {
30433d6423SLionel Sambuc int i, r, src_ind, dst_ind;
31433d6423SLionel Sambuc unsigned flags;
32433d6423SLionel Sambuc static int inside = 0;
33d639cffeSCristiano Giuffrida int needack = 0;
34433d6423SLionel Sambuc
35433d6423SLionel Sambuc /* Debug printf() causes asynchronous sends? */
36433d6423SLionel Sambuc if (inside) /* Panic will not work either then, so exit */
37433d6423SLionel Sambuc exit(1);
38433d6423SLionel Sambuc
39433d6423SLionel Sambuc inside = 1;
40433d6423SLionel Sambuc
41433d6423SLionel Sambuc if(!initialized) {
42433d6423SLionel Sambuc /* Initialize table by marking all entries empty */
43433d6423SLionel Sambuc for (i = 0; i < ASYN_NR; i++) msgtable[i].flags = AMF_EMPTY;
44433d6423SLionel Sambuc
45433d6423SLionel Sambuc initialized = 1;
46433d6423SLionel Sambuc }
47433d6423SLionel Sambuc
48433d6423SLionel Sambuc /* Update first_slot. That is, find the first not-completed slot by the
49433d6423SLionel Sambuc * kernel since the last time we sent this table (e.g., the receiving end of
50433d6423SLionel Sambuc * the message wasn't ready yet).
51433d6423SLionel Sambuc */
52433d6423SLionel Sambuc for (; first_slot < next_slot; first_slot++) {
53433d6423SLionel Sambuc flags = msgtable[first_slot].flags;
54433d6423SLionel Sambuc if ((flags & (AMF_VALID|AMF_DONE)) == (AMF_VALID|AMF_DONE)) {
55433d6423SLionel Sambuc /* Marked in use by us (VALID) and processed by the kernel */
56433d6423SLionel Sambuc if (msgtable[first_slot].result != OK) {
57*6afe2674SJean-Baptiste Boric #ifdef DEBUG
58433d6423SLionel Sambuc printf("asynsend: found entry %d with error %d\n",
59433d6423SLionel Sambuc first_slot, msgtable[first_slot].result);
60433d6423SLionel Sambuc #endif
61433d6423SLionel Sambuc needack = (flags & (AMF_NOTIFY|AMF_NOTIFY_ERR));
62433d6423SLionel Sambuc }
63433d6423SLionel Sambuc continue;
64433d6423SLionel Sambuc }
65433d6423SLionel Sambuc
66433d6423SLionel Sambuc if (flags != AMF_EMPTY)
67433d6423SLionel Sambuc /* Found first not-completed table entry */
68433d6423SLionel Sambuc break;
69433d6423SLionel Sambuc }
70433d6423SLionel Sambuc
71433d6423SLionel Sambuc /* Reset to the beginning of the table when all messages are completed */
72433d6423SLionel Sambuc if (first_slot >= next_slot && !needack)
73433d6423SLionel Sambuc next_slot = first_slot = 0;
74433d6423SLionel Sambuc
75433d6423SLionel Sambuc /* Can the table handle one more message? */
76433d6423SLionel Sambuc if (next_slot >= ASYN_NR) {
77433d6423SLionel Sambuc /* We're full; tell the kernel to stop processing for now */
78433d6423SLionel Sambuc if ((r = ipc_senda(NULL, 0)) != OK)
79433d6423SLionel Sambuc panic("asynsend: ipc_senda failed: %d", r);
80433d6423SLionel Sambuc
81433d6423SLionel Sambuc /* Move all unprocessed messages to the beginning */
82433d6423SLionel Sambuc dst_ind = 0;
83433d6423SLionel Sambuc for (src_ind = first_slot; src_ind < next_slot; src_ind++) {
84433d6423SLionel Sambuc flags = msgtable[src_ind].flags;
85433d6423SLionel Sambuc
86433d6423SLionel Sambuc /* Skip empty entries */
87433d6423SLionel Sambuc if (flags == AMF_EMPTY) continue;
88433d6423SLionel Sambuc
89433d6423SLionel Sambuc /* and completed entries only if result is OK or if error
90433d6423SLionel Sambuc * doesn't need to be acknowledged */
91433d6423SLionel Sambuc if ((flags & (AMF_VALID|AMF_DONE)) == (AMF_VALID|AMF_DONE)) {
92433d6423SLionel Sambuc if (msgtable[src_ind].result == OK)
93433d6423SLionel Sambuc continue;
94433d6423SLionel Sambuc else {
95*6afe2674SJean-Baptiste Boric #ifdef DEBUG
96433d6423SLionel Sambuc printf(
97433d6423SLionel Sambuc "asynsend: found entry %d with error %d\n",
98433d6423SLionel Sambuc src_ind, msgtable[src_ind].result);
99433d6423SLionel Sambuc #endif
100433d6423SLionel Sambuc if (!(flags & (AMF_NOTIFY|AMF_NOTIFY_ERR)))
101433d6423SLionel Sambuc /* Don't need to ack this error */
102433d6423SLionel Sambuc continue;
103433d6423SLionel Sambuc }
104433d6423SLionel Sambuc }
105433d6423SLionel Sambuc
106433d6423SLionel Sambuc
107433d6423SLionel Sambuc /* Copy/move in use entry */
108*6afe2674SJean-Baptiste Boric #ifdef DEBUG
109433d6423SLionel Sambuc printf("asynsend: copying entry %d to %d\n", src_ind, dst_ind);
110433d6423SLionel Sambuc #endif
111433d6423SLionel Sambuc if (src_ind != dst_ind) msgtable[dst_ind] = msgtable[src_ind];
112433d6423SLionel Sambuc dst_ind++;
113433d6423SLionel Sambuc }
114433d6423SLionel Sambuc
115433d6423SLionel Sambuc /* Mark unused entries empty */
116433d6423SLionel Sambuc for (i = dst_ind; i < ASYN_NR; i++) msgtable[i].flags = AMF_EMPTY;
117433d6423SLionel Sambuc
118433d6423SLionel Sambuc first_slot = 0;
119433d6423SLionel Sambuc next_slot = dst_ind;
120433d6423SLionel Sambuc if (next_slot >= ASYN_NR) /* Cleanup failed */
121433d6423SLionel Sambuc panic("asynsend: msgtable full");
122433d6423SLionel Sambuc }
123433d6423SLionel Sambuc
124433d6423SLionel Sambuc fl |= AMF_VALID; /* Mark in use */
125433d6423SLionel Sambuc msgtable[next_slot].dst = dst;
126433d6423SLionel Sambuc msgtable[next_slot].msg = *mp;
127a082b2afSDavid van Moolenbroek __insn_barrier();
128433d6423SLionel Sambuc msgtable[next_slot].flags = fl; /* Has to be last. The kernel
129433d6423SLionel Sambuc * scans this table while we
130433d6423SLionel Sambuc * are sleeping.
131433d6423SLionel Sambuc */
132433d6423SLionel Sambuc next_slot++;
133433d6423SLionel Sambuc
134d639cffeSCristiano Giuffrida /* Reload. */
135d639cffeSCristiano Giuffrida inside = 0;
136d639cffeSCristiano Giuffrida r = senda_reload();
137d639cffeSCristiano Giuffrida
138d639cffeSCristiano Giuffrida return r;
139d639cffeSCristiano Giuffrida }
140d639cffeSCristiano Giuffrida
141d639cffeSCristiano Giuffrida /*===========================================================================*
142d639cffeSCristiano Giuffrida * senda_reload *
143d639cffeSCristiano Giuffrida *===========================================================================*/
senda_reload()144d639cffeSCristiano Giuffrida int senda_reload()
145d639cffeSCristiano Giuffrida {
146d639cffeSCristiano Giuffrida int len;
147d639cffeSCristiano Giuffrida
148433d6423SLionel Sambuc assert(next_slot >= first_slot);
149433d6423SLionel Sambuc len = next_slot - first_slot;
150433d6423SLionel Sambuc assert(first_slot + len <= ASYN_NR);
151433d6423SLionel Sambuc assert(len >= 0);
152433d6423SLionel Sambuc
153433d6423SLionel Sambuc /* Tell the kernel to rescan the table */
154433d6423SLionel Sambuc return ipc_senda(&msgtable[first_slot], len);
155433d6423SLionel Sambuc }
156433d6423SLionel Sambuc
157433d6423SLionel Sambuc /*===========================================================================*
158433d6423SLionel Sambuc * asyn_geterror *
159433d6423SLionel Sambuc *===========================================================================*/
asyn_geterror(endpoint_t * dst,message * msg,int * err)160433d6423SLionel Sambuc int asyn_geterror(endpoint_t *dst, message *msg, int *err)
161433d6423SLionel Sambuc {
162433d6423SLionel Sambuc int src_ind, flags, result;
163433d6423SLionel Sambuc
164433d6423SLionel Sambuc if (!initialized) return(0);
165433d6423SLionel Sambuc
166433d6423SLionel Sambuc for (src_ind = 0; src_ind < next_slot; src_ind++) {
167433d6423SLionel Sambuc flags = msgtable[src_ind].flags;
168433d6423SLionel Sambuc result = msgtable[src_ind].result;
169433d6423SLionel Sambuc
170433d6423SLionel Sambuc /* Find a message that has been completed with an error */
171433d6423SLionel Sambuc if ((flags & (AMF_VALID|AMF_DONE)) == (AMF_VALID|AMF_DONE)) {
172433d6423SLionel Sambuc if (result != OK && (flags & (AMF_NOTIFY|AMF_NOTIFY_ERR))) {
173433d6423SLionel Sambuc /* Found one */
174433d6423SLionel Sambuc if (dst != NULL) *dst = msgtable[src_ind].dst;
175433d6423SLionel Sambuc if (msg != NULL) *msg = msgtable[src_ind].msg;
176433d6423SLionel Sambuc if (err != NULL) *err = result;
177433d6423SLionel Sambuc
178433d6423SLionel Sambuc /* Acknowledge error so it can be cleaned up upon next
179433d6423SLionel Sambuc * asynsend */
180433d6423SLionel Sambuc msgtable[src_ind].result = OK;
181433d6423SLionel Sambuc
182433d6423SLionel Sambuc return(1);
183433d6423SLionel Sambuc }
184433d6423SLionel Sambuc }
185433d6423SLionel Sambuc }
186433d6423SLionel Sambuc
187433d6423SLionel Sambuc return(0);
188433d6423SLionel Sambuc }
189433d6423SLionel Sambuc
190