USG_PG3/usr/source/opsys/sys5.c
#include "../head/param.h"
#include "../head/reg.h"
#include "../head/ipcomm.h"
#include "../head/ipcommx.h"
#include "../head/user.h"
#include "../head/userx.h"
#include "../head/proc.h"
/*
* Semaphore System Call
*/
lflags()
{ register struct semi4s *sp, **p;
register int n;
if((n = u.u_arg[1]) >= NLOCK) {
u.u_error = EINVAL;
return;
}
if(n < 0) sp = NULL;
else sp = &semi4s[n];
switch(u.u_arg[0].lobyte) {
default:
u.u_error = EINVAL;
return;
case ASEMI:
if(sp == NULL) { /*dynamic alloc*/
for(sp = &semi4s[0]; sp < &semi4s[NLOCK]; sp++)
if(sp->sem_cnt == 0) {
alocsem(sp);
return;
}
u.u_error = ETABLE;
}
else if(usemf(sp) == NULL) alocsem(sp);
else u.u_error = ENOALOC; /*already alloc*/
return;
case FSEMI:
if(sp == NULL) {
u.u_error = ENOALOC;
for(p = &u.u_semi4[0];p < &u.u_semi4[NOLOCK]; p++)
if(*p) {
freesem(p);
u.u_error = 0;
}
}
else if((p = usemf(sp)) != NULL) freesem(p);
else u.u_error = ENOALOC;
return;
case LOCK:
case UNLOCK:
case TLOCK:
n = S_LU;
break;
case P:
case V:
case TEST:
n = S_PV;
}
/*ensure semi4 is alloc for purpose intended*/
if(sp == NULL) {
u.u_error = EINVAL;
return;
}
if(usemf(sp) == NULL || (sp->sem_flag & S_TYPE) != n) {
u.u_error = ENOALOC;
return;
}
u.u_ar0[R0] = sp->sem_lock;
switch(u.u_arg[0].lobyte) {
case LOCK:
if(sp->sem_lock == u.u_procp->p_pid) return;
while(sp->sem_lock != 0) {
sp->sem_flag =| IP_WANTED;
sleep(sp, PSEMI4);
}
u.u_ar0[R0] = sp->sem_lock;
sp->sem_lock = u.u_procp->p_pid;
return;
case UNLOCK:
if(sp->sem_lock != u.u_procp->p_pid)
u.u_error = EFUNC;
else {
sp->sem_lock = 0;
if(sp->sem_flag & IP_WANTED) {
sp->sem_flag =& ~IP_WANTED;
wakeup(sp);
}
}
return;
case TLOCK:
if(sp->sem_lock == 0)
sp->sem_lock = u.u_procp->p_pid;
return;
case P:
while(sp->sem_lock <= 0) {
sp->sem_flag =| IP_WANTED;
sleep(sp, PSEMI4);
}
u.u_ar0[R0] = sp->sem_lock;
sp->sem_lock--;
return;
case V:
sp->sem_lock++;
if(sp->sem_flag & IP_WANTED) {
sp->sem_flag =& ~IP_WANTED;
wakeup(sp);
}
return;
case TEST:
if(sp->sem_lock > 0) sp->sem_lock--;
}
}
/*
* Free a semaphore
*/
freesem(up)
int **up;
{ register struct semi4s *rsp;
rsp = *up;
/* unlock l-u semi4 if necessary */
if(((rsp->sem_flag & S_TYPE) == S_LU) &&
(rsp->sem_lock == u.u_procp->p_pid)) {
rsp->sem_lock = 0;
if(rsp->sem_flag & IP_WANTED) {
rsp->sem_flag =& ~IP_WANTED;
wakeup(rsp);
}
}
rsp->sem_cnt--;
*up = NULL;
}
/*
* See if the semaphore "sp" is already allocated
* by a process. Note that NULL is a suitable argument.
*/
usemf(sp)
struct semi4s *sp;
{ register struct semi4s *rsp, **p;
rsp = sp;
for(p = &u.u_semi4[0]; p < &u.u_semi4[NOLOCK]; p++)
if(rsp == *p) return(p);
return(NULL);
}
/*
* Allocate the semaphore "sp".
*/
alocsem(sp)
struct semi4s *sp;
{ register struct semi4s *rsp;
struct semi4s **p;
register int type, scope;
if((p = usemf(NULL)) == NULL) {
u.u_error = ETABLE;
return;
}
rsp = sp;
switch(scope = u.u_arg[0].hibyte) {
default:
u.u_error = EINVAL;
return;
case 0:
case 1:
case 2:
type = S_LU;
break;
case 3:
case 4:
case 5:
type = S_PV;
scope =- 3;
}
if(rsp->sem_cnt == 0) {
rsp->sem_flag = type | scope;
rsp->sem_lock = 0;
rsp->sem_id = ipidtyp(scope);
}
else if((rsp->sem_flag & S_TYPE) != type)
u.u_error = ENOALOC;
else ipacces(&rsp->sem_flag);
if(u.u_error) return;
rsp->sem_cnt++;
*p = rsp;
u.u_ar0[R0] = rsp - &semi4s[0];
}
/*
* Verify that a process has permission to access an
* interprocess communication resource.
*/
ipacces(p)
struct ipaword *p;
{ register int scope, id;
register struct ipaword *rp;
rp = p;
scope = rp->ip_flag & IP_PERM;
if(u.u_uid == 0 || scope == IP_ANY) return(1);
id = rp->ip_id & 0377;
if(id == ipidtyp(scope)) return(1);
u.u_error = EACCES;
return(0);
}
/*
* Determine the appropriate id to to used
* in checking acces permission.
*/
ipidtyp(scope)
{ switch(scope) {
case IP_ANY: return(0);
case IP_UID: return(u.u_uid&0377);
case IP_GID: return(u.u_gid&0377);
}
u.u_error = EINVAL;
return(0);
}