prot_lock.c

来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 1,176 行 · 第 1/2 页

C
1,176
字号
					if ((msgp = retransmitted(nl, KLM_LOCK)) != NULL) 						dequeue(msgp);				}			}			nl = nl->wait_nxt;		}	return;}/*  * add to the list of call backs to klm(call_q is not doubled linked!) * this is necc because of original nl may be altered while the call * to klm needs to be queued for retransmission * add_call returns -1 upon error returns, * otherwise if returns 0 */intadd_call(nl)	reclock *nl;{	reclock *new ;	if ((new = copy_le(nl)) == NULL)		return(-1);	new->rel = 1;	new->nxt = call_q;	call_q = new;	return(0);}/* * find "a" in the proper order in the fp list and insert; * does not worry about overlap or merge with lock from same process; * it all should have been taken care of before find_insert is called; */voidfind_insert(fp, a)	struct fs_rlck *fp;	reclock *a;{	reclock *nl;	reclock *insrtp;		nl = fp->rlckp;	insrtp = NULL;	while (nl != NULL && nl->lck.lb < a->lck.ub) {		insrtp = nl;		if (nl->lck.lb < a->lck.lb)			nl = nl->nxt;		else			break;	}	insert_le(fp, insrtp, a);	return;}/* * insert adds a lock entry "a" to the list ptr to by fp->rlckp * starting at position ptr to by insrtp */voidinsert_le(fp, insrtp, a)	struct fs_rlck *fp;	reclock *insrtp;	reclock *a;{	if (insrtp == NULL) {		a->nxt = fp->rlckp;		if (a->nxt != NULL)			a->nxt->prev = a;		fp->rlckp = a;	}	else {		a->nxt = insrtp->nxt;		if (insrtp->nxt != NULL)			insrtp->nxt->prev = a;		insrtp->nxt = a;	}	a->prev = insrtp;	return;}/* * delete a lock entry "a" from rlck list ptr to by fp->rlckp; * fp can be deleted and returned to the free list if no more reclock * on the same file system exists */voiddelete_le(fp, a)	struct fs_rlck *fp;	reclock *a;{	if (a->prev != NULL)		a->prev->nxt = a->nxt;	else {		fp->rlckp = a->nxt;		if (a->nxt == NULL)	/* prepare to be released if no lock is added to fp */			rel_fe = fp;	}	if (a->nxt != NULL)		a->nxt->prev =a->prev;}/* * copy_fe allocates a new fe entry *fp and copies a into fp; * it returns *fp if succeeds, * otherwise it returns NULL */struct fs_rlck *copy_fe(a)	reclock *a;{	struct fs_rlck *fp;	if ((fp = get_fe()) == NULL) {	/*no more fe entry*/		fprintf(stderr, "get_fe: out of fs_rlck entry\n");		return(NULL); 	}	else {	/*add new fe entry*/		if ((fp->svr = xmalloc(strlen(a->lck.svr)+1)) == NULL) {			free_fe(fp);			return(NULL);		}		(void) strcpy(fp->svr, a->lck.svr);		/* copy fh structure: use malloc */		if (obj_alloc(&fp->fs.fh, a->lck.fh_bytes, a->lck.fh_len) == -1) {			free_fe(fp);			return(NULL);		}		return(fp);	}}/* * copy_le allocates a new le entry a and copies b into a; * it returns *a if succeeds, * otherwise returns NULL */reclock *copy_le(b)	reclock *b;{	reclock *a;	if (( a= get_le()) == NULL)		return(NULL);	if ((a->lck.svr = xmalloc(strlen(b->lck.svr)+1)) == NULL) {		free_le(a);		return(NULL);	}	(void) strcpy(a->lck.svr, b->lck.svr);	if (obj_alloc(&a->lck.fh, b->lck.fh_bytes, b->lck.fh_len) == -1) {		free_le(a);		return(NULL);	}	a->lck.pid = b->lck.pid;	a->lck.lb = b->lck.lb;	a->lck.l_len = b->lck.l_len;	/* callername is not copied */	if (obj_alloc(&a->lck.oh, b->lck.oh_bytes, b->lck.oh_len) == -1) {		free_le(a);		return(NULL);	}	if (obj_alloc(&a->cookie, b->cookie_bytes, b->cookie_len) == -1) {		free_le(a);		return(NULL);	}		a->lck.svid = b->lck.svid;	if ((a->lck.clnt = xmalloc(strlen(b->lck.clnt)+1)) == NULL) {		free_le(a);		return(NULL);	}	(void) strcpy(a->lck.clnt, b->lck.clnt);	a->lck.caller_name = a->lck.clnt;	a->lck.ub = b->lck.ub;	a->lck.op = b->lck.op;	a->block = b->block;	a->exclusive = b->exclusive;	return(a);}/* * insert a into the list chained by mnt_ptr; ptr to by mp; * insert_mp is similar to insert_le except that no insrtp and  * mnt_nxt, mnt_prev are used */voidinsert_mp(mp,  a)	struct fs_rlck *mp;	reclock *a;{	a->mnt_nxt = mp->rlckp;	if (a->mnt_nxt != NULL)		a->mnt_nxt->mnt_prev = a;	mp->rlckp = a;	a->mnt_prev = NULL;	return;}/* * delete_mp remove a from the list chained by mnt_prt; ptr by mp; * delete_mp is similar to delete_le; except mnt_prev, mnt_nxt are used; * and rel_me is set for future release_me */voiddelete_mp(mp, a)	struct fs_rlck *mp;	reclock *a;{	if (a->mnt_prev != NULL)		a->mnt_prev->mnt_nxt = a->mnt_nxt;	else if (mp->rlckp == a) { /* this is necc because a may nothave any monitor chain in the case of call back */		mp->rlckp = a->mnt_nxt;		if (a->mnt_nxt == NULL)		/* prepare to release mp; later release_me is called */			rel_me = mp;	}	if (a->mnt_nxt != NULL)		a->mnt_nxt->mnt_prev =a->mnt_prev;}bool_tobj_cmp(a, b)	struct netobj *a, *b;{	if (a->n_len != b->n_len) 		return(FALSE);	if (bcmp(&a->n_bytes[0], &b->n_bytes[0], a->n_len) != 0) 		return(FALSE);	else		return(TRUE);}/* * duplicate b in a; * return -1, if malloc error; * returen 0, otherwise; */intobj_alloc(a, b, n)	netobj *a;	char *b;	u_int n;{	a->n_len = n;	if ((a->n_bytes = xmalloc(n)) == NULL) {		return(-1);		}	else		bcopy(b, a->n_bytes, a->n_len);	return(0);}/* * copy b into a * returns 0, if succeeds * return -1 upon error */intobj_copy(a, b)	netobj *a, *b;{	if (b == NULL) {		/* trust a is already NULL */		if (debug)			printf(" obj_copy(a = %x, b = NULL), a\n", a);		return(0);	}	return(obj_alloc(a, b->n_bytes, b->n_len));}/* * adj_len modified the l_len field, since lb or ub has changed */voidadj_len(a)	reclock *a;{	if (a->lck.ub == MAXLEN)		a->lck.l_len = 0;	else		a->lck.l_len = a->lck.ub - a->lck.lb;}/* * if nl is inside a, inside returns TRUE; */bool_tinside(nl,a)	reclock *nl,*a;{	if (a == NULL | nl == NULL)		return( FALSE);	else		return(a->lck.lb <=nl->lck.lb && a->lck.ub >=nl->lck.ub);}/* * if nl overlaps with a, overlap returns TRUE; */bool_toverlap(nl, a)	reclock *nl, *a;{	if (nl->lck.ub <= a->lck.lb || nl->lck.lb >= a->lck.ub)		return(FALSE);	else		return(TRUE);}bool_tsame_bound(a,b)	reclock *a, *b;{/*	if (a == NULL || b == NULL)		return( FALSE);	else*/		return(a->lck.lb == b ->lck.lb && a->lck.ub == b ->lck.ub);}bool_tsame_op(a,b)	reclock *a, *b;{		return(( (a-> lck.op & LOCK_EX) && (b-> lck.op & LOCK_EX)) ||		((a-> lck.op & LOCK_SH) && (b-> lck.op & LOCK_SH)));}bool_tsame_lock(a, b)	reclock *a, *b;{	if (same_proc(a, b) && same_op(a, b) && same_bound(a, b))		return(TRUE);	else		return(FALSE);}bool_tsimi_lock(a, b)	reclock *a, *b;{	if (same_proc(a, b) && same_op(a, b) && inside(b, a))		return(TRUE);	else		return(FALSE);}bool_tremote_data(a)	reclock *a;{	if (strcmp(a->lck.svr, hostname) == 0)		return(FALSE);	else		return(TRUE);}bool_tremote_clnt(a)	reclock *a;{	if (strcmp(a->lck.clnt, hostname) == 0)		return(FALSE);	else		return(TRUE);}/*  * translate monitor calls into modifying monitor chains * returns 0, if success * returns -1, in case of error */intadd_mon(a,i)	reclock *a;	int i;{	if (strcmp(a->lck.svr, a->lck.clnt) == 0)		/* local case, no need for monitoring */		return(0);	if (remote_data(a)) {		if (mond(hostname, PRIV_RECOVERY, a, i) == -1)			return(-1);		if (mond(a->lck.svr, PRIV_RECOVERY, a, i) == -1)			return(-1);		}	else		if (mond(a->lck.clnt, PRIV_CRASH, a, i) == -1)			return(-1);		return(0);}/* * mond set up the monitor ptr;  * it return -1, if no more free mp entry is available when needed *		 or cannot contact status monitor */intmond(site, proc, a, i)	char *site;	int proc;	reclock *a;	int i;{	struct fs_rlck * new;	if (i == 1) { /* insert! */		if ((new = find_me(site, proc)) == NULL) { /* not found*/			if (( new = get_me()) == NULL) /* no more me entry */				return(-1);			else  {		/* create a new mp */				if ((new->svr = xmalloc(strlen(site)+1)) == NULL) {					used_me--;					free((char *) new);					return(-1);				}				(void) strcpy((char *) new->svr, site);				new->fs.procedure = proc;				/* contact status monitor */				if (contact_monitor(new, 1) == -1) {					used_me--;					xfree(&new->svr);					free((char *) new);					return(-1);				}				else {					insert_me(new);				}			}		}		insert_mp(new, a);		return(0);	}	else { /* i== 0; delete! */		if ((new = find_me(site, proc)) == NULL)			return(0);			/* happen due to call back */		else			delete_mp(new, a);		/* delete_mp may be no op if a is introduced due to call back */			return(0);	}}intcontact_monitor(new, i)	struct fs_rlck *new;	int i;{	struct stat_res *resp;	int priv_size;	int func;	switch(i) {	case 0:		func = SM_UNMON;		break;	case 1:		func = SM_MON;		break;	default:		fprintf(stderr, "unknown contact monitor (%d)\n", i);		abort();	}	priv.pid = pid;	priv.priv_ptr = (int *) new;	if ((priv_size = sizeof(struct priv_struct)) > 16) 	/* move to init*/		fprintf(stderr, "contact_mon: problem with private data size (%d) to status monitor\n",		priv_size);	resp = stat_mon(new->svr, hostname, PRIV_PROG, PRIV_VERS,	 new->fs.procedure, func, priv_size, &priv);	if (resp->res_stat == stat_succ) {		if (resp->sm_stat == stat_succ) {			local_state = resp->sm_state;	/* update local state */			return(0);		}		else {			fprintf(stderr, "rpc.lockd: site %s does not subscribe to status monitor service \n", new->svr);			return(-1);		}	}	else {		fprintf(stderr, "rpc.lockd cannot contact local statd\n");		return(-1);	}}/* * would_deadlock is called when blocked () has returned true, and  * the request is a blocking request, indicating that the caller * would be put to sleep.  would_deadlock is called only when the * request and the resource are both local;  lack of globally shared * locking information among the lock managers prevents this algorithm * from being effective in other than the local environment. * * blocked () sets the variable insrtp to point to the reclock structure * which currently "owns" the lock on the file WHEN IT RETURNS TRUE (i.e. * when it determines that the new lock request is "blocked" by a currently * existing lock on the resource.) * * would_deadlock () implements the following LOCAL deadlock avoidance * algorithm: * *	Before permitting process A to sleep on a given lock, check that the *	current owner of that lock is not already sleeping on a lock which *	is either: * *		1) owned by A, or *		2) owned by another process which is currently *		   sleeping on a lock owned by A. *	 *	Both of these conditions would lead to deadlock, and can be avoided *	in the local case, since all of the information required to make the *	local test is available locally. */would_deadlock (insrtp, a)		/* Ultrix mod - fsg */reclock *insrtp;			/* current lock owner */reclock *a;				/* lock requester */{	register int lpid;		/* current lock owner pid */	reclock *wp;			/* wait_q pointer */	reclock *exitflag;		/* loop exit flag */	if ((insrtp == NULL) || (wait_q == NULL)) {		return (0);		/* no deadlock */	}	exitflag = insrtp;	lpid     = insrtp->lck.svid;	/* init to current owner */	do {		if (lpid == a->lck.svid) {			return (1);	/* would deadlock */		}		/*		 *	Each reclock entry on the wait queue contains the		 *	pid of the waiting process, as well as the pid of 		 *	the process which currently owns the lock.		 *		 * 	Thus, for each entry on wait_q:		 *		 *		if a pid on the wait queue matches that of 		 *		of the current lock owner (identified by lpid)		 *			set the lock owner pid (lpid) to the 		 *			pid of the current owner of the lock 		 *			and recheck against the requester.		 *			 */		for (wp = wait_q; wp != NULL; wp = wp->wait_nxt) {			if (lpid == wp->lck.svid) {				lpid = wp->lopid;				break;			}		}		exitflag = wp;	} while (exitflag != NULL);	return (0);		/* No deadlock */}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?