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 #define DEBUG 0 23 24 /*===========================================================================* 25 * asynsend3 * 26 *===========================================================================*/ 27 int asynsend3(dst, mp, fl) 28 endpoint_t dst; 29 message *mp; 30 int fl; 31 { 32 int i, r, src_ind, dst_ind; 33 unsigned flags; 34 static int inside = 0; 35 int needack = 0; 36 37 /* Debug printf() causes asynchronous sends? */ 38 if (inside) /* Panic will not work either then, so exit */ 39 exit(1); 40 41 inside = 1; 42 43 if(!initialized) { 44 /* Initialize table by marking all entries empty */ 45 for (i = 0; i < ASYN_NR; i++) msgtable[i].flags = AMF_EMPTY; 46 47 initialized = 1; 48 } 49 50 /* Update first_slot. That is, find the first not-completed slot by the 51 * kernel since the last time we sent this table (e.g., the receiving end of 52 * the message wasn't ready yet). 53 */ 54 for (; first_slot < next_slot; first_slot++) { 55 flags = msgtable[first_slot].flags; 56 if ((flags & (AMF_VALID|AMF_DONE)) == (AMF_VALID|AMF_DONE)) { 57 /* Marked in use by us (VALID) and processed by the kernel */ 58 if (msgtable[first_slot].result != OK) { 59 #if DEBUG 60 printf("asynsend: found entry %d with error %d\n", 61 first_slot, msgtable[first_slot].result); 62 #endif 63 needack = (flags & (AMF_NOTIFY|AMF_NOTIFY_ERR)); 64 } 65 continue; 66 } 67 68 if (flags != AMF_EMPTY) 69 /* Found first not-completed table entry */ 70 break; 71 } 72 73 /* Reset to the beginning of the table when all messages are completed */ 74 if (first_slot >= next_slot && !needack) 75 next_slot = first_slot = 0; 76 77 /* Can the table handle one more message? */ 78 if (next_slot >= ASYN_NR) { 79 /* We're full; tell the kernel to stop processing for now */ 80 if ((r = ipc_senda(NULL, 0)) != OK) 81 panic("asynsend: ipc_senda failed: %d", r); 82 83 /* Move all unprocessed messages to the beginning */ 84 dst_ind = 0; 85 for (src_ind = first_slot; src_ind < next_slot; src_ind++) { 86 flags = msgtable[src_ind].flags; 87 88 /* Skip empty entries */ 89 if (flags == AMF_EMPTY) continue; 90 91 /* and completed entries only if result is OK or if error 92 * doesn't need to be acknowledged */ 93 if ((flags & (AMF_VALID|AMF_DONE)) == (AMF_VALID|AMF_DONE)) { 94 if (msgtable[src_ind].result == OK) 95 continue; 96 else { 97 #if DEBUG 98 printf( 99 "asynsend: found entry %d with error %d\n", 100 src_ind, msgtable[src_ind].result); 101 #endif 102 if (!(flags & (AMF_NOTIFY|AMF_NOTIFY_ERR))) 103 /* Don't need to ack this error */ 104 continue; 105 } 106 } 107 108 109 /* Copy/move in use entry */ 110 #if DEBUG 111 printf("asynsend: copying entry %d to %d\n", src_ind, dst_ind); 112 #endif 113 if (src_ind != dst_ind) msgtable[dst_ind] = msgtable[src_ind]; 114 dst_ind++; 115 } 116 117 /* Mark unused entries empty */ 118 for (i = dst_ind; i < ASYN_NR; i++) msgtable[i].flags = AMF_EMPTY; 119 120 first_slot = 0; 121 next_slot = dst_ind; 122 if (next_slot >= ASYN_NR) /* Cleanup failed */ 123 panic("asynsend: msgtable full"); 124 } 125 126 fl |= AMF_VALID; /* Mark in use */ 127 msgtable[next_slot].dst = dst; 128 msgtable[next_slot].msg = *mp; 129 __insn_barrier(); 130 msgtable[next_slot].flags = fl; /* Has to be last. The kernel 131 * scans this table while we 132 * are sleeping. 133 */ 134 next_slot++; 135 136 /* Reload. */ 137 inside = 0; 138 r = senda_reload(); 139 140 return r; 141 } 142 143 /*===========================================================================* 144 * senda_reload * 145 *===========================================================================*/ 146 int senda_reload() 147 { 148 int len; 149 150 assert(next_slot >= first_slot); 151 len = next_slot - first_slot; 152 assert(first_slot + len <= ASYN_NR); 153 assert(len >= 0); 154 155 /* Tell the kernel to rescan the table */ 156 return ipc_senda(&msgtable[first_slot], len); 157 } 158 159 /*===========================================================================* 160 * asyn_geterror * 161 *===========================================================================*/ 162 int asyn_geterror(endpoint_t *dst, message *msg, int *err) 163 { 164 int src_ind, flags, result; 165 166 if (!initialized) return(0); 167 168 for (src_ind = 0; src_ind < next_slot; src_ind++) { 169 flags = msgtable[src_ind].flags; 170 result = msgtable[src_ind].result; 171 172 /* Find a message that has been completed with an error */ 173 if ((flags & (AMF_VALID|AMF_DONE)) == (AMF_VALID|AMF_DONE)) { 174 if (result != OK && (flags & (AMF_NOTIFY|AMF_NOTIFY_ERR))) { 175 /* Found one */ 176 if (dst != NULL) *dst = msgtable[src_ind].dst; 177 if (msg != NULL) *msg = msgtable[src_ind].msg; 178 if (err != NULL) *err = result; 179 180 /* Acknowledge error so it can be cleaned up upon next 181 * asynsend */ 182 msgtable[src_ind].result = OK; 183 184 return(1); 185 } 186 } 187 } 188 189 return(0); 190 } 191 192