/* allocate new MF; retains pointer to pthReal! Must free via FreeMf (or CloseMf which calls FreeMf). mm set to mmNil. */ MF * PmfAlloc( PTH pthReal[], char *szTemp, /* 0 -> use base of pthReal */ FX fx) { register MF *pmf; AssertF(pthReal != 0); if (mf1.pthReal == 0) pmf = &mf1; else if (mf2.pthReal == 0) pmf = &mf2; else if (mf3.pthReal == 0) pmf = &mf3; else if (mf4.pthReal == 0) pmf = &mf4; else AssertF(fFalse); /* initialize contents which are not already initialized */ pmf->fx = fx; pmf->pthReal = pthReal; pmf->fNoBuffering = fFalse; pmf->fWritten = fFalse; if (szTemp != 0) NmCopySz(pmf->nmTemp, szTemp, cchFileMax); AssertF(FIsClosedMf(pmf)); return pmf; }
// Inserts the reservation into the required track segments static void reservation_insert(struct reservation_node* reservation, struct location* position, int length, int branch_safety) { int node_direction; struct track_node* node = location_to_node(track, position); if (node->type == NODE_BRANCH) { node_direction = switch_table[node->num] == SWITCH_STRAIGHT ? DIR_STRAIGHT : DIR_CURVED; } else { node_direction = DIR_AHEAD; } struct track_edge* occupied_edge = &(node->edge[node_direction]); int startOffset = position->offset; int r_index = 0; while (length > 0) { int stopOffset = MIN(length + startOffset, occupied_edge->dist); if (occupied_edge->src->type == NODE_BRANCH) { // The is an edge coming from a branch, so we must make sure we cover the whole // length of it so we don't get stuck on the switch stopOffset = occupied_edge->dist; } AssertF(r_index < SEGMENTS_PER_TRAIN, "Too many segments for train reservation"); // Set the forward direction edge's occupied information reservation->reservations[r_index].start = startOffset; reservation->reservations[r_index].stop = stopOffset; reservation->reservations[r_index].edge = occupied_edge; reservation->reservations[r_index].next = occupied_edge->reservation_node; occupied_edge->reservation_node = &reservation->reservations[r_index]; r_index++; // Set the reverse direction edge's occupied information AssertF(r_index < SEGMENTS_PER_TRAIN, "Too many segments for train reservation"); reservation->reservations[r_index].start = occupied_edge->dist - stopOffset; reservation->reservations[r_index].stop = occupied_edge->dist - startOffset; reservation->reservations[r_index].edge = occupied_edge->reverse; reservation->reservations[r_index].next = occupied_edge->reverse->reservation_node; occupied_edge->reverse->reservation_node = &reservation->reservations[r_index]; r_index++; length = length - (stopOffset - startOffset); // If this is a branch and the reservation ends somewhere in the next edge, make // sure we take branch safety into consideration if (occupied_edge->src->type == NODE_BRANCH) { length = MAX(length, branch_safety); } if (occupied_edge->dest->type == NODE_BRANCH) { node_direction = switch_table[occupied_edge->dest->num] == SWITCH_STRAIGHT ? DIR_STRAIGHT : DIR_CURVED; } else { node_direction = DIR_AHEAD; } occupied_edge = &occupied_edge->dest->edge[node_direction]; startOffset = 0; } }
int dist_between_nodes(int start_num, int end_num) { struct track_node *start = &track[start_num]; struct track_node *end = &track[end_num]; AssertF(track != 0 && start != 0 && end != 0, "BAD INPUT TO dist_betwen_nodes", 0); int distance = 0; struct track_node *current = start; while (current->num != end->num || current->type != end->type) { if (current->type == NODE_EXIT) { return 0; } else if (current->type == NODE_BRANCH) { int switch_direction = switch_table[current->num]; int node_direction = (switch_direction == SWITCH_STRAIGHT ? DIR_STRAIGHT : DIR_CURVED); distance += current->edge[node_direction].dist; current = current->edge[node_direction].dest; } else { distance += current->edge[DIR_AHEAD].dist; current = current->edge[DIR_AHEAD].dest; } if (current == start) { // HORRY SHIITTu, WE ARE IN A ROOP! return -1; } } return distance; }
/* Open one of the two static MF structures dedicated for local files. */ MF * OpenLocalMf( char *pszLocalFileName) { register MF *pmf; int wRetErr; if (mfLocal1.fdWrite == fdNil) pmf = &mfLocal1; else if (mfLocal2.fdWrite == fdNil) pmf = &mfLocal2; else { AssertF(fFalse); return NULL; } pmf->pthReal = malloc(strlen(pszLocalFileName) + 1); if (pmf->pthReal) { strcpy(pmf->pthReal, pszLocalFileName); pmf->fdWrite = _open(pmf->pthReal, O_APPEND|O_WRONLY|O_CREAT, S_IREAD|S_IWRITE); } if (pmf->fdWrite == fdNil) FatalError("Unable to open file (%s) for write access\n", pszLocalFileName); else { pmf->pos = SeekMf(pmf, (POS)0, 2); pmf->fWritten = fFalse; } return pmf; }
int TrackSwitchDirection(int train, int switch_node, int next_node, int tid) { int reserved; struct track_request_message msg; msg.operation = TRACK_OP_SWITCH_DIRECTION; msg.train = train; msg.node1 = switch_node; msg.node2 = next_node; AssertF(Send(tid, (char*)&msg, sizeof(msg), (char*)&reserved, sizeof(reserved)) >= 0, "Send() failed in TrainSwitchDirection"); return reserved; }
/* return fTrue if the mf is allocated and otherwise valid */ F FIsValidMf( MF *pmf) { if (pmf != &mfStdin && pmf != &mfStdout && pmf != &mfStderr && pmf != &mfStdlog && pmf != &mfLocal1 && pmf != &mfLocal2 && pmf != &mf1 && pmf != &mf2 && pmf != &mf3 && pmf != &mf4) return fFalse; if (pmf->pthReal == 0) return fFalse; /* check for proper configuration */ switch(pmf->mm) { default: AssertF(fFalse); case mmNil: break; case mmDelTemp: case mmInstall: case mmInstall1Ed: case mmRenTemp: case mmRenTempRO: case mmRenReal: case mmAppToReal: case mmCreate: if (FEmptyNm(pmf->nmTemp)) return fFalse; break; case mmDelReal: case mmSetRO: case mmSetRW: if (!FEmptyNm(pmf->nmTemp)) return fFalse; break; } if (pmf->fFileLock && pmf->fdWrite < 0) return fFalse; return fTrue; }
int next_sensor_node(int start_num, int direction, int *target_distance) { struct track_node *start_node = &track[start_num]; AssertF(track != 0 && start_node != 0 && target_distance != 0, "BAD INPUT TO NEXT_SENSOR_NODE", 0); struct track_node *current = start_node; *target_distance = 0; while (1) { if (current->type == NODE_EXIT) { break; } else if (current->type == NODE_BRANCH) { int switch_direction = switch_table[current->num]; if (direction != -1) { switch_direction = direction; } AssertF(switch_direction != -1, "SwitchGetDirection returned -1\r"); int node_direction = (switch_direction == SWITCH_STRAIGHT ? DIR_STRAIGHT : DIR_CURVED); *target_distance += current->edge[node_direction].dist; current = current->edge[node_direction].dest; } else { *target_distance += current->edge[DIR_AHEAD].dist; current = current->edge[DIR_AHEAD].dest; } // if the sensor is broken, we must skip this one! if (current->type == NODE_SENSOR) { return current->num; } if (current == start_node) { // we are in a loop! Assert("Next Sensor Node is in a loop!"); } } return -1; }
static int reservation_available(int train, struct track_edge* edge, int startOffset, int stopOffset) { // Check if this segment of track is occupied y a train AssertF(edge != 0, "res_avail: EDGE PASSED IN IS NULL!"); struct reservation* r = edge->reservation_node; while (r != 0) { if (r->train != train && ((startOffset >= r->start && startOffset <= r->stop) || (stopOffset >= r->start && stopOffset <= r->stop) || (startOffset <= r->start && stopOffset >= r->stop))) { // Now we are really crossing the line. Report that // reservation failed! return 0; } r = r->next; } return 1; }
static int dist_until_goal(int start_num, int start_offset, int end_num, int end_offset, int max_distance) { struct track_node *start = &track[start_num]; struct track_node *end = &track[end_num]; AssertF(track != 0 && start != 0 && end != 0, "BAD INPUT TO dist_until_goal", 0); int distance = 0 - start_offset; struct track_node *current = start; while (!(current->num == end->num && current->type == end->type)) { if (current->type == NODE_EXIT) { return 0; } else if (current->type == NODE_BRANCH) { int switch_direction = switch_table[current->num]; int node_direction = (switch_direction == SWITCH_STRAIGHT ? DIR_STRAIGHT : DIR_CURVED); distance += current->edge[node_direction].dist; current = current->edge[node_direction].dest; } else { distance += current->edge[DIR_AHEAD].dist; current = current->edge[DIR_AHEAD].dest; } if (current == start) { // HORRY SHIITTu, WE ARE IN A ROOP! return max_distance; } if (distance >= max_distance) { return max_distance; } } distance += end_offset; // make sure distance is >= 0, and <= max_distance: return MIN(MAX(0, distance), max_distance); }
/* Records the mf (if not already) and makes the mf available for use; we ensure that the mf is back the initial state */ void FreeMf( MF *pmf) { static char *mpmmsz[] = { "nil\n", /* mmNil */ "delete %@T\n", /* mmDelTemp */ "clear %@R\n", /* mmDelReal */ "rename %@T %@R\n", /* mmRenTemp */ "install %@T %@R\n", /* mmInstall */ "renreal %@T %@R\n", /* mmRenReal */ "append %@T %@R\n", /* mmAppToReal */ "makero %@R\n", /* mmSetRO */ "makerw %@R\n", /* mmSetRW */ "rename %@T %@R\n", /* mmRenTempRO ( + makero) */ "link %@R %@N\n", /* mmLinkReal */ "create %@R\n", /* mmCreate */ "install1Ed %@T %@R\n" /* mmInstall1Ed */ }; AssertF(FIsClosedMf(pmf)); if (pmf->mm != mmNil) { AppendScript(pmf->fx, mpmmsz[pmf->mm], pmf, pmf); if (pmf->mm == mmRenTempRO) AppendScript(pmf->fx, mpmmsz[mmSetRO], pmf, pmf); } pmf->mm = mmNil; pmf->fx = fxNil; pmf->pthReal = 0; *pmf->nmTemp = '\0'; pmf->fdRead = fdNil; pmf->fdWrite = fdNil; pmf->fFileLock = fFalse; pmf->fNoBuffering = fFalse; pmf->fWritten = fFalse; }
// Entry point of track-server void track_server_entry() { RegisterAs(TRACK_SERVER); // Initialize the track track_init(); // Initialize the reservation list reservation_init(train_reservations); // So we can update our own cached copy of the switch table int switch_courier_tid = CreateSwitchCourier(PRIORITY_HIGHEST - 1); int sender_tid; // Message buffer large enough to hold the largest message request char message_buffer[32]; while (1) { Receive(&sender_tid, message_buffer, sizeof(message_buffer)); if (sender_tid == switch_courier_tid) { // This is an update from the switch server, record the switch that changed // so that our cached table of switches is in sync int reply = 0; Reply(sender_tid, (char*)&reply, sizeof(reply)); struct switch_report* report = (struct switch_report*)message_buffer; switch_table[(int)report->sw] = report->direction; } else { // API requests to the track_server struct track_reply_message reply = {-1, -1}; int op = *(int*)message_buffer; switch(op) { // Handle track reservation requests case TRACK_OP_RESERVATION: { int reply = -1; struct reservation_request_message* reservation_msg = (struct reservation_request_message*)message_buffer; // Make the location be a sensor and positive offset that fits in the edge if (normalize_location(track, switch_table, &reservation_msg->position) != -1) { // Check if we can reserve this space for the train int status = reservation_verify(reservation_msg->train, &(reservation_msg->position), reservation_msg->length, reservation_msg->branch_safety); reply = status; if (status == 0) { // We succeeded. Reserve the track // Find the train's reservation_node struct reservation_node* train_r = get_reservation(train_reservations, reservation_msg->train); if (train_r != 0) { clear_train_reservations(train_r); // Add new reservation reservation_insert(train_r, &(reservation_msg->position), reservation_msg->length, reservation_msg->branch_safety); } } else if (status == -2) { // Reached max reservation } } else { Printf("Could not normalize\r"); } Reply(sender_tid, (char*)&reply, sizeof(reply)); } break; case TRACK_OP_RESERVATION_STRING: { struct reservation_request_message* reservation_msg = (struct reservation_request_message*)message_buffer; struct reservation_node* train_r = get_reservation(train_reservations, reservation_msg->train); char buf[300]; *buf = 0; // null termination character int len = 0; if (train_r != 0) { len = reservation_print(train_r, buf); } Reply(sender_tid, (char*)buf, len); // +1 for null termination char } break; case TRACK_OP_NODE_IS_RESERVED: { struct reservation_request_message* reservation_msg = (struct reservation_request_message*)message_buffer; int reserved = node_is_reserved(reservation_msg->train, reservation_msg->position.node); Reply(sender_tid, (char*)&reserved, sizeof(reserved)); } break; // Handle requests for calculating the distance between 2 nodes case TRACK_OP_TRACK_DISTANCE: { struct track_request_message* track_msg = (struct track_request_message*)message_buffer; if (track_msg->node1 < TRACK_MAX && track_msg->node2 < TRACK_MAX) { reply.distance = dist_between_nodes(track_msg->node1, track_msg->node2); } Reply(sender_tid, (char*)&reply, sizeof(reply)); } break; case TRACK_OP_TRACK_DISTANCE_UNTIL_GOAL: { struct track_request_message* track_msg = (struct track_request_message*)message_buffer; int distance = 0; if (track_msg->node1 < TRACK_MAX && track_msg->node2 < TRACK_MAX) { distance = dist_until_goal(track_msg->node1, track_msg->offset1, track_msg->node2, track_msg->offset2, track_msg->distance); } Reply(sender_tid, (char*)&distance, sizeof(distance)); } break; // Handle requests for getting the next sensor on the track case TRACK_OP_TRACK_NEXT_SENSOR: { struct track_request_message* track_msg = (struct track_request_message*)message_buffer; if (track_msg->node1 >= A1 && track_msg->node1 <= E16) { int distance; int next_sensor = next_sensor_node(track_msg->node1, track_msg->node2, &distance); reply.node = next_sensor; reply.distance = distance; } Reply(sender_tid, (char*)&reply, sizeof(reply)); } break; case TRACK_OP_NORMALIZE: { struct track_request_message *msg = (struct track_request_message*)message_buffer; struct location loc; loc.node = msg->node1; loc.offset = msg->offset1; if (normalize_location(track, switch_table, &loc) == -1) { Reply(sender_tid, (char*)&loc, 0); // reply size 0 means error! } Reply(sender_tid, (char*)&loc, sizeof(loc)); } break; // Handle requests for getting the reverse node of a given node case TRACK_OP_TRACK_REVERSE_NODE: { struct track_request_message* track_msg = (struct track_request_message*)message_buffer; if (track_msg->node1 < TRACK_MAX) { reply.node = track[track_msg->node1].reverse->num; } Reply(sender_tid, (char*)&reply, sizeof(reply)); } break; case TRACK_OP_ROUTE: { struct track_request_message* track_msg = (struct track_request_message*)message_buffer; int train = track_msg->train; int start_node_num = track_msg->node1; int end_node_num = track_msg->node2; short path[TRACK_MAX]; int num_nodes = 0; if (IS_SENSOR(start_node_num) && IS_SENSOR(end_node_num)) { struct track_node *start_node = &track[start_node_num]; struct track_node *end_node = &track[end_node_num]; mark_path(train, track, start_node, end_node); if (end_node->routing_info.visited == 1) { // we have a path! // store all nodes, from bottom up struct track_node *cur_node = end_node; struct location loc; while (cur_node->routing_info.previous != 0 && cur_node != start_node) { node_to_location(cur_node, &loc); path[num_nodes] = loc.node; num_nodes++; if (cur_node->routing_info.previous == cur_node->reverse) { // the next node is the reverse of this node, so we squeeze in a "REVERSE" in the path path[num_nodes] = -99; // magic number for REVERSE commands num_nodes++; } cur_node = cur_node->routing_info.previous; } // we didn't store the beginning node in our path, so we should do that now if (cur_node == start_node) { node_to_location(start_node, &loc); path[num_nodes] = loc.node; num_nodes++; } } else { Printf("Could not find route! num_nodes = %d\r", num_nodes); } } Reply(sender_tid, (char*)path, sizeof(short) * num_nodes); } break; case TRACK_OP_SWITCH_DIRECTION: { struct track_request_message* track_msg = (struct track_request_message*)message_buffer; int switch_node = track_msg->node1; int next_node = track_msg->node2; AssertF(track[switch_node].type == NODE_BRANCH, "TrackSwitchDirection not given a switch node! Given node num %d, type %d", track[switch_node].num, track[switch_node].type); int reserved = node_is_reserved(track_msg->train, switch_node); if (reserved) { // Printf("Attempting to switch %s if reserved .. \r", track[switch_node].name); int direction = -1; if (track[switch_node].edge[DIR_CURVED].dest == &(track[next_node])) { direction = SWITCH_CURVED; } else { direction = SWITCH_STRAIGHT; } SwitchSetDirection(track[switch_node].num, direction, WhoIs(SWITCH_SERVER)); switch_table[track[switch_node].num] = direction; } Reply(sender_tid, (char*)&reserved, sizeof(reserved)); } break; default: AssertF(0, "Invalid message %d to the track server from %d", op, sender_tid); Reply(sender_tid, (char*)&reply, sizeof(reply)); break; } } } Assert("Track server is quitting"); Exit(); }
int reservation_edge_available(int train, struct track_edge* edge) { AssertF(edge != 0, "res_edge_avail: EDGE PASSED IN IS NULL!"); return reservation_available(train, edge, 0, edge->dist); }
void AssertNoMf( void) { AssertF(mf1.pthReal == 0); AssertF(mf2.pthReal == 0); AssertF(mf3.pthReal == 0); AssertF(mf4.pthReal == 0); AssertF(FEmptyNm(mf1.nmTemp)); AssertF(FEmptyNm(mf2.nmTemp)); AssertF(FEmptyNm(mf3.nmTemp)); AssertF(FEmptyNm(mf4.nmTemp)); AssertF(mf1.fdRead == fdNil); AssertF(mf2.fdRead == fdNil); AssertF(mf3.fdRead == fdNil); AssertF(mf4.fdRead == fdNil); AssertF(mf1.fdWrite == fdNil); AssertF(mf2.fdWrite == fdNil); AssertF(mf3.fdWrite == fdNil); AssertF(mf4.fdWrite == fdNil); AssertF(!mf1.fFileLock); AssertF(!mf2.fFileLock); AssertF(!mf3.fFileLock); AssertF(!mf4.fFileLock); AssertF(mf1.mm == mmNil); AssertF(mf2.mm == mmNil); AssertF(mf3.mm == mmNil); AssertF(mf4.mm == mmNil); }