2 #include <minix/config.h>
5 #include <minix/const.h>
6 #include <minix/type.h>
10 #include <minix/syslib.h>
11 #include <minix/sysutil.h>
12 #include <minix/sys_config.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 /*===========================================================================*
24 *===========================================================================*/
25 int asynsend3(dst
, mp
, fl
)
30 int i
, r
, src_ind
, dst_ind
;
32 static int inside
= 0;
35 /* Debug printf() causes asynchronous sends? */
36 if (inside
) /* Panic will not work either then, so exit */
42 /* Initialize table by marking all entries empty */
43 for (i
= 0; i
< ASYN_NR
; i
++) msgtable
[i
].flags
= AMF_EMPTY
;
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
) {
58 printf("asynsend: found entry %d with error %d\n",
59 first_slot
, msgtable
[first_slot
].result
);
61 needack
= (flags
& (AMF_NOTIFY
|AMF_NOTIFY_ERR
));
66 if (flags
!= AMF_EMPTY
)
67 /* Found first not-completed table entry */
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 */
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
)
97 "asynsend: found entry %d with error %d\n",
98 src_ind
, msgtable
[src_ind
].result
);
100 if (!(flags
& (AMF_NOTIFY
|AMF_NOTIFY_ERR
)))
101 /* Don't need to ack this error */
107 /* Copy/move in use entry */
109 printf("asynsend: copying entry %d to %d\n", src_ind
, dst_ind
);
111 if (src_ind
!= dst_ind
) msgtable
[dst_ind
] = msgtable
[src_ind
];
115 /* Mark unused entries empty */
116 for (i
= dst_ind
; i
< ASYN_NR
; i
++) msgtable
[i
].flags
= AMF_EMPTY
;
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
133 assert(next_slot
>= first_slot
);
134 len
= next_slot
- first_slot
;
135 assert(first_slot
+ len
<= ASYN_NR
);
140 /* Tell the kernel to rescan the table */
141 return ipc_senda(&msgtable
[first_slot
], len
);
144 /*===========================================================================*
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
))) {
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
167 msgtable
[src_ind
].result
= OK
;