1 2 #include <minix/config.h> 3 #include <assert.h> 4 #include <sys/types.h> 5 #include <minix/const.h> 6 #include <minix/type.h> 7 8 #include <stdlib.h> 9 #include <unistd.h> 10 #include <minix/syslib.h> 11 #include <minix/sysutil.h> 12 #include <minix/sys_config.h> 13 14 #include <limits.h> 15 #include <errno.h> 16 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; 21 22 /*===========================================================================* 23 * asynsend3 * 24 *===========================================================================*/ 25 int asynsend3(dst, mp, fl) 26 endpoint_t dst; 27 message *mp; 28 int fl; 29 { 30 int i, r, src_ind, dst_ind; 31 unsigned flags; 32 static int inside = 0; 33 int needack = 0; 34 35 /* Debug printf() causes asynchronous sends? */ 36 if (inside) /* Panic will not work either then, so exit */ 37 exit(1); 38 39 inside = 1; 40 41 if(!initialized) { 42 /* Initialize table by marking all entries empty */ 43 for (i = 0; i < ASYN_NR; i++) msgtable[i].flags = AMF_EMPTY; 44 45 initialized = 1; 46 } 47 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). 51 */ 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) { 57 #ifdef DEBUG 58 printf("asynsend: found entry %d with error %d\n", 59 first_slot, msgtable[first_slot].result); 60 #endif 61 needack = (flags & (AMF_NOTIFY|AMF_NOTIFY_ERR)); 62 } 63 continue; 64 } 65 66 if (flags != AMF_EMPTY) 67 /* Found first not-completed table entry */ 68 break; 69 } 70 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; 74 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); 80 81 /* Move all unprocessed messages to the beginning */ 82 dst_ind = 0; 83 for (src_ind = first_slot; src_ind < next_slot; src_ind++) { 84 flags = msgtable[src_ind].flags; 85 86 /* Skip empty entries */ 87 if (flags == AMF_EMPTY) continue; 88 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) 93 continue; 94 else { 95 #ifdef DEBUG 96 printf( 97 "asynsend: found entry %d with error %d\n", 98 src_ind, msgtable[src_ind].result); 99 #endif 100 if (!(flags & (AMF_NOTIFY|AMF_NOTIFY_ERR))) 101 /* Don't need to ack this error */ 102 continue; 103 } 104 } 105 106 107 /* Copy/move in use entry */ 108 #ifdef DEBUG 109 printf("asynsend: copying entry %d to %d\n", src_ind, dst_ind); 110 #endif 111 if (src_ind != dst_ind) msgtable[dst_ind] = msgtable[src_ind]; 112 dst_ind++; 113 } 114 115 /* Mark unused entries empty */ 116 for (i = dst_ind; i < ASYN_NR; i++) msgtable[i].flags = AMF_EMPTY; 117 118 first_slot = 0; 119 next_slot = dst_ind; 120 if (next_slot >= ASYN_NR) /* Cleanup failed */ 121 panic("asynsend: msgtable full"); 122 } 123 124 fl |= AMF_VALID; /* Mark in use */ 125 msgtable[next_slot].dst = dst; 126 msgtable[next_slot].msg = *mp; 127 __insn_barrier(); 128 msgtable[next_slot].flags = fl; /* Has to be last. The kernel 129 * scans this table while we 130 * are sleeping. 131 */ 132 next_slot++; 133 134 /* Reload. */ 135 inside = 0; 136 r = senda_reload(); 137 138 return r; 139 } 140 141 /*===========================================================================* 142 * senda_reload * 143 *===========================================================================*/ 144 int senda_reload() 145 { 146 int len; 147 148 assert(next_slot >= first_slot); 149 len = next_slot - first_slot; 150 assert(first_slot + len <= ASYN_NR); 151 assert(len >= 0); 152 153 /* Tell the kernel to rescan the table */ 154 return ipc_senda(&msgtable[first_slot], len); 155 } 156 157 /*===========================================================================* 158 * asyn_geterror * 159 *===========================================================================*/ 160 int asyn_geterror(endpoint_t *dst, message *msg, int *err) 161 { 162 int src_ind, flags, result; 163 164 if (!initialized) return(0); 165 166 for (src_ind = 0; src_ind < next_slot; src_ind++) { 167 flags = msgtable[src_ind].flags; 168 result = msgtable[src_ind].result; 169 170 /* Find a message that has been completed with an error */ 171 if ((flags & (AMF_VALID|AMF_DONE)) == (AMF_VALID|AMF_DONE)) { 172 if (result != OK && (flags & (AMF_NOTIFY|AMF_NOTIFY_ERR))) { 173 /* Found one */ 174 if (dst != NULL) *dst = msgtable[src_ind].dst; 175 if (msg != NULL) *msg = msgtable[src_ind].msg; 176 if (err != NULL) *err = result; 177 178 /* Acknowledge error so it can be cleaned up upon next 179 * asynsend */ 180 msgtable[src_ind].result = OK; 181 182 return(1); 183 } 184 } 185 } 186 187 return(0); 188 } 189 190