openblt

a hobby OS from the late 90s
git clone http://frotz.net/git/openblt.git
Log | Files | Refs | LICENSE

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