/* 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; } } } }
/* * all clients connected to a console must disconnect before * removing a console. */ static void cleanup_cons(vntsd_cons_t *consp) { vntsd_group_t *groupp; timestruc_t to; assert(consp); D1(stderr, "t@%d vntsd_disconn_clients@%d\n", thr_self(), consp->cons_no); groupp = consp->group; assert(groupp); (void) mutex_lock(&consp->lock); /* wait for all clients disconnect from the console */ while (consp->clientpq != NULL) { consp->status |= VNTSD_CONS_SIG_WAIT; /* signal client to disconnect the console */ (void) vntsd_que_walk(consp->clientpq, (el_func_t)vntsd_notify_client_cons_del); (void) thr_kill(consp->wr_tid, SIGUSR1); to.tv_sec = VNTSD_CV_WAIT_DELTIME; to.tv_nsec = 0; /* wait for clients to disconnect */ (void) cond_reltimedwait(&consp->cvp, &consp->lock, &to); } (void) mutex_unlock(&consp->lock); free_cons(consp); }
/* initial console configuration */ void vntsd_get_config(vntsd_t *vntsdp) { int i; int num_cons; vcc_console_t *consp; vntsd_group_t *groupp; /* num of consoles */ num_cons = 0; if (vntsd_vcc_ioctl(VCC_NUM_CONSOLE, 0, (void *)&num_cons) != VNTSD_SUCCESS) { vntsd_log(VNTSD_ERR_VCC_IOCTL, "VCC_NUM_CONSOLE failed\n"); return; } D3(stderr, "get_config:num_cons=%d", num_cons); if (num_cons == 0) { return; } /* allocate memory for all consoles */ consp = malloc(num_cons*sizeof (vcc_console_t)); if (consp == NULL) { vntsd_log(VNTSD_ERR_NO_MEM, "for console table."); return; } /* get console table */ if (vntsd_vcc_ioctl(VCC_CONS_TBL, 0, (void *)consp) != VNTSD_SUCCESS) { vntsd_log(VNTSD_ERR_VCC_IOCTL, " VCC_CONS_TBL " "for console table\n"); return; } /* intialize groups and consoles */ for (i = 0; i < num_cons; i++) { if (alloc_cons_with_group(vntsdp, &consp[i], &groupp) != VNTSD_SUCCESS) { vntsd_log(VNTSD_ERR_ADD_CONS_FAILED, "get_config"); } } /* create listen thread for each group */ (void) mutex_lock(&vntsdp->lock); for (; ; ) { groupp = vntsd_que_walk(vntsdp->grouppq, (el_func_t)create_listen_thread); if (groupp == NULL) { break; } vntsd_log(VNTSD_ERR_CREATE_LISTEN_THR, "get config()"); } (void) mutex_unlock(&vntsdp->lock); }
/* 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); }
/* * check the state of listen thread. exit if there is an fatal error * or the group is removed. Main thread will call free_group * to close group socket and free group structure. */ static void listen_chk_status(vntsd_group_t *groupp, int status) { char err_msg[VNTSD_LINE_LEN]; D1(stderr, "t@%d listen_chk_status() status=%d group=%s " "tcp=%lld group status = %x\n", thr_self(), status, groupp->group_name, groupp->tcp_port, groupp->status); (void) snprintf(err_msg, sizeof (err_msg), "Group:%s TCP port %lld status %x", groupp->group_name, groupp->tcp_port, groupp->status); switch (status) { case VNTSD_SUCCESS: return; case VNTSD_STATUS_ACCEPT_ERR: return; case VNTSD_STATUS_INTR: assert(groupp->status & VNTSD_GROUP_SIG_WAIT); /*FALLTHRU*/ case VNTSD_STATUS_NO_CONS: default: /* fatal error or no console in the group, remove the group. */ (void) mutex_lock(&groupp->lock); if (groupp->status & VNTSD_GROUP_SIG_WAIT) { /* * group is already being deleted, notify main * thread and exit. */ groupp->status &= ~VNTSD_GROUP_SIG_WAIT; (void) cond_signal(&groupp->cvp); (void) mutex_unlock(&groupp->lock); thr_exit(0); } /* * if there still is console(s) in the group, * the console(s) could not be connected any more because of * a fatal error. Therefore, mark the console and notify * main thread to delete console and group. */ (void) vntsd_que_walk(groupp->conspq, (el_func_t)vntsd_mark_deleted_cons); groupp->status |= VNTSD_GROUP_CLEAN_CONS; /* signal main thread to delete the group */ (void) thr_kill(groupp->vntsd->tid, SIGUSR1); (void) mutex_unlock(&groupp->lock); /* log error */ if (status != VNTSD_STATUS_NO_CONS) vntsd_log(status, err_msg); thr_exit(0); } }