int main(int ac, char *av[]){ setup(); if(get_ticket() != 0) exit(0); do_regular_work(); release_ticket(); shut_down(); }
/********* ** The inhabitant thread function ** args : structure with inhabitant's arguments **********/ void *inhabitant_thread_fn(void *args) { bool take_ticket; inhabitant_params_t params = *(inhabitant_params_t *)args; uint32_t id = params.id; printf("inhabitant #%d: start\n", params.id); while (true) { usleep(params.d0); take_ticket = true; while (take_ticket) { // Lock access to the queue sem_wait(&(params.bank->mutex_queue)); uint32_t t = get_ticket(params.bank); params.bank->queue[id].t = t; printf("inhabitant #%d got ticket %d\n", id, t); uint32_t inhabitant_before = get_inhabitant_before(params.bank, t); // Decide to goes way or not bool is_away = inhabitant_before > 3 && decide_goes_away(¶ms.rng, params.p); params.bank->queue[id].is_away = is_away; // Unlock access to the queue sem_post(&(params.bank->mutex_queue)); // Inhabitant decided to goes away if (is_away) { printf("inhabitant #%d goes away\n", id); usleep(inhabitant_before * params.d1); printf("inhabitant #%d returned to the bank\n", id); // Lock access to the queue sem_wait(&(params.bank->mutex_queue)); // Check if his ticket is already expired ticket_expired = get_ticket_expired(params.bank, t); if (ticket_expired) { printf("inhabitant #%d ticket expired\n", id); } params.bank->queue[id].is_away = false; // Unlock access to the queue sem_post(&(params.bank->mutex_queue)); } else { printf("inhabitant #%d doesn't goes away\n", id); } // Inhabitant is in the bank and his ticket is valid if (!is_away || !ticket_expired) { printf("inhabitant #%d stands in line\n", id); // Inhabitant wait in the queue, he will be waked by the bank_manager // when he has been served stand_in_line(params.bank, id); take_ticket = false; printf("inhabitant #%d has been served\n", id); } } } return NULL; }
/*-------------------------------------------------------------------------*/ socket_t * new_socket(int fd, char type) /* Create a socket_t of <type> for <fd>, assign it a ticket and add it to * the socket list. * Return the pointer to the socket structure. */ { socket_t *sp; sp = malloc(sizeof(struct socket_s)); XPRINTF((stderr, "%s New socket %p: fd %d\n", time_stamp(), sp, fd)); sp->next = sockets; sp->fd = fd; sp->type = type; sp->ticket.seq = (seq_number+=seq_interval); sp->ticket.rnd = get_ticket(); sp->queue = NULL; sockets = sp; return sp; } /* new_socket() */
// 显示车次信息页面 static void traininfo_menu(int num){ int index=1; int i_traininfo=0; int order_result=0; int ticket_result=0; char t_num[20]; char ticket_num[10]; char commend[1]; time_t now; erase(); cbreak(); noecho(); mvprintw(3, 25, "%s", "欢迎访问模拟铁路订票系统!"); mvprintw(5, 1, "%s", "火车编号"); mvprintw(5, 11, "%s", "日期"); mvprintw(5, 21, "%s", "车次号"); mvprintw(5, 29, "%s", "出发站"); mvprintw(5, 37, "%s", "到达站"); mvprintw(5, 45, "%s", "出发时间"); mvprintw(5, 55, "%s", "到达时间"); mvprintw(5, 65, "%s", "票价"); mvprintw(5, 71, "%s", "余票张数"); for(;num!=0;num--){ mvprintw(num+5, 1, "%d", static_traininfo[num-1].tid); mvprintw(num+5, 11, "%d/%d/%d", static_message.ticket_data.departure_date.tm_year+1900, static_message.ticket_data.departure_date.tm_mon+1, static_message.ticket_data.departure_date.tm_mday); mvprintw(num+5, 21, "%s", static_traininfo[num-1].t_num); mvprintw(num+5, 29, "%s", static_traininfo[num-1].originator); mvprintw(num+5, 37, "%s", static_traininfo[num-1].terminal); mvprintw(num+5, 45, "%d:%d:%d", static_traininfo[num-1].departure_time.tm_hour, static_traininfo[num-1].departure_time.tm_min, static_traininfo[num-1].departure_time.tm_sec); mvprintw(num+5, 55, "%d:%d:%d", static_traininfo[num-1].arrival_time.tm_hour, static_traininfo[num-1].arrival_time.tm_min, static_traininfo[num-1].arrival_time.tm_sec); static_message.ticket_data=get_ticket(static_traininfo[num-1].tid, &(static_message.ticket_data.departure_date)); static_ticket[num-1]=static_message.ticket_data; mvprintw(num+5, 65, "%d", static_ticket[num-1].price); mvprintw(num+5, 71, "%d", static_ticket[num-1].num); } mvprintw(20, 30, "%s", "1. 订票"); mvprintw(20, 50, "%s", "2. 返回上一页"); refresh(); while(index){ commend[0]=getch(); switch(commend[0]){ case '1': echo(); nocbreak(); mvprintw(21, 30, "请输入车次号:"); getstr(t_num); mvprintw(22, 30, "请输入张数:"); getstr(ticket_num); static_message.order_data.num=atoi(ticket_num); while(strcmp(static_traininfo[i_traininfo].t_num, t_num)) i_traininfo++; static_message.order_data.uid=static_message.userinfo_data.uid; static_message.order_data.tid=static_traininfo[i_traininfo].tid; static_message.order_data.departure_date=static_message.ticket_data.departure_date; static_message.order_data.price=static_ticket[i_traininfo].price*static_message.order_data.num; time(&now); static_message.order_data.rise_time=*(localtime(&now)); static_message.order_data.state=STATE_BEFORE_PAYMENT; static_ticket[i_traininfo].num-=static_message.order_data.num; order_result=add_order(static_message.order_data); ticket_result=modify_ticket(static_ticket[i_traininfo]); if(order_result&&ticket_result){ mvprintw(23, 30, "%s", "订票成功,返回主界面中...!"); }else{ mvprintw(23, 30, "%s", "订票失败,返回主界面中...!"); } refresh(); sleep(3); main_menu(); index=0; break; case '2': echo(); nocbreak(); main_menu(); index=0; break; default: mvprintw(23, 30, "%s", "无效的命令!"); break; } } }
/*-------------------------------------------------------------------------*/ int main(int argc, char *argv[]) /* The main program and -loop of the ERQ. */ { int num; master_pid = getpid(); /* Print information about this daemon to help debugging */ { fprintf(stderr, "%s XERQ %s: Path '%s', debuglevel %d\n" , time_stamp(), __DATE__, argv[0], ERQ_DEBUG ); } /* Quick and dirty commandline parser */ { int is_forked = 0; int i; for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "--forked")) is_forked = 1; else if (!strcmp(argv[i], "--execdir")) { if (i+1 >= argc) { fprintf(stderr, "%s Missing value for --execdir.\n" , time_stamp()); die(); } erq_dir = argv[i+1]; i++; } else { fprintf(stderr, "%s Unknown argument '%s'.\n" , time_stamp(), argv[i]); die(); } } /* Check if we have been forked off the driver */ if (is_forked) { write(1, "1", 1); /* indicate sucessful fork/execl */ fprintf(stderr, "%s Demon started\n", time_stamp() ); } else { fprintf(stderr, "%s Dynamic attachment unimplemented\n" , time_stamp()); die(); } } /* Initialize */ in_select = 0; pending_sig = 0; signal(SIGCLD, sig_child); signal(SIGPIPE, SIG_IGN); sockets = NULL; childs = NULL; retries = NULL; stdout_queue = NULL; randomize(time(0)); seq_number = get_ticket(); seq_interval = get_ticket() | 1; /* make sure it is odd */ #ifdef DETACH /* Detach from console */ num = open("/dev/tty", O_RDWR); if (num >= 0) { ioctl(num, TIOCNOTTY, 0); close(num); } #endif /* The main loop */ while(1) { fd_set read_fds, write_fds; int num_fds; child_t *chp; retry_t *rtp, **rtpp; socket_t *sp; struct timeval timeout; /* Clean up the list of children (may close some sockets) */ for (chp = childs; chp;) { child_t *this = chp; chp = chp->next; /* If there is a pending SIG_CLD for this child, handle it. * This is to be expected for CHILD_FORK children. */ if (pending_sig && this->pid == pending_pid) { if (this->type != CHILD_FORK) fprintf(stderr, "%s Pending SIG_CLD for pid %d delivered.\n" , time_stamp(), pending_pid); this->status = pending_status; this->pid = pending_pid; pending_sig = 0; } if (this->status == CHILD_EXITED) { XPRINTF((stderr, "%s Child %p exited.\n", time_stamp(), this)); remove_child(this); /* will also unlink it from the list */ } } /* look for sockets to select on */ FD_ZERO(&read_fds); FD_ZERO(&write_fds); FD_SET(0, &read_fds); if (stdout_queue) FD_SET(1, &write_fds); num_fds = 2; for (sp = sockets; sp; sp = sp->next) { switch(sp->type) { case SOCKET_WAIT_CONNECT: case SOCKET_WAIT_AUTH: FD_SET(sp->fd, &write_fds); FD_SET(sp->fd, &read_fds); if (sp->fd >= num_fds) num_fds=sp->fd+1; break; default: FD_SET(sp->fd, &read_fds); if (sp->fd >= num_fds) num_fds=sp->fd+1; break; case SOCKET_WAIT_ACCEPT: /* do nothing */; /* Without the ; above, Metrowerks Codewarrior reports * an error :-( */ } if (sp->queue) FD_SET(sp->fd, &write_fds); } /* for (sockets) */ /* Scan the list of pending retries for the soonest one. * Put the time till then into timeout. * (If the list is empty, select() will receive NULL for timeout). */ if (retries) { time_t t; t = retries->time; for (rtp = retries; rtp; rtp = rtp->next) { if (rtp->time < t) t = rtp->time; } timeout.tv_sec = t - time(NULL); timeout.tv_usec = 0; XPRINTF((stderr, "%s Soonest retry_t: in %ld seconds.\n" , time_stamp(), (long)timeout.tv_sec)); if (timeout.tv_sec < 0) timeout.tv_sec = 0; } #if ERQ_DEBUG > 1 fprintf(stderr, "%s select()\n", time_stamp()); #endif in_select = 1; /* so sig_child() can write reply directly */ num = select(num_fds, &read_fds, &write_fds, 0, retries ? &timeout : 0); in_select = 0; /* don't want sig_child() writing now */ #if ERQ_DEBUG > 1 { int myerrno = errno; fprintf(stderr, "%s select() returns %d, time() %ld\n" , time_stamp(), num, (long)time(NULL)); errno = myerrno; } #endif #if ERQ_DEBUG > 0 if (num < 0) /* Give an error now, but don't abort this loop, * because the retries have to be handled first. */ { int myerrno = errno; fprintf(stderr, "%s select() errno = %d", time_stamp(), errno); errno = myerrno; perror(" "); } #endif /* Is stdout ready to write? Then flush the queue. */ if (num >= 0 && FD_ISSET(1, &write_fds)) { XPRINTF((stderr, "%s stdout_queue ready for flush.\n", time_stamp())); flush_queue(&stdout_queue, 1, 0); } /* Check for retries */ for (rtpp = &retries; *rtpp; ) { rtp = *rtpp; if (rtp->time <= time(NULL)) { XPRINTF((stderr, "%s Call retry %p (time %ld)\n" , time_stamp(), rtp, (long)rtp->time)); (*(rtp->func))(rtp->mesg, read_32(rtp->mesg)); *rtpp = rtp->next; free(rtp); } else { rtpp = &rtp->next; } } /* Error in select */ if (num < 0) continue; /* check for input from driver */ if (FD_ISSET(0, &read_fds)) { XPRINTF((stderr, "%s New command from driver.\n", time_stamp())); erq_cmd(); } /* Handle the ready sockets. * Remember that read_socket() may close the socket. */ for (sp = sockets; sp; ) { socket_t *this = sp; int rc; sp = sp->next; rc = 0; if (FD_ISSET(this->fd, &read_fds)) { XPRINTF((stderr, "%s Socket %p (%d) ready for reading.\n" , time_stamp(), this, this->fd)); rc = read_socket(this, 0); } if (!rc && FD_ISSET(this->fd, &write_fds)) { XPRINTF((stderr, "%s Socket %p (%d) ready for writing.\n" , time_stamp(), this, this->fd)); (void)read_socket(this, 1); } } } /* while(1) */ /* NOTREACHED */ return 0; } /* main() */
//定义所有客户端请求命令的处理函数 void exec_request(const message_data message_request){ message_data message_response; int end_index=0; char log[250]; message_response=message_request; message_response.response=s_success; switch(message_request.request){ case c_add_userinfo: if(!add_userinfo(message_request.userinfo_data)){ message_response.response=s_failure; sprintf(log, " 用户 %s 注册失败.", message_request.userinfo_data.u_name); sys_log(log); }else{ sprintf(log, " 用户 %s 注册成功.", message_request.userinfo_data.u_name); sys_log(log); } break; case c_get_userinfo: message_response.userinfo_data=get_userinfo(message_request.userinfo_data.u_name, message_request.userinfo_data.pwd); userinfo userinfo_cmp; memset(&userinfo_cmp, 0, sizeof(userinfo_cmp)); if(!memcmp(&userinfo_cmp, &(message_response.userinfo_data), sizeof(userinfo))) { message_response.response=s_failure; sprintf(log, "获取用户 %s 资料失败.", message_request.userinfo_data.u_name); sys_log(log); }else{ sprintf(log, " 获取用户 %s 资料成功.", message_request.userinfo_data.u_name); sys_log(log); } break; case c_modify_userinfo: if(!modify_userinfo(message_request.userinfo_data)) { message_response.response=s_failure; sprintf(log, "修改用户 %s 资料失败.", message_request.userinfo_data.u_name); sys_log(log); }else{ sprintf(log, " 修改用户 %s 资料成功.", message_request.userinfo_data.u_name); sys_log(log); } break; case c_get_traininfo_by_t_num: message_response.traininfo_data=get_traininfo_by_t_num(message_request.traininfo_data.t_num); traininfo traininfo_cmp; memset(&traininfo_cmp, 0, sizeof(traininfo_cmp)); if(!memcmp(&traininfo_cmp, &(message_response.traininfo_data), sizeof(traininfo))){ message_response.response=s_failure; sprintf(log, "用户 %s 获取车次 %s 信息失败.", message_request.userinfo_data.u_name, message_request.traininfo_data.t_num); sys_log(log); }else{ sprintf(log, "用户 %s 获取车次 %s 信息成功.", message_request.userinfo_data.u_name, message_request.traininfo_data.t_num); sys_log(log); } break; case c_get_traininfo_by_o_and_t: while(!end_index){ message_response.traininfo_data=get_traininfo_by_o_and_t(message_request.traininfo_data.originator, message_request.traininfo_data.terminal); traininfo traininfo_cmp; memset(&traininfo_cmp, 0, sizeof(traininfo_cmp)); if(!memcmp(&traininfo_cmp, &(message_response.traininfo_data), sizeof(traininfo))){ message_response.response=s_failure; end_index=1; }else{ if(!send_response_to_client(message_response)){ fprintf(stderr, "Server Warning: fail to response to %d. \n", message_response.client_pid); sprintf(log, "用户 %s 获取车次 %s 信息失败.", message_request.userinfo_data.u_name, message_response.traininfo_data.t_num); sys_log(log); }else{ sprintf(log, "用户 %s 获取车次 %s 信息成功.", message_request.userinfo_data.u_name, message_response.traininfo_data.t_num); sys_log(log); } } } break; case c_get_ticket: message_response.ticket_data=get_ticket(message_request.ticket_data.tid, &(message_request.ticket_data.departure_date)); ticket ticket_cmp; memset(&ticket_cmp, 0, sizeof(ticket_cmp)); if(!memcmp(&ticket_cmp, &(message_response.ticket_data), sizeof(ticket))) message_response.response=s_failure; break; case c_modify_ticket: if(!modify_ticket(message_request.ticket_data)) message_response.response=s_failure; break; case c_add_order: if(!add_order(message_request.order_data)){ message_response.response=s_failure; sprintf(log, "用户 %s 购买 Tid 为 %d 的车次火车票 %d 张失败.", message_request.userinfo_data.u_name, message_request.order_data.tid, message_request.order_data.num); sys_log(log); }else{ sprintf(log, "用户 %s 购买 Tid 为 %d 的车次火车票 %d 张成功.", message_request.userinfo_data.u_name, message_request.order_data.tid, message_request.order_data.num); sys_log(log); } break; case c_get_orders: while(!end_index){ message_response.order_data=get_orders(message_request.order_data.uid); orders order_cmp; memset(&order_cmp, 0, sizeof(order_cmp)); if(!memcmp(&order_cmp, &(message_response.order_data), sizeof(orders))){ message_response.response=s_failure; end_index=1; }else{ if(!send_response_to_client(message_response)){ fprintf(stderr, "Server Warning: fail to response to %d. \n", message_response.client_pid); sprintf(log, "获取用户 %s 订单 %d 信息失败.", message_request.userinfo_data.u_name, message_response.order_data.oid); sys_log(log); }else{ sprintf(log, "获取用户 %s 订单 %d 信息成功.", message_request.userinfo_data.u_name, message_response.order_data.oid); sys_log(log); } } } break; case c_modify_order: if(!modify_order(message_request.order_data)){ message_response.response=s_failure; sprintf(log, "修改用户 %s 订单 %d 信息失败.", message_request.userinfo_data.u_name, message_request.order_data.oid); sys_log(log); }else{ sprintf(log, "修改用户 %s 订单 %d 信息成功.", message_request.userinfo_data.u_name, message_request.order_data.oid); sys_log(log); } break; default: message_response.response=s_failure; break; } if(!send_response_to_client(message_response)){ fprintf(stderr, "Server Warning: fail to response to %d. \n", message_response.client_pid); return; } return; }