void TimerISR() { outportb(0x20, 0x60); // dismiss timer interrupt // deal with sleep items sys_tick++; while(!EmptyQ(&sleep_q) && (pcbs[sleep_q.q[sleep_q.head]].wake_tick <= sys_tick)) { int tmpPID = DeQ(&sleep_q); pcbs[tmpPID].state=READY; EnQ(tmpPID, &ready_q); } if(cur_pid == 0) return; // if Idle process, no need to do this on it pcbs[cur_pid].tick_count++; if(pcbs[cur_pid].tick_count == TIME_SLICE) // running up time, preempt it? { pcbs[cur_pid].tick_count = 0; // reset (roll over) usage time pcbs[cur_pid].total_tick_count += TIME_SLICE; // sum to total pcbs[cur_pid].state = READY; // change its state EnQ(cur_pid, &ready_q); // move it to ready_q cur_pid = -1; // no longer running } }
void MsgSndISR() { int mid, pid; msg_t *src, *dest; mid = pcbs[cur_pid].tf_p->eax; src = (msg_t *)pcbs[cur_pid].tf_p->ebx; src->sender = cur_pid; // authenticate sender src->time_stamp = sys_tick; // authenticate time_stamp if(EmptyQ(&mboxes[mid].wait_q)) { MsgEnQ( src, &( mboxes[mid].msg_q ) ); } else { pid = DeQ(&mboxes[mid].wait_q); pcbs[pid].state = READY; EnQ(pid, &ready_q); dest = (msg_t *)pcbs[pid].tf_p->eax; // eax since MsgRcv changed *dest = *src; } }
void MsgSndISR() { int mid,pid,head; msg_t *source, *destination; mid = pcbs[cur_pid].tf_p ->eax; source = (msg_t*)pcbs[cur_pid].tf_p -> ebx; if(!EmptyQ(&mboxes[mid].wait_q)) { pid = DeQ(&mboxes[mid].wait_q); EnQ(pid,&ready_q); pcbs[pid].state = READY; destination = (msg_t *)pcbs[pid].tf_p -> ebx; MyMemCpy((char*)destination,(char*)source,sizeof(msg_t)); } else { EnQMsg(source, &mboxes[mid].msg_q); head = mboxes[mid].msg_q.head; destination = &mboxes[mid].msg_q.msgs[head]; } destination->sender = cur_pid; destination->send_tick = sys_tick; }
void SemPostISR(int sid){ if (!EmptyQ(&(sems[sid].wait_q))) { int free_pid = DeQ(&(sems[sid].wait_q)); pcbs[free_pid].state = READY; EnQ(free_pid, &ready_q); } else { sems[sid].sem_count += 1; } }
void SleepISR(int sleep_secs){ q_t tmp_q; InitQ(&tmp_q); pcbs[cur_pid].wake_tick = (sys_tick + sleep_secs * 100); while( !(EmptyQ(&sleep_q)) && (pcbs[sleep_q.q[sleep_q.head]].wake_tick <= pcbs[cur_pid].wake_tick) ){ int tmpPID= DeQ(&sleep_q); EnQ(tmpPID, &tmp_q); } EnQ(cur_pid, &tmp_q); while (!EmptyQ(&sleep_q)){ EnQ(DeQ(&sleep_q), &tmp_q); } while(!EmptyQ(&tmp_q)){ EnQ(DeQ(&tmp_q), &sleep_q); } pcbs[cur_pid].state = SLEEP; cur_pid = -1; }
void Scheduler() // this is kernel's process scheduler, simple round robin { if(cur_pid > 0) return; // when cur_pid is not 0 (IdleProc) or -1 (none) if(cur_pid == 0) pcbs[0].state = READY; // skip when cur_pid is -1 if(EmptyQ(&ready_q)) cur_pid = 0; // ready q empty, use IdleProc else cur_pid = DeQ(&ready_q); // or get 1st process from ready_q pcbs[cur_pid].state = RUN; // RUN state for newly selected process }
int SemInitISR(int sem_count){ int sid; if (!EmptyQ(&avail_sem_q)) { sid = DeQ(&avail_sem_q); sems[sid].sem_count = sem_count; InitQ(&(sems[sid].wait_q)); } else { sid = -1; } return sid; }
//void SemPostISR(int sid) { void SemPostISR() { int pid, sid = pcbs[cur_pid].tf_p->eax; if(!EmptyQ(&sems[sid].wait_q)) { pid = DeQ(&sems[sid].wait_q); EnQ(pid, &ready_q); pcbs[pid].state = READY; } else { sems[sid].sem_count++; } }
void SemPostISR( int sid ) // passing arg as device driver phase uses this { if( EmptyQ( &sems[ sid ].wait_q ) ) { sems[ sid ].sem_count++; } else { int pid = DeQ( &sems[ sid ].wait_q ); pcbs[ pid ].state = READY; EnQ( pid, &ready_q ); } }
datatype *DeQueueQ(struct sequeue *sq){ datatype *ret; if(EmptyQ(sq)){ printf("queue is empty\n"); return NULL; }else{ ret = (datatype *)malloc(sizeof(datatype)); *ret = sq->data[(sq->rear-sq->length+1)%MAXSIZE]; sq->rear--; sq->quelen--; return ret; } }
void Kernel(tf_t *tf_p) // kernel directly enters here when interrupt occurs { // Save "tf_p" to pcbs[cur_pid].tf_p for future resume of process runtime pcbs[cur_pid].tf_p = tf_p; // tf_p->intr_id tells what intr made CPU get here, pushed in entry.S switch(tf_p->intr_id) { case TIMER_INTR: TimerISR(); // this must include dismissal of timer interrupt break; case IRQ7_INTR: IRQ7ISR(); break; case SLEEP_INTR: SleepISR(tf_p->eax); break; case GETPID_INTR: tf_p->eax = cur_pid; break; case SPAWN_INTR: if (EmptyQ(&avail_q)) { cons_printf("No more available PIDs!\n"); tf_p->ebx = -1; } else { tf_p->ebx = DeQ(&avail_q); SpawnISR((int) tf_p->ebx, (func_ptr_t) tf_p->eax); } break; case SEMINIT_INTR: tf_p->ebx = SemInitISR(tf_p->eax); break; case SEMWAIT_INTR: SemWaitISR(tf_p->eax); break; case SEMPOST_INTR: SemPostISR(tf_p->eax); break; case MSGSND_INTR: MsgSndISR(); break; case MSGRCV_INTR: MsgRcvISR(); break; } Scheduler(); // select a process to run Loader(pcbs[cur_pid].tf_p); // run the process selected }
void SleepISR() { q_t tmp_q; InitQ( &tmp_q ); // empty temp q // calc the future wake_tick of cur_pid pcbs[cur_pid].wake_tick = sys_tick + 100 * pcbs[cur_pid].tf_p->eax; // WHILE sleep_q not empty AND the 1st one in it has a wake_tick <= // wake_tick of cur_pid: move that 1st one from sleep_q to tmp_q while(!EmptyQ(&sleep_q) && pcbs[ sleep_q.q[ sleep_q.head ] ].wake_tick <= pcbs[ cur_pid ].wake_tick ) { EnQ(DeQ(&sleep_q), &tmp_q); // append it to tmp_q } // insertion point is reached as either sleep_q is now empty or the // wake_tick of cur_pid is smaller than the 1st one in the sleep_q EnQ( cur_pid, &tmp_q ); // append cur_pid to tmp_q // append the rest of sleep_q to tmp_q while( ! EmptyQ( &sleep_q ) ) { EnQ( DeQ( &sleep_q ), &tmp_q ); } // update sleep_q with the now ordered tmp_q sleep_q = tmp_q; // assignment allowed for struct type pcbs[cur_pid].state = SLEEP; cur_pid = -1; // need to get a different proc to run now }
void SemPostISR(int sid) { int pid; if( EmptyQ( &(sems[sid].wait)) ) { sems[sid].count++; return; } pid = DeQ(&(sems[sid].wait)); pcbs[pid].state = READY; EnQ(pid, &ready_q); return; }
int DeQ(q_t *p) // return -1 if queue is empty { int id; if(EmptyQ(p)) { cons_printf("Queue is empty, can't dequeue!\n"); return -1; } id = p->q[p->head]; p->head++; if(p->head == Q_SIZE) p->head = 0; // wrap around p->count--; return id; }
int DeQ(q_t *p)// return -1 if q is empty { int pid; if(!EmptyQ(p))//if Queue is not empty { pid = p->q[p->head]; p->head = p->head + 1; if(p->head == Q_SIZE)//if head is at index 20 of queue then reset head to 0 p->head = 0; p->count = p->count - 1; return pid; } else return -1; //return -1 if q is empty }
void WakieWakie() // wake if (multiple) processes to wake { int pid; sys_tick++; // system time/ticks // repeat until false: // check if sleep_q is not empty and wake_tick of the 1st // process indicated in sleep_q == sys_tick to wake it up while(!EmptyQ(&sleep_q) && pcbs[sleep_q.q[sleep_q.head]].wake_tick==sys_tick) { pid = DeQ(&sleep_q); EnQ(pid, &ready_q); pcbs[pid].state = READY; } }
void MsgSndISR(int mid, msg_t *p) { int pid; p->sender = cur_pid; p->send_tick = sys_tick; if(EmptyQ(&(mboxes[mid].wait_q))) // If wait Queue of message is empty. MsgEnQ(p, &(mboxes[mid].msg_q)); // Queue the message. else { pid = DeQ(&(mboxes[mid].wait_q)); // Dequeue the waiting process pcbs[pid].state = READY; EnQ(pid, &ready_q); *((msg_t *) pcbs[pid].tf_p->eax) = *p; } }
void Kernel(tf_t *tf_p) // kernel begins its control upon/after interrupt { int pid, sid; pcbs[cur_pid].tf_p = tf_p; // save for cur_pid which may change switch(tf_p->intr_id) { case TIMER_INTR: TimerISR(); // service the simulated timer interrupt break; case GETPID_INTR: tf_p->eax = cur_pid; break; case SLEEP_INTR: SleepISR(); break; case SPAWN_INTR: if(EmptyQ(&avail_q)) { cons_printf("No more processes\n"); tf_p->eax = -1; } else { pid = DeQ(&avail_q); pcbs[pid].state = READY; SpawnISR(pid, (func_ptr_t) tf_p->eax); tf_p->eax = pid; } break; case SEMINIT_INTR: sid = SemInitISR(tf_p->eax); tf_p->eax = sid; break; case SEMWAIT_INTR: SemWaitISR(); break; case SEMPOST_INTR: SemPostISR(); break; } Scheduler(); // find same/new process to run Loader(pcbs[cur_pid].tf_p); // load it to run } // Kernel()
void Kernel(tf_t *tf_p) // kernel directly enters here when interrupt occurs { // Save "tf_p" to pcbs[cur_pid].tf_p for future resume of process runtime pcbs[cur_pid].tf_p = tf_p; // tf_p->intr_id tells what intr made CPU get here, pushed in entry.S switch(tf_p->intr_id) { case TIMER_INTR: TimerISR(); // this must include dismissal of timer interrupt break; case SLEEP_INTR: SleepISR(tf_p->eax); break; case GETPID_INTR: tf_p->eax = cur_pid; break; } // still handles other keyboard-generated simulated events if(cons_kbhit()) // check if a key was pressed (returns non zero) { char key = cons_getchar(); // get the pressed key switch(key) // see if it's one of the following for service { case 'n': if(EmptyQ(&avail_q)) cons_printf("No more available PIDs!\n"); else { SpawnISR(DeQ(&avail_q), SimpleProc); } break; case 'k': KillISR(); break; // non-functional in phase 2 case 's': ShowStatusISR(); break; case 'b': breakpoint(); break; // this stops when run in GDB mode case 'q': exit(0); } // switch(key) } // if(cons_kbhit()) Scheduler(); // select a process to run Loader(pcbs[cur_pid].tf_p); // run the process selected }
int DeQ(q_t *p) // return -1 if q is empty { int pid; if (EmptyQ(p)) { cons_printf("Queue is empty, can't dequeue!\n"); return -1; } pid = p->q[p->head]; p->head += 1; if (p->head >= Q_SIZE) { p->head = 0; } p->count -= 1; return pid; }