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 + -
显示快捷键?