port.c (6288B)
1 /* Copyright 1998-1999, Brian J. Swetland. All rights reserved. 2 ** Distributed under the terms of the OpenBLT License 3 */ 4 5 #include "kernel.h" 6 #include "memory.h" 7 #include "port.h" 8 #include "resource.h" 9 10 #define MAX_MSGCOUNT 16 11 12 int snprintf (char *s, int len, char *fmt, ...); 13 14 int port_create(int restrict, const char *name) 15 { 16 port_t *p; 17 char qname[16]; 18 19 /* create new port */ 20 p = kmalloc(port_t); 21 p->sendqueue = kmalloc(resource_t); 22 23 p->msgcount = 0; 24 p->first = p->last = NULL; 25 p->slaved = 0; 26 p->refcount = 1; 27 p->nowait = 0; 28 p->restrict = restrict; 29 30 rsrc_bind(&p->rsrc, RSRC_PORT, current->rsrc.owner); 31 rsrc_bind(p->sendqueue, RSRC_QUEUE, current->rsrc.owner); 32 rsrc_set_name(&p->rsrc, name); 33 snprintf(qname,16,"port:%d",p->rsrc.id); 34 rsrc_set_name(p->sendqueue, name); 35 return p->rsrc.id; 36 } 37 38 int port_destroy(int port) 39 { 40 port_t *p; 41 if(!(p = rsrc_find_port(port))) return ERR_RESOURCE; 42 // if(p->rsrc.owner != current) return ERR_PERMISSION; 43 44 if(p->refcount == 1) { 45 /* destroy port */ 46 rsrc_release(&p->rsrc); 47 rsrc_release(p->sendqueue); 48 kfree(resource_t,p->sendqueue); 49 kfree(port_t,p); 50 return ERR_NONE; 51 } 52 53 /* port is the master of one or more slaves */ 54 return ERR_RESOURCE; 55 } 56 57 uint32 port_option(uint32 port, uint32 opt, uint32 arg) 58 { 59 port_t *p; 60 61 if(!(p = rsrc_find_port(port))) return ERR_RESOURCE; 62 if(p->rsrc.owner != current->rsrc.owner) return ERR_PERMISSION; 63 64 if(opt == PORT_OPT_SETRESTRICT){ 65 p->restrict = arg; 66 return ERR_NONE; 67 } 68 69 if(opt == PORT_OPT_SLAVE){ 70 port_t *master; 71 72 if(arg){ 73 /* arg == 0 will simply release the old master */ 74 75 if(!(master = rsrc_find_port(arg))) return ERR_RESOURCE; 76 if(master->rsrc.owner != current->rsrc.owner) return ERR_PERMISSION; 77 78 /* indicate that our master has one more slave */ 79 master->refcount++; 80 } 81 82 if(p->slaved){ 83 /* change in slave status, deref our old master */ 84 if(!(master = rsrc_find_port(p->slaved))) 85 panic("port_option(): master port not found?"); 86 87 master->refcount--; 88 } 89 p->slaved = arg; 90 return ERR_NONE; 91 } 92 93 if (opt == PORT_OPT_NOWAIT) { 94 p->nowait = arg; 95 return ERR_NONE; 96 } 97 98 return ERR_PERMISSION; 99 } 100 101 static chain_t *msg_pool = NULL; 102 103 104 int port_send(int src, int dst, void *msg, size_t size, uint32 code) 105 { 106 int i; 107 message_t *m; 108 port_t *f,*p; 109 110 if(!(f = rsrc_find_port(src))) return ERR_SENDPORT; 111 #if 0 112 if(f->rsrc.owner != current) { 113 task_t *t = current->rsrc.owner; /* XXX */ 114 while(t){ 115 if(t == f->rsrc.owner) break; 116 t = t->rsrc.owner; 117 118 } 119 if(!t) return ERR_PERMISSION; 120 } 121 #endif 122 /* insure the port exists and we may send to it */ 123 if(!(p = rsrc_find_port(dst))) return ERR_RECVPORT; 124 /* if((p->restrict) && 125 (p->restrict != src)) return ERR_PERMISSION; XXX */ 126 127 /* are we slaved to a different port? */ 128 if(p->slaved){ 129 if(!(p = rsrc_find_port(p->slaved))) return ERR_RESOURCE; 130 if(p->slaved) return ERR_RESOURCE; 131 /* if((p->restrict) && 132 (p->restrict != src)) return ERR_PERMISSION; XXX */ 133 } 134 135 while(p->msgcount >= MAX_MSGCOUNT){ 136 int status; 137 if(p->nowait) return ERR_WOULD_BLOCK; 138 if((status = wait_on(p->sendqueue))) return status; 139 } 140 141 /* ignore invalid sizes/locations */ 142 if( (((uint32) msg) > 0x400000) || 143 (size > 4096)) return ERR_MEMORY; 144 145 m = kmalloc(message_t); 146 147 /* allocate a 4k page to carry the message. klunky... */ 148 if(size < 256){ 149 m->data = size ? kmallocB(size) : NULL; 150 } else { 151 if(msg_pool){ 152 m->data = (void *) msg_pool; 153 msg_pool = (chain_t *) msg_pool->next; 154 } else { 155 m->data = kgetpages(1); 156 } 157 } 158 159 for(i=0;i<size;i++){ 160 ((unsigned char *) m->data)[i] = *((unsigned char *) msg++); 161 } 162 163 m->from_port = src; 164 m->to_port = dst; 165 m->code = code; 166 m->size = size; 167 m->next = NULL; 168 if(p->last){ 169 p->last->next = m; 170 } else { 171 p->first = m; 172 } 173 p->last = m; 174 p->msgcount++; 175 176 177 /* If a thread is sleeping on the destination, wake it up 178 */ 179 if(p->slaved){ 180 port_t *p0 = rsrc_find_port(p->slaved); 181 if(p0){ 182 task_t *task = rsrc_dequeue(&p0->rsrc); 183 if(task) task_wake(task,ERR_NONE); 184 } 185 } else { 186 task_t *task = rsrc_dequeue(&p->rsrc); 187 if(task) task_wake(task,ERR_NONE); 188 } 189 190 return size; 191 } 192 193 /*int old_port_recv(int port, void *msg, int size, int *from)*/ 194 int port_recv(int dst, int *src, void *msg, size_t size, uint32 *code) 195 { 196 int i; 197 message_t *m; 198 port_t *p; 199 200 /* insure the port exists and we may receive on it */ 201 if(!(p = rsrc_find_port(dst))) return ERR_RECVPORT; 202 #if 0 203 if(p->rsrc.owner != current) return ERR_PERMISSION; 204 #endif 205 206 /* bounds check the message... should be more careful */ 207 if((current->team != kernel_team) && (((uint32) msg) > 0x400000)) 208 return ERR_MEMORY; 209 210 /* no messages -- sleep */ 211 while(!p->msgcount) { 212 int status; 213 if (p->nowait) return ERR_WOULD_BLOCK; 214 if((status = wait_on(&p->rsrc))) return status; 215 } 216 217 m = p->first; 218 for(i=0;i<m->size && (i <size);i++){ 219 *((unsigned char *) msg++) = ((unsigned char *) m->data)[i]; 220 } 221 if(src) *src = m->from_port; 222 if(code) *code = m->code; 223 dst = m->to_port; // XXX 224 225 /* unchain from the head of the queue */ 226 if(!(p->first = p->first->next)) p->last = NULL; 227 228 if(p->sendqueue->queue.count && (p->msgcount <= MAX_MSGCOUNT)) { 229 task_t *task = rsrc_dequeue (p->sendqueue); 230 if(task) task_wake(task, ERR_NONE); 231 } 232 p->msgcount--; 233 234 /* add to the freepool */ 235 if(m->size < 256){ 236 if(m->size) kfreeB(m->size,m->data); 237 } else { 238 ((chain_t *) m->data)->next = msg_pool; 239 msg_pool = ((chain_t *) m->data); 240 } 241 kfree(message_t,m); 242 return size < m->size ? size : m->size; 243 } 244