/* * Handler for command with PIO data-in phase (Read/Read Multiple). */ static ide_startstop_t task_in_intr(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; struct request *rq = hwif->rq; u8 stat = hwif->tp_ops->read_status(hwif); /* Error? */ if (stat & ATA_ERR) return task_error(drive, rq, __func__, stat); /* Didn't want any data? Odd. */ if ((stat & ATA_DRQ) == 0) return task_in_unexpected(drive, rq, stat); ide_pio_datablock(drive, rq, 0); /* Are we done? Check status and finish transfer. */ if (!hwif->nleft) { stat = wait_drive_not_busy(drive); if (!OK_STAT(stat, 0, BAD_STAT)) return task_error(drive, rq, __func__, stat); task_end_request(drive, rq, stat); return ide_stopped; } /* Still data left to transfer. */ ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL); return ide_started; }
/* insert new object at head of queue (after queue->q_ptr) */ int qhead::putback(object* p) { oqueue* q = qh_queue; if (p->o_next) task_error(E_BACKOBJ, this); ll: if (q->q_count++ < q->q_max) { if (q->q_count == 1) { q->q_ptr = p; p->o_next = p; } else { object* oo = q->q_ptr; p->o_next = oo->o_next; oo->o_next = p; } return 1; } switch (qh_mode) { case WMODE: case EMODE: task_error(E_BACKFULL, this); goto ll; case ZMODE: return 0; } }
void sched.schedule() /* schedule either clock_task or front of run_chain */ { DB(("%x->sched::schedule( )\n",this)); register sched* p; register long tt; lll: DB((" run_chain: x%x\n", run_chain)); if (p = run_chain) { run_chain = (sched*) p->o_next; p->o_next = 0; } else { if (exit_fct) (*exit_fct)(); exit(0); } tt = p->s_time; DB((" thistask->s_time, p->s_time, clock == %ld, %ld, %ld\n", thistask->s_time, tt, clock)); if (tt != clock) { if (tt < clock) task_error(E_SCHTIME,this); clock = tt; if (clock_task) { if (clock_task->s_state != IDLE) task_error(E_CLOCKIDLE,this); /* clock_task preferred */ p->o_next = (object*) run_chain; run_chain = p; p = (sched*) clock_task; } } switch (p->o_type) { case TIMER: /* time is up; "delete" timer & schedule next task */ p->s_state = TERMINATED; p->alert(); goto lll; case TASK: if (p != this) { if (thistask && thistask->s_state != TERMINATED) thistask->save(); thistask = (task*) p; thistask->restore(); } break; default: DB(("object(%x) type == %x\n", p, p->o_type)); task_error(E_SCHOBJ,this); } } /* schedule */
void sched.insert(int d, object* who) /* schedule THIS to run in ``d'' time units inserted by who */ { register sched * p; register sched * pp; register long tt = s_time = clock + d; DB(("%x->sched::insert( %x, %x )\n",this,d,who)); switch (s_state) { case TERMINATED: task_error(E_RESTERM,this); break; case IDLE: break; case RUNNING: if (this != (class sched *)thistask) task_error(E_RESRUN,this); } if (d<0) task_error(E_NEGTIME,this); if (o_next) task_error(E_RESOBJ,this); s_state = RUNNING; if (o_type == TASK) ((task *) this)->t_alert = who; /* run_chain ordered by s_time */ if (p = run_chain) { if (tt < p->s_time) { o_next = (object*) run_chain; run_chain = this; } else { while (pp = (sched *) p->o_next) { if (tt < pp->s_time) { o_next = pp; p->o_next = this; return; } else p = pp; } p->o_next = this; } } else run_chain = this; }
// q->q_ptr points to last object. last->o_next points to first object. // first->o_next points to the next object. object* qhead::get() { register oqueue* q = qh_queue; ll: if (q->q_count) { register object* oo = q->q_ptr; register object* p = oo->o_next; oo->o_next = p->o_next; p->o_next = 0; if (q->q_count-- == q->q_max) { qtail* t = q->q_tail; if (t) t->alert(); }; return p; } switch (qh_mode) { case WMODE: this_task()->sleep(this); goto ll; case EMODE: task_error(E_GETEMPTY, this); goto ll; case ZMODE: return 0; } }
void start_threads(void) { if (running) task_error("threads already running"); if (pthread_barrier_init(&barrier, NULL, threads)) { task_error("Can't create a barrier"); } running = TRUE; for (unsigned int id = 0; id<threads; id++) task_args[id].id = id; pthread_attr_t attributes; pthread_attr_init(&attributes); pthread_attr_setstacksize(&attributes, 10*1024*1024); /* hardwired 10MB */ for (unsigned int id = 0; id<threads; id++) { if (pthread_create(&thread[id], &attributes, task[id], (void *)&task_args[id])) { task_error("Can't start thread %u", id); } } pthread_attr_destroy(&attributes); }
/* * Handler for command with PIO data-out phase (Write/Write Multiple). */ static ide_startstop_t task_out_intr (ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; struct request *rq = hwif->rq; u8 stat = hwif->tp_ops->read_status(hwif); if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat)) return task_error(drive, rq, __func__, stat); /* Deal with unexpected ATA data phase. */ if (((stat & ATA_DRQ) == 0) ^ !hwif->nleft) return task_error(drive, rq, __func__, stat); if (!hwif->nleft) { task_end_request(drive, rq, stat); return ide_stopped; } /* Still data left to transfer. */ ide_pio_datablock(drive, rq, 1); ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL); return ide_started; }
void stop_threads(void) { /* needs work: Technically, can't access running here without a mutex. */ if (running&&!halt) { pthread_mutex_lock(&halt_mutex); halt = TRUE; pthread_mutex_unlock(&halt_mutex); for (unsigned int id = 0; id<threads; id++) { if (pthread_join(thread[id], NULL)!=0) { task_error("Can't join thread %u", id); } } pthread_barrier_destroy(&barrier); halt = FALSE; } }
int sched.result() /* wait for termination and retrieve result */ { DB(("%x->sched::result( )\n", this)); DB((" o_type == x%x\n", o_type)); if (this == (sched*)thistask) task_error(E_RESULT,0); while (s_state != TERMINATED) { remember(thistask); DB((" o_type == x%x -- remember(x%x)\n", o_type,thistask)); thistask->sleep(); DB((" o_type == x%x -- x%x->sleep()\n", o_type,thistask)); forget(thistask); DB((" o_type == x%x -- forget(x%x)\n", o_type,thistask)); } return (int) s_time; }
int task_abandon (struct task_act *tk) { struct oper_act * on; DLOG(log_dsap, LLOG_TRACE, ("task_abandon")); for(on = tk->tk_operlist; on != NULLOPER; on = on->on_next_task) { on->on_state = ON_ABANDONED; on->on_task = NULLTASK; if (on->on_dsas) { di_desist (on->on_dsas); on -> on_dsas = NULL_DI_BLOCK; } } ds_error_free (&tk->tk_resp.di_error.de_err); tk->tk_resp.di_error.de_err.dse_type = DSE_ABANDONED; task_error(tk); return(OK); }
double current_time(void) { struct timeval time; if (gettimeofday(&time, NULL)!=0) task_error("gettimeofday failed"); /* needs work: Will it convert division into multiplication? */ return ((double)time.tv_sec)+((double)time.tv_usec)/1e6; }
void *task_malloc(size_t size) { void *p = malloc(size); if (p==NULL) task_error("Out of memory"); return p; }
int conn_extract (struct connection *conn) { /* * Extract all the operations made on this connection, and all * the tasks (and their derivative operations) made on the connection; * then remove the connection from the list of active connections. */ struct oper_act * on; struct oper_act * on_next; struct task_act * tk; struct task_act * tk_next; struct connection * cn; struct connection **cn_p; struct DSError * err; DLOG (log_dsap,LLOG_TRACE, ("conn_extract")); #ifdef QUIPU_CONSOLE /* SPT: Catch this close and indicate it on the open_calls */ closing_analyse(conn) ; #endif /* QUIPU_CONSOLE */ if(conn == NULLCONN) { LLOG(log_dsap, LLOG_EXCEPTIONS, ("Extracting NULLCONN!!!")); return; } cn_p = &(connlist); for(cn=connlist; cn!=NULLCONN; cn=cn->cn_next) { DLOG(log_dsap, LLOG_DEBUG, ("checking connlist")); if(cn == conn) break; cn_p = &(cn->cn_next); } if(cn==NULLCONN) { LLOG(log_dsap, LLOG_EXCEPTIONS, ("conn_extract - connection not in connlist")); return; } else { /* Cut connection loose from global list */ DLOG(log_dsap, LLOG_DEBUG, ("Extracting conn from connlist")); (*cn_p) = cn->cn_next; conns_used--; } for(on=conn->cn_operlist; on!=NULLOPER; on=on_next) { on_next = on->on_next_conn; oper_fail_wakeup (on); } for(tk=conn->cn_tasklist; tk!=NULLTASK; tk=tk_next) { tk_next = tk->tk_next; err = &(tk->tk_resp.di_error.de_err); if((err->dse_type != DSE_REFERRAL) && (err->dse_type != DSE_DSAREFERRAL)) { err->dse_type = DSE_SERVICEERROR; err->ERR_SERVICE.DSE_sv_problem = DSE_SV_UNAVAILABLE; } task_error(tk); task_extract(tk); } conn_free(conn); }
void setclock(long t) { if (clock) task_error(E_SETCLOCK,0); clock = t; }
int timeout_task (struct task_act *tk) { struct oper_act * on; struct DSError * err = &(tk->tk_resp.di_error.de_err); struct ds_search_task *tmp; DLOG(log_dsap, LLOG_TRACE, ("timeout_task")); for(on=tk->tk_operlist; on!=NULLOPER; on=on->on_next_task) { /* Time out operations started by task */ on->on_state = ON_ABANDONED; on->on_task = NULLTASK; if (on->on_dsas) { di_desist (on->on_dsas); on -> on_dsas = NULL_DI_BLOCK; } } if(tk->tk_dx.dx_arg.dca_dsarg.arg_type != OP_SEARCH) { ds_error_free (err); err->dse_type = DSE_SERVICEERROR; if (tk->tk_timed == TRUE) err->ERR_SERVICE.DSE_sv_problem = DSE_SV_TIMELIMITEXCEEDED; else /* tk->tk_timed == 2 */ err->ERR_SERVICE.DSE_sv_problem = DSE_SV_ADMINLIMITEXCEEDED; task_error(tk); task_extract(tk); } else { /* Do search collation */ if ((tk->tk_state == TK_ACTIVE) && (tk->local_st == NULL_ST)) { ds_error_free (err); /* nothing happened yet... */ err->dse_type = DSE_SERVICEERROR; if (tk->tk_timed == TRUE) err->ERR_SERVICE.DSE_sv_problem = DSE_SV_TIMELIMITEXCEEDED; else /* tk->tk_timed == 2 */ err->ERR_SERVICE.DSE_sv_problem = DSE_SV_ADMINLIMITEXCEEDED; task_error(tk); } else { /* send the results we have got... */ tk->tk_result = &(tk->tk_resp.di_result.dr_res); tk->tk_result->dcr_dsres.result_type = tk->tk_dx.dx_arg.dca_dsarg.arg_type; tk->tk_resp.di_type = DI_RESULT; if (tk->tk_timed == TRUE) tk->tk_resp.di_result.dr_res.dcr_dsres.res_sr.CSR_limitproblem = LSR_TIMELIMITEXCEEDED; else /* tk->tk_timed == 2 */ tk->tk_resp.di_result.dr_res.dcr_dsres.res_sr.CSR_limitproblem = LSR_ADMINSIZEEXCEEDED; /* Go through sub-tasks and add a POQ for each */ for(tmp=tk->referred_st; tmp!= NULL_ST; tmp=tmp->st_next) add_cref2poq (&tk->tk_result->dcr_dsres.res_sr,tmp->st_cr); task_result(tk); st_free_dis(&tk->referred_st,1); } task_extract(tk); } }