xref: /minix3/minix/lib/libsys/asynsend.c (revision 6afe26749abc49c059b9b20284d55aaa3e3ef981)
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