-
#define _MINIX 1
#define _SYSTEM 1
#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;
-
- /* printf() causes asynsend? */
- if(inside) {
- exit(1);
- }
-
- inside = 1;
-
- if(first) {
- int i;
- for(i = 0; i < ASYN_NR; i++) {
- msgtable[i].flags = AMF_EMPTY;
+ int i, r, src_ind, dst_ind;
+ unsigned flags;
+ static int inside = 0;
+ int len, needack = 0;
+
+ /* Debug printf() causes asynchronous sends? */
+ if (inside) /* Panic will not work either then, so exit */
+ exit(1);
+
+ inside = 1;
+
+ 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);
-#endif
- }
- continue;
- }
- if (flags == AMF_EMPTY)
- continue;
-#if 0
- printf("asynsend: copying entry %d to %d\n",
- src_ind, dst_ind);
+ /* Copy/move in use entry */
+#if NDEBUG
+ 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(next_slot >= first_slot);
+ len = next_slot - first_slot;
+ assert(first_slot + len <= ASYN_NR);
+ assert(len >= 0);
+
+ inside = 0;
+
+ /* Tell the kernel to rescan the table */
+ return senda(&msgtable[first_slot], len);
+}
- assert(first_slot < ASYN_NR);
- assert(next_slot >= first_slot);
- len = next_slot-first_slot;
- assert(first_slot + len <= ASYN_NR);
+/*===========================================================================*
+ * 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;
- /* Tell the kernel to rescan the table */
- r = senda(msgtable+first_slot, len);
+ /* 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;
- inside = 0;
+ /* Acknowledge error so it can be cleaned up upon next
+ * asynsend */
+ msgtable[src_ind].result = OK;
+
+ return(1);
+ }
+ }
+ }
- return r;
+ return(0);
}