up(sem_t &sem) {

  disable_interrupts();
  acquire_spinlock(mu);

  sem->val++;

  if (not_empty(queue)) {
    // threads are waiting - wake one up
    
    other_thread = dequeue(queue);
    other_thread->state = READY;
    add_to_ready_queue(other_thread);
  }

  release_spinlock(mu);
  enable_interrupts();
}
Example #2
0
/**
 * Used for interrupt handler. According to the action the process wants to take,
 * do the corresponding work and call dispatcher to schedule the processes.
 * @param device_id: The id of the device obtained from interrupt handler.
 */
void read_write_scheduler(INT32 device_id)
{
    PCB *pcb;
    INT16 disk_id;

    switch (device_id)
    {
        case 5:
            disk_id = 1;
            break;
        case 6:
            disk_id = 2;
            break;
        case 7:
            disk_id = 3;
            break;
        default:
            error_message("Illegal device id.");
            break;
    }

    pcb = remove_from_suspend_queue_by_disk_id(disk_id);

    if (pcb != NULL)
    {
        // If the process needs to write, then write data to specific sector.
        if (pcb->operation == WRITE_ONE)
        {
            INT32 status;
            
            write_to_memory(Z502DiskSetID, & pcb->disk);
            read_from_memory(Z502DiskStatus, &status);
            if (status == DEVICE_FREE)
            {
                write_to_memory(Z502DiskSetSector, & pcb->sector);
                write_to_memory(Z502DiskSetBuffer, (INT32 *) pcb->disk_data);
                status = 1; // Specify a write.
                write_to_memory(Z502DiskSetAction, &status);
                status = 0; // Must be set to 0.
                write_to_memory(Z502DiskStart, &status);
                pcb->operation = WRITE_TWO;
                enqueue_suspend_queue_reversly(pcb);
                pcb->suspend = TRUE;
                print_scheduling_info(ACTION_NAME_WRITE, pcb, NORMAL_INFO);
            }
            else
            {
                enqueue_suspend_queue_reversly(pcb);
                pcb->suspend = TRUE;
                print_scheduling_info(ACTION_NAME_WRITE, pcb, NORMAL_INFO);
            }
        }

            // If the process needs to read, then read data from specific sector.
        else if (pcb->operation == READ_ONE)
        {
            INT32 status;

            write_to_memory(Z502DiskSetID, & pcb->disk);
            read_from_memory(Z502DiskStatus, &status);
            if (status == DEVICE_FREE)
            {
                write_to_memory(Z502DiskSetSector, & pcb->sector);
                write_to_memory(Z502DiskSetBuffer, (INT32 *) pcb->disk_data);
                status = 0; // Specify a read.
                write_to_memory(Z502DiskSetAction, &status);
                status = 0; // Must be set to 0.
                write_to_memory(Z502DiskStart, &status);
                pcb->operation = READ_TWO;
                enqueue_suspend_queue_reversly(pcb);
                pcb->suspend = TRUE;
                print_scheduling_info(ACTION_NAME_READ, pcb, NORMAL_INFO);
            }
            else
            {
                // If in use, add it reversely.
                enqueue_suspend_queue_reversly(pcb);
                pcb->suspend = TRUE;
                print_scheduling_info(ACTION_NAME_READ, pcb, NORMAL_INFO);
            }
        }
        else
        {
            add_to_ready_queue(pcb);
            pcb->suspend = FALSE;
            print_scheduling_info(ACTION_NAME_READY, pcb, NORMAL_INFO);
        }
    }
}