/* delete a console */ void vntsd_delete_cons(vntsd_t *vntsdp) { vntsd_group_t *groupp; vntsd_cons_t *consp; for (; ; ) { /* get the group contains deleted console */ (void) mutex_lock(&vntsdp->lock); groupp = vntsd_que_walk(vntsdp->grouppq, (el_func_t)find_clean_cons_group); if (groupp == NULL) { /* no more group has console deleted */ (void) mutex_unlock(&vntsdp->lock); return; } groupp->status &= ~VNTSD_GROUP_CLEAN_CONS; (void) mutex_unlock(&vntsdp->lock); for (; ; ) { /* get the console to be deleted */ (void) mutex_lock(&groupp->lock); assert(groupp->conspq); consp = vntsd_que_walk(groupp->conspq, (el_func_t)find_clean_cons); if (consp == NULL) { /* no more cons to delete */ (void) mutex_unlock(&groupp->lock); break; } /* remove console from the group */ (void) vntsd_que_rm(&groupp->conspq, consp); groupp->num_cons--; (void) mutex_unlock(&groupp->lock); /* clean up the console */ cleanup_cons(consp); /* delete group? */ if (groupp->num_cons == 0) { /* no more console delete it */ assert(groupp->vntsd); (void) mutex_lock(&groupp->vntsd->lock); (void) vntsd_que_rm(&groupp->vntsd->grouppq, groupp); (void) mutex_unlock(&groupp->vntsd->lock); /* clean up the group */ vntsd_clean_group(groupp); break; } } } }
/* * acquire_writer() the client is going to be writer. * insert the client to the head of the console client queue. */ static int acquire_writer(vntsd_client_t *clientp) { vntsd_cons_t *consp; vntsd_client_t *writerp; int rv; D1(stderr, "t@%d:acuire_writer :client@%d\n", thr_self(), clientp->sockfd); assert(clientp != NULL); consp = clientp->cons; assert(consp); (void) mutex_lock(&consp->lock); assert(consp->clientpq != NULL); if (consp->clientpq->handle == clientp) { /* clientp is a writer already */ (void) mutex_unlock(&consp->lock); return (VNTSD_SUCCESS); } /* current writer */ writerp = (vntsd_client_t *)(consp->clientpq->handle); (void) mutex_lock(&writerp->lock); rv = vntsd_que_rm(&(consp->clientpq), clientp); assert(rv == VNTSD_SUCCESS); (void) mutex_lock(&clientp->lock); /* move client to be first in the console queue */ consp->clientpq->handle = clientp; /* move previous writer to be the second in the queue */ rv = vntsd_que_insert_after(consp->clientpq, clientp, writerp); (void) mutex_unlock(&consp->lock); (void) mutex_unlock(&writerp->lock); (void) mutex_unlock(&clientp->lock); if (rv != VNTSD_SUCCESS) { return (rv); } /* write warning message to the writer */ if ((rv = vntsd_write_line(writerp, gettext("Warning: Console connection forced into read-only mode"))) != VNTSD_SUCCESS) { return (rv); } return (VNTSD_SUCCESS); }
/* clean up a group */ void vntsd_clean_group(vntsd_group_t *groupp) { timestruc_t to; D1(stderr, "t@%d clean_group() group=%s tcp=%lld\n", thr_self(), groupp->group_name, groupp->tcp_port); (void) mutex_lock(&groupp->lock); /* prevent from reentry */ if (groupp->status & VNTSD_GROUP_CLEANUP) { (void) mutex_unlock(&groupp->lock); return; } groupp->status |= VNTSD_GROUP_CLEANUP; vntsd_free_que(&groupp->conspq, (clean_func_t)cleanup_cons); (void) mutex_unlock(&groupp->lock); /* walk through no cons client queue */ while (groupp->no_cons_clientpq != NULL) { groupp->status |= VNTSD_GROUP_SIG_WAIT; (void) vntsd_que_walk(groupp->no_cons_clientpq, (el_func_t)vntsd_notify_client_cons_del); to.tv_sec = VNTSD_CV_WAIT_DELTIME; to.tv_nsec = 0; (void) cond_reltimedwait(&groupp->cvp, &groupp->lock, &to); } if (groupp->listen_tid == thr_self()) { /* listen thread is exiting */ (void) mutex_lock(&(groupp->vntsd->lock)); (void) vntsd_que_rm(&groupp->vntsd->grouppq, groupp); (void) mutex_unlock(&groupp->vntsd->lock); (void) cond_destroy(&groupp->cvp); (void) mutex_unlock(&groupp->lock); (void) mutex_destroy(&groupp->lock); free(groupp); return; } /* signal listen thread to exit */ groupp->status |= VNTSD_GROUP_SIG_WAIT; while (groupp->status & VNTSD_GROUP_SIG_WAIT) { (void) thr_kill(groupp->listen_tid, SIGUSR1); to.tv_sec = VNTSD_CV_WAIT_DELTIME; to.tv_nsec = 0; /* wait listen thread to exit */ (void) cond_reltimedwait(&groupp->cvp, &groupp->lock, &to); } (void) mutex_unlock(&groupp->lock); (void) thr_join(groupp->listen_tid, NULL, NULL); /* free group */ (void) cond_destroy(&groupp->cvp); (void) mutex_destroy(&groupp->lock); free(groupp); }
/* ceate console selection thread */ static int create_console_thread(vntsd_group_t *groupp, int sockfd) { vntsd_client_t *clientp; vntsd_thr_arg_t *thr_arg; int rv; assert(groupp); D1(stderr, "t@%d create_console_thread@%lld:client@%d\n", thr_self(), groupp->tcp_port, sockfd); /* allocate a new client */ clientp = (vntsd_client_t *)malloc(sizeof (vntsd_client_t)); if (clientp == NULL) { return (VNTSD_ERR_NO_MEM); } /* initialize the client */ bzero(clientp, sizeof (vntsd_client_t)); clientp->sockfd = sockfd; clientp->cons_tid = (thread_t)-1; (void) mutex_init(&clientp->lock, USYNC_THREAD|LOCK_ERRORCHECK, NULL); /* append client to group */ (void) mutex_lock(&groupp->lock); /* check if the group is [being] removed */ if (groupp->status & VNTSD_GROUP_IN_CLEANUP) { (void) mutex_unlock(&groupp->lock); vntsd_free_client(clientp); return (VNTSD_STATUS_NO_CONS); } if ((rv = vntsd_que_append(&groupp->no_cons_clientpq, clientp)) != VNTSD_SUCCESS) { (void) mutex_unlock(&groupp->lock); vntsd_free_client(clientp); return (rv); } (void) mutex_unlock(&groupp->lock); /* * allocate thr_arg from heap for console thread so * that thr_arg is still valid after this function exits. * console thread will free thr_arg. */ thr_arg = (vntsd_thr_arg_t *)malloc(sizeof (vntsd_thr_arg_t)); if (thr_arg == NULL) { vntsd_free_client(clientp); return (VNTSD_ERR_NO_MEM); } thr_arg->handle = groupp; thr_arg->arg = clientp; (void) mutex_lock(&clientp->lock); /* create console selection thread */ if (thr_create(NULL, 0, (thr_func_t)vntsd_console_thread, thr_arg, THR_DETACHED, &clientp->cons_tid)) { free(thr_arg); (void) mutex_unlock(&clientp->lock); (void) mutex_lock(&groupp->lock); (void) vntsd_que_rm(&groupp->no_cons_clientpq, clientp); (void) mutex_unlock(&groupp->lock); vntsd_free_client(clientp); return (VNTSD_ERR_CREATE_CONS_THR); } (void) mutex_unlock(&clientp->lock); return (VNTSD_SUCCESS); }