Enable a process to find out what the error code was when delivery of an
asynchronous message resulted in an error. The model here is that: - Iff a sender wishes to be notified, the sender MUST check for errors BEFORE sending another asynchronous message. The reason is that in order to remember the error code, we can't clean up the message table and hence we risk running out of table space. This is less of a problem when the sender enables notifications only for errors.
This commit is contained in:
parent
7457cbe62f
commit
2cde22ee10
2 changed files with 129 additions and 89 deletions
|
@ -68,6 +68,7 @@ _PROTOTYPE( void get_randomness, (struct k_randomness *, int));
|
|||
|
||||
#define asynsend(ep, msg) asynsend3(ep, msg, 0)
|
||||
_PROTOTYPE( int asynsend3, (endpoint_t ep, message *msg, int flags));
|
||||
_PROTOTYPE( int asyn_geterror, (endpoint_t *dst, message *msg, int *err));
|
||||
|
||||
#define ASSERT(c) if(!(c)) { panic("%s:%d: assert %s failed", __FILE__, __LINE__, #c); }
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
#define _MINIX 1
|
||||
#define _SYSTEM 1
|
||||
|
||||
|
@ -20,121 +19,161 @@
|
|||
|
||||
#define ASYN_NR (2*_NR_PROCS)
|
||||
PRIVATE asynmsg_t msgtable[ASYN_NR];
|
||||
PRIVATE int first_slot= 0, next_slot= 0;
|
||||
PRIVATE int first_slot = 0, next_slot = 0;
|
||||
PRIVATE int initialized = 0;
|
||||
|
||||
/*===========================================================================*
|
||||
* asynsend3 *
|
||||
*===========================================================================*/
|
||||
PUBLIC int asynsend3(dst, mp, fl)
|
||||
endpoint_t dst;
|
||||
message *mp;
|
||||
int fl;
|
||||
{
|
||||
int r, src_ind, dst_ind;
|
||||
unsigned flags;
|
||||
static int first = 1;
|
||||
static int inside = 0;
|
||||
int len;
|
||||
int i, r, src_ind, dst_ind;
|
||||
unsigned flags;
|
||||
static int inside = 0;
|
||||
int len, needack = 0;
|
||||
|
||||
/* printf() causes asynsend? */
|
||||
if(inside) {
|
||||
exit(1);
|
||||
}
|
||||
/* Debug printf() causes asynchronous sends? */
|
||||
if (inside) /* Panic will not work either then, so exit */
|
||||
exit(1);
|
||||
|
||||
inside = 1;
|
||||
inside = 1;
|
||||
|
||||
if(first) {
|
||||
int i;
|
||||
for(i = 0; i < ASYN_NR; i++) {
|
||||
msgtable[i].flags = AMF_EMPTY;
|
||||
if(!initialized) {
|
||||
/* Initialize table by marking all entries empty */
|
||||
for (i = 0; i < ASYN_NR; i++) msgtable[i].flags = AMF_EMPTY;
|
||||
|
||||
initialized = 1;
|
||||
}
|
||||
|
||||
/* Update first_slot. That is, find the first not-completed slot by the
|
||||
* kernel since the last time we sent this table (e.g., the receiving end of
|
||||
* the message wasn't ready yet).
|
||||
*/
|
||||
for (; first_slot < next_slot; first_slot++) {
|
||||
flags = msgtable[first_slot].flags;
|
||||
if ((flags & (AMF_VALID|AMF_DONE)) == (AMF_VALID|AMF_DONE)) {
|
||||
/* Marked in use by us (VALID) and processed by the kernel */
|
||||
if (msgtable[first_slot].result != OK) {
|
||||
#if NDEBUG
|
||||
printf("asynsend: found entry %d with error %d\n",
|
||||
first_slot, msgtable[first_slot].result);
|
||||
#endif
|
||||
needack = (flags & (AMF_NOTIFY|AMF_NOTIFY_ERR));
|
||||
}
|
||||
first = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Update first_slot */
|
||||
for (; first_slot < next_slot; first_slot++)
|
||||
{
|
||||
flags= msgtable[first_slot].flags;
|
||||
if ((flags & (AMF_VALID|AMF_DONE)) == (AMF_VALID|AMF_DONE))
|
||||
{
|
||||
if (msgtable[first_slot].result != OK)
|
||||
{
|
||||
#if 0
|
||||
if (flags != AMF_EMPTY)
|
||||
/* Found first not-completed table entry */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Reset to the beginning of the table when all messages are completed */
|
||||
if (first_slot >= next_slot && !needack)
|
||||
next_slot = first_slot = 0;
|
||||
|
||||
/* Can the table handle one more message? */
|
||||
if (next_slot >= ASYN_NR) {
|
||||
/* We're full; tell the kernel to stop processing for now */
|
||||
if ((r = senda(NULL, 0)) != OK)
|
||||
panic("asynsend: senda failed: %d", r);
|
||||
|
||||
/* Move all unprocessed messages to the beginning */
|
||||
dst_ind = 0;
|
||||
for (src_ind = first_slot; src_ind < next_slot; src_ind++) {
|
||||
flags = msgtable[src_ind].flags;
|
||||
|
||||
/* Skip empty entries */
|
||||
if (flags == AMF_EMPTY) continue;
|
||||
|
||||
/* and completed entries only if result is OK or if error
|
||||
* doesn't need to be acknowledged */
|
||||
if ((flags & (AMF_VALID|AMF_DONE)) == (AMF_VALID|AMF_DONE)) {
|
||||
if (msgtable[src_ind].result == OK)
|
||||
continue;
|
||||
else {
|
||||
#if NDEBUG
|
||||
printf(
|
||||
"asynsend: found completed entry %d with error %d\n",
|
||||
first_slot,
|
||||
msgtable[first_slot].result);
|
||||
"asynsend: found entry %d with error %d\n",
|
||||
src_ind, msgtable[src_ind].result);
|
||||
#endif
|
||||
if (!(flags & (AMF_NOTIFY|AMF_NOTIFY_ERR)))
|
||||
/* Don't need to ack this error */
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (flags != AMF_EMPTY)
|
||||
break;
|
||||
}
|
||||
|
||||
if (first_slot >= next_slot)
|
||||
{
|
||||
/* Reset first_slot and next_slot */
|
||||
next_slot= first_slot= 0;
|
||||
}
|
||||
|
||||
if (next_slot >= ASYN_NR)
|
||||
{
|
||||
/* Tell the kernel to stop processing */
|
||||
r= senda(NULL, 0);
|
||||
if (r != OK)
|
||||
panic("asynsend: senda failed: %d", r);
|
||||
|
||||
dst_ind= 0;
|
||||
for (src_ind= first_slot; src_ind<next_slot; src_ind++)
|
||||
{
|
||||
flags= msgtable[src_ind].flags;
|
||||
if ((flags & (AMF_VALID|AMF_DONE)) ==
|
||||
(AMF_VALID|AMF_DONE))
|
||||
{
|
||||
if (msgtable[src_ind].result != OK)
|
||||
{
|
||||
#if 0
|
||||
printf(
|
||||
"asynsend: found completed entry %d with error %d\n",
|
||||
src_ind,
|
||||
msgtable[src_ind].result);
|
||||
/* Copy/move in use entry */
|
||||
#if NDEBUG
|
||||
printf("asynsend: copying entry %d to %d\n", src_ind, dst_ind);
|
||||
#endif
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (flags == AMF_EMPTY)
|
||||
continue;
|
||||
#if 0
|
||||
printf("asynsend: copying entry %d to %d\n",
|
||||
src_ind, dst_ind);
|
||||
#endif
|
||||
if (src_ind != dst_ind)
|
||||
msgtable[dst_ind]= msgtable[src_ind];
|
||||
if (src_ind != dst_ind) msgtable[dst_ind] = msgtable[src_ind];
|
||||
dst_ind++;
|
||||
}
|
||||
first_slot= 0;
|
||||
next_slot= dst_ind;
|
||||
if (next_slot >= ASYN_NR)
|
||||
panic("asynsend: msgtable full");
|
||||
}
|
||||
|
||||
fl |= AMF_VALID;
|
||||
msgtable[next_slot].dst= dst;
|
||||
msgtable[next_slot].msg= *mp;
|
||||
msgtable[next_slot].flags= fl; /* Has to be last. The kernel
|
||||
/* Mark unused entries empty */
|
||||
for (i = dst_ind; i < ASYN_NR; i++) msgtable[i].flags = AMF_EMPTY;
|
||||
|
||||
first_slot = 0;
|
||||
next_slot = dst_ind;
|
||||
if (next_slot >= ASYN_NR) /* Cleanup failed */
|
||||
panic("asynsend: msgtable full");
|
||||
}
|
||||
|
||||
fl |= AMF_VALID; /* Mark in use */
|
||||
msgtable[next_slot].dst = dst;
|
||||
msgtable[next_slot].msg = *mp;
|
||||
msgtable[next_slot].flags = fl; /* Has to be last. The kernel
|
||||
* scans this table while we
|
||||
* are sleeping.
|
||||
*/
|
||||
next_slot++;
|
||||
next_slot++;
|
||||
|
||||
assert(first_slot < ASYN_NR);
|
||||
assert(next_slot >= first_slot);
|
||||
len = next_slot-first_slot;
|
||||
assert(first_slot + len <= ASYN_NR);
|
||||
assert(next_slot >= first_slot);
|
||||
len = next_slot - first_slot;
|
||||
assert(first_slot + len <= ASYN_NR);
|
||||
assert(len >= 0);
|
||||
|
||||
/* Tell the kernel to rescan the table */
|
||||
r = senda(msgtable+first_slot, len);
|
||||
inside = 0;
|
||||
|
||||
inside = 0;
|
||||
|
||||
return r;
|
||||
/* Tell the kernel to rescan the table */
|
||||
return senda(&msgtable[first_slot], len);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* asyn_geterror *
|
||||
*===========================================================================*/
|
||||
PUBLIC int asyn_geterror(endpoint_t *dst, message *msg, int *err)
|
||||
{
|
||||
int src_ind, flags, result;
|
||||
|
||||
if (!initialized) return(0);
|
||||
|
||||
for (src_ind = 0; src_ind < next_slot; src_ind++) {
|
||||
flags = msgtable[src_ind].flags;
|
||||
result = msgtable[src_ind].result;
|
||||
|
||||
/* Find a message that has been completed with an error */
|
||||
if ((flags & (AMF_VALID|AMF_DONE)) == (AMF_VALID|AMF_DONE)) {
|
||||
if (result != OK && (flags & (AMF_NOTIFY|AMF_NOTIFY_ERR))) {
|
||||
/* Found one */
|
||||
if (dst != NULL) *dst = msgtable[src_ind].dst;
|
||||
if (msg != NULL) *msg = msgtable[src_ind].msg;
|
||||
if (err != NULL) *err = result;
|
||||
|
||||
/* Acknowledge error so it can be cleaned up upon next
|
||||
* asynsend */
|
||||
msgtable[src_ind].result = OK;
|
||||
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue