/* get sticks for philosopher n */ void getsticks( i4 n) { #ifdef EX_DEBUG EXsignal(get_exc, 1, n); #endif /* ** While you can't get both sticks, give control to others who ** might eventually free the ones you need */ for( ;; ) { Psem( &Freesem ); if( Freesticks[ n ] == 2 ) break; Vsem( &Freesem ); CSswitch(); } /* ASSERT: phil n holds Freesem and Freesticks[ n ] == 2. */ Freesticks[ n ] -= 2; --Freesticks[ LEFT( n ) ]; --Freesticks[ RIGHT( n ) ]; CSswitch(); /* gratuitous; tests semaphores */ Vsem( &Freesem ); }
/* Observe that philosopher n is eating */ void eats( i4 n) { #ifdef EX_DEBUG EX_CONTEXT context; if (EXdeclare(ex_handler, &context) != OK) { /* some exception was raised */ Psem( &SIsem ); SIfprintf( stderr,"Error: unexpected exception in eats()..."); Vsem( &SIsem ); EXdelete(); return; } #endif if( Noisy ) { Psem( &SIsem ); SIfprintf(stderr, "%d (%s) eats...\n", n, Names[ n ] ); Vsem( &SIsem ); } CSswitch(); #ifdef EX_DEBUG EXdelete(); #endif }
/* Observe that philosopher n is thinking */ void thinks( i4 n) { #ifdef EX_DEBUG EX_CONTEXT context; if (EXdeclare(ex_handler, &context) != OK) { /* some exception was raised */ Psem( &SIsem ); SIfprintf( stderr,"exception raised while thinking, OK...\n"); Vsem( &SIsem ); EXdelete(); return; } #endif if( Noisy ) { Psem( &SIsem ); SIfprintf(stderr, "%d (%s) thinks...\n", n, Names[ n ] ); Vsem( &SIsem ); } CSswitch(); #ifdef EX_DEBUG EXsignal(not_handled, 0); Psem( &SIsem ); SIfprintf( stderr,"Error: should not be reached in thinks()..."); Vsem( &SIsem ); EXdelete(); #endif }
/* release sticks held by philosopher n */ void freesticks( i4 n) { #ifdef EX_DEBUG EX_CONTEXT context; if (EXdeclare(ex_handler2, &context) != OK) { /* free_exc error should never be EX_DECLARE'd. */ Psem( &SIsem ); SIfprintf( stderr,"Error: unexpected exception in freesticks()..."); Vsem( &SIsem ); EXdelete(); return; } #endif Psem( &Freesem ); #ifdef EX_DEBUG EXsignal(free_exc, 1, n); #endif Freesticks[ n ] += 2; ++Freesticks[ LEFT( n ) ]; ++Freesticks[ RIGHT( n ) ]; CSswitch(); /* gratuitous, tests semaphores */ Vsem( &Freesem ); #ifdef EX_DEBUG EXdelete(); #endif }
DB_STATUS qen_tsort( QEN_NODE *node, QEF_RCB *qef_rcb, QEE_DSH *dsh, i4 function ) { QEF_CB *qef_cb = dsh->dsh_qefcb; PTR *cbs = dsh->dsh_cbs; ADE_EXCB *ade_excb; DMR_CB *dmr_load = (DMR_CB*)cbs[node->node_qen.qen_tsort.tsort_load]; DMR_CB *dmr_get = (DMR_CB*) cbs[node->node_qen.qen_tsort.tsort_get]; QEN_NODE *out_node = node->node_qen.qen_tsort.tsort_out; QEE_XADDRS *node_xaddrs = dsh->dsh_xaddrs[node->qen_num]; QEN_STATUS *qen_status = node_xaddrs->qex_status; QEN_SHD *shd = dsh->dsh_shd[node->node_qen.qen_tsort.tsort_shd]; DB_STATUS status; bool reset = FALSE; bool heap_sort = TRUE, no_qef = FALSE; i4 rowno; i4 out_func = NO_FUNC; DM_MDATA dm_mdata; i4 val1; i4 val2; TIMERSTAT timerstat; i4 loop_cntr = 0; if (function != 0) { if (function & FUNC_RESET) { reset = TRUE; out_func = FUNC_RESET; } /* Do open processing, if required. Only if this is the root node ** of the query tree do we continue executing the function. */ if ((function & TOP_OPEN || function & MID_OPEN) && !(qen_status->node_status_flags & QEN1_NODE_OPEN)) { status = (*out_node->qen_func)(out_node, qef_rcb, dsh, MID_OPEN); qen_status->node_status_flags = QEN1_NODE_OPEN; if (function & MID_OPEN) return(E_DB_OK); function &= ~TOP_OPEN; } /* Do close processing, if required. */ if (function & FUNC_CLOSE) { if (!(qen_status->node_status_flags & QEN8_NODE_CLOSED)) { status = (*out_node->qen_func)(out_node, qef_rcb, dsh, FUNC_CLOSE); qen_status->node_status_flags = (qen_status->node_status_flags & ~QEN1_NODE_OPEN) | QEN8_NODE_CLOSED; } return(E_DB_OK); } if (function & FUNC_EOGROUP) { /* End of partition group request ends our sort if we're returning ** rows. If we aren't in the middle of returning rows, pass the ** EOG request on down so that the child skips the upcoming group ** and moves on to the next one. */ if (qen_status->node_status == QEN3_GET_NEXT_INNER) { status = qen_ts_reset(dsh, node, qen_status); /* FIXME we should do better at remembering whether this ** sort load got EOF or EOG, and pass it on up now. At ** present (Apr '07), tsorts aren't very common except under ** merge join plans, where early eof detection doesn't ** matter much. (the tsort is on the outer side.) ** For now, pass EOG back up, if we're really at EOF caller ** will find out soon enough. */ if (status == E_DB_OK) { status = E_DB_WARN; dsh->dsh_error.err_code = E_QE00A5_END_OF_PARTITION; } } else { status = (*out_node->qen_func)(out_node, qef_rcb, dsh, FUNC_EOGROUP); /* Pass resulting EOF or EOG indication in dsh up to caller */ } return(status); } } /* if function != 0 */ /* Check for cancel, context switch if not MT */ CScancelCheck(dsh->dsh_sid); if (QEF_CHECK_FOR_INTERRUPT(qef_cb, dsh) == E_DB_ERROR) return (E_DB_ERROR); /* If the trace point qe90 is turned on then gather cpu and dio stats */ if (dsh->dsh_qp_stats) { qen_bcost_begin(dsh, &timerstat, qen_status); } if (node->node_qen.qen_tsort.tsort_dups == DMR_NODUPLICATES && ult_check_macro(&qef_cb->qef_trace, 92, &val1, &val2)) heap_sort = FALSE; if (ult_check_macro(&qef_cb->qef_trace, 94, &val1, &val2)) { no_qef = TRUE; qen_status->node_u.node_sort.node_sort_status = QEN9_DMF_SORT; } #ifdef xDEBUG (VOID) qe2_chk_qp(dsh); #endif for (;;) /* to break off in case of error */ { if (reset && qen_status->node_status != QEN0_INITIAL) { status = qen_ts_reset(dsh, node, qen_status); if (status != E_DB_OK) break; } /* If NO MORE ROWS from this node, just return */ if (qen_status->node_status == QEN4_NO_MORE_ROWS) { dsh->dsh_error.err_code = E_QE0015_NO_MORE_ROWS; status = E_DB_WARN; break; } rowno = node->node_qen.qen_tsort.tsort_mat->qen_output; ade_excb = node_xaddrs->qex_otmat; /* If this is the first time execution, or if the node is reset, ** initialize the sorter. If this is not, just go get a tuple. */ if (qen_status->node_status == QEN0_INITIAL || qen_status->node_status == QEN1_EXECUTED) { if (qen_status->node_status == QEN0_INITIAL) { if (qen_status->node_u.node_sort.node_sort_status == QEN0_QEF_SORT) { status = qes_init(dsh, shd, node, rowno, node->node_qen.qen_tsort.tsort_dups); if (status != E_DB_OK) { if (dsh->dsh_error.err_code == E_QE000D_NO_MEMORY_LEFT) { /* out of space, convert it to DMF sort */ qen_status->node_u.node_sort.node_sort_status = QEN9_DMF_SORT; status = E_DB_OK; } else { break; } } } if (qen_status->node_u.node_sort.node_sort_status == QEN9_DMF_SORT) { status = qen_ts_dump(shd, dsh, node, rowno, heap_sort, no_qef); if (status != E_DB_OK) break; } if (node->node_qen.qen_tsort.tsort_pqual != NULL) qeq_join_pqreset(dsh, node->node_qen.qen_tsort.tsort_pqual); qen_status->node_status = QEN1_EXECUTED; } /* Common code for QEN0_INITIAL and QEN1_EXECUTED */ /* Get dm_mdata ready for DMF loading */ dm_mdata.data_address = dsh->dsh_row[rowno]; dm_mdata.data_size = dsh->dsh_qp_ptr->qp_row_len[rowno]; dmr_load->dmr_mdata = &dm_mdata; dsh->dsh_qp_status |= DSH_SORT; /* Get rows from the underneath node and append them to the ** sorter */ for (;;) { /* fetch rows */ status = (*out_node->qen_func)(out_node, qef_rcb, dsh, out_func); out_func = NO_FUNC; if (status != E_DB_OK) { /* the error.err_code field in qef_rcb should already be ** filled in. */ if (dsh->dsh_error.err_code == E_QE0015_NO_MORE_ROWS) { status = E_DB_OK; } else if (dsh->dsh_error.err_code == E_QE00A5_END_OF_PARTITION && (node->qen_flags & QEN_PART_SEPARATE)) { /* End of rows from partitioning group. Flag the ** fact and make it look like regular "eof". */ qen_status->node_status_flags |= QEN2_OPART_END; dsh->dsh_error.err_code = E_QE0015_NO_MORE_ROWS; status = E_DB_OK; } break; } /* project the attributes into sort tuple row */ status = qen_execute_cx(dsh, ade_excb); if (status != E_DB_OK) break; /* If we're generating partition qualifications on behalf ** of a parent FSM join, eval against this row. */ if (node->node_qen.qen_tsort.tsort_pqual != NULL) { status = qeq_join_pquals(dsh, node->node_qen.qen_tsort.tsort_pqual); if (status != E_DB_OK) break; } /* append the sort tuple into the sorter - note periodic ** differences between heap sort and trace point mandated ** insert sort */ if (qen_status->node_u.node_sort.node_sort_status == QEN0_QEF_SORT) { if (heap_sort) status = qes_putheap(dsh, shd, node->node_qen.qen_tsort.tsort_cmplist, node->node_qen.qen_tsort.tsort_scount); else status = qes_insert(dsh, shd, node->node_qen.qen_tsort.tsort_cmplist, node->node_qen.qen_tsort.tsort_scount); if (status != E_DB_OK && dsh->dsh_error.err_code == E_QE000D_NO_MEMORY_LEFT) { /* out of space, convert it to DMF sort */ qen_status->node_u.node_sort.node_sort_status = QEN9_DMF_SORT; status = qen_ts_dump(shd, dsh, node, rowno, heap_sort, no_qef); } if (status != E_DB_OK) break; } if(qen_status->node_u.node_sort.node_sort_status == QEN9_DMF_SORT) { status = dmf_call(DMR_LOAD, dmr_load); if (status != E_DB_OK) { dsh->dsh_error.err_code = dmr_load->error.err_code; break; } } if (!(Qef_s_cb->qef_state & QEF_S_IS_MT) && (loop_cntr++ >1000)) { /* On an Internal threaded system, after processing 1000 rows ** give another thread a chance. */ loop_cntr = 0; CSswitch(); } } if (status != E_DB_OK) break; /* End of loading loop */ /* Finish up join-time part qual if we're doing it */ if (node->node_qen.qen_tsort.tsort_pqual != NULL) { qeq_join_pqeof(dsh, node->node_qen.qen_tsort.tsort_pqual); } if(qen_status->node_u.node_sort.node_sort_status == QEN0_QEF_SORT) { if (!heap_sort) qes_endsort(dsh, shd); /* prep return of tups */ } else /* DMF */ { /* Tell DMF that there are no more rows */ dmr_load->dmr_flags_mask = (DMR_ENDLOAD | DMR_SORT_NOCOPY); status = dmf_call(DMR_LOAD, dmr_load); if (status != E_DB_OK) { dsh->dsh_error.err_code = dmr_load->error.err_code; break; } /* position the table for reading sorted tuples */ dmr_get->dmr_flags_mask = DMR_SORTGET; dmr_get->dmr_position_type = DMR_ALL; status = dmf_call(DMR_POSITION, dmr_get); if (status != E_DB_OK) { dsh->dsh_error.err_code = dmr_get->error.err_code; break; } } /* Mark the node is ready to return tuples */ qen_status->node_status = QEN3_GET_NEXT_INNER; } /* ** Return a tuple from the sorter to the caller. */ if (qen_status->node_u.node_sort.node_sort_status == QEN0_QEF_SORT) { if (heap_sort) { status = qes_getheap(dsh, shd, node->node_qen.qen_tsort.tsort_cmplist, node->node_qen.qen_tsort.tsort_scount); if (status != E_DB_OK) { if (dsh->dsh_error.err_code == E_QE0015_NO_MORE_ROWS) { qen_status->node_status = QEN4_NO_MORE_ROWS; status = E_DB_WARN; } break; } } else { /* rows come straight from pointer array */ /* Check for the end of buffer */ if (shd->shd_next_tup == shd->shd_tup_cnt) { qen_status->node_status = QEN4_NO_MORE_ROWS; dsh->dsh_error.err_code = E_QE0015_NO_MORE_ROWS; status = E_DB_WARN; break; } /* Copy tuple to the row buffer */ MEcopy((PTR)(shd->shd_vector[shd->shd_next_tup]), shd->shd_width, (PTR)shd->shd_row); ++shd->shd_next_tup; status = E_DB_OK; } } else { dmr_get->dmr_flags_mask = (DMR_NEXT | DMR_SORTGET); status = dmf_call(DMR_GET, dmr_get); if (status != E_DB_OK) { if (dmr_get->error.err_code == E_DM0055_NONEXT) { qen_status->node_status = QEN4_NO_MORE_ROWS; dsh->dsh_error.err_code = E_QE0015_NO_MORE_ROWS; status = E_DB_WARN; } else { dsh->dsh_error.err_code = dmr_get->error.err_code; } break; } } /* status has to be OK here */ /* Increment the count of rows that this node has returned */ qen_status->node_rcount++; dsh->dsh_error.err_code = 0; /* print tracing information DO NOT xDEBUG THIS */ if (node->qen_prow && (ult_check_macro(&qef_cb->qef_trace, 100+node->qen_num, &val1, &val2) || ult_check_macro(&qef_cb->qef_trace, 99, &val1, &val2) ) ) { (void) qen_print_row(node, qef_rcb, dsh); } break; } /* end of error-break loop */ #ifdef xDEBUG (VOID) qe2_chk_qp(dsh); #endif if (dsh->dsh_qp_stats) { qen_ecost_end(dsh, &timerstat, qen_status); } dsh->dsh_qp_status &= ~DSH_SORT; if (dsh->dsh_error.err_code == E_QE0015_NO_MORE_ROWS && (qen_status->node_status_flags & QEN2_OPART_END)) { /* If this was just the end of a partition, reset error code ** to notify the caller. */ qen_status->node_status_flags &= ~QEN2_OPART_END; dsh->dsh_error.err_code = E_QE00A5_END_OF_PARTITION; status = E_DB_WARN; } return (status); }