Beispiel #1
0
void _zombify( pcb_t *pcb ) {
	pcb_t *parent;
	status_t stat;
	pid_t pid;
	key_t key;
	info_t *info;

	// sanity check

	if( pcb == NULL ) {
		_kpanic( "_zombify", "null pcb", 0 );
	}

	// Locate the parent of this process

	parent = _pcb_find( pcb->ppid );

	if( parent == NULL ) {
		c_printf( "** zombify(): pid %d ppid %d\n",
			  pcb->pid, pcb->ppid );
		_kpanic( "_zombify", "no process parent", 0 );
	}

	//
	// Found the parent.  If it's waiting for this process,
	// wake it up, give it this process' status, and clean up.
	//

	if( parent->state == WAITING ) {

		// get the address of the info structure from the
		// parent, and pull out the desired PID

		info = (info_t *) ARG(parent->context,1);
		pid = info->pid;

		// if the parent was waiting for any of its children
		// or was waiting for us specifically, give it our
		// information and terminate this process.
		//
		// if the parent was waiting for another child,
		// turn this process into a zombie.

		if( pid == 0 || pid == _current->pid ) {

			// pull the parent off the waiting queue

			key.u = parent->pid;
			stat = _q_remove_by_key(&_waiting,(void **)&parent,key);
			if( stat != E_SUCCESS ) {
				_kpanic( "_zombify", "wait remove status %s",
					 stat );
			}

			// return our PID and our termination status
			// to the parent

			info->pid = _current->pid;
			info->status = ARG(_current->context,1);

			// clean up this process

			stat = _stack_free( pcb->stack );
			if( stat != E_SUCCESS ) {
				_kpanic( "_zombify", "stack free status %s",
					 stat );
			}

			stat = _pcb_free( pcb );
			if( stat != E_SUCCESS ) {
				_kpanic( "_zombify", "pcb free status %s",
					 stat );
			}

			// schedule the parent; give it a quick dispatch

			_schedule( parent, PRIO_MAXIMUM );

			return;
		}

	}

	//
	// Our parent either wasn't waiting, or was waiting for someone
	// else.  Put this process on the zombie queue until our parent
	// wants us.
	//

	key.u = _current->pid;
	_current->state = ZOMBIE;

	stat = _q_insert( &_zombie, (void *)_current, key );
	if( stat != E_SUCCESS ) {
		_kpanic( "_zombify", "zombie insert status %s", stat );
	}

}
Beispiel #2
0
void _init( void ) {
	pcb_t *pcb;

	/*
	** BOILERPLATE CODE - taken from basic framework
	**
	** Initialize interrupt stuff.
	*/

	__init_interrupts();	// IDT and PIC initialization
	// Ignore the 0x2A interrupt which happens when removing or inserting a
	// flash drive.
	__install_isr( 0x2A,  _ignore_isr );

	/*
	** Console I/O system.
	*/

	c_io_init();
	c_clearscreen();
#ifdef ISR_DEBUGGING_CODE
	c_setscroll( 0, 7, 99, 99 );
	c_puts_at( 0, 6, "================================================================================" );
#endif

	/*
	** 20123-SPECIFIC CODE STARTS HERE
	*/

	/*
	** Initialize various OS modules
	**
	** Note:  the clock, SIO, and syscall modules also install
	** their ISRs.
	*/

	c_puts( "Module init: " );

	_q_init();		// must be first
	_pcb_init();
	_stack_init();
	_sio_init();
	_sys_init();
	_sched_init();
	_clock_init();
	_pci_init();
	_disk_init();
	_net_init();

	c_puts( "\n" );
	c_puts("Launching the shell. Please be patient\n");
	__delay(1000);
	c_clearscreen();

	/*
	** Create the initial system ESP
	**
	** This will be the address of the next-to-last
	** longword in the system stack.
	*/

	_system_esp = ((uint32_t *) ( (&_system_stack) + 1)) - 2;

	/*
	** Create the initial process
	**
	** Code mostly stolen from _sys_fork(); if that routine
	** changes, SO MUST THIS!!!
	*/

	// allocate a PCB and stack

	pcb = _create_process( NULL );
	if( pcb == NULL ) {
		_kpanic( "_init", "init() creation failed", FAILURE );
	}

	// initialize the stack with the standard context

	pcb->context = _create_stack( pcb->stack );
	if( pcb->context == NULL ) {
		_kpanic( "_init", "init() stack setup failed", FAILURE );
	}

	// define the entry point for init()

	pcb->context->eip = (uint32_t) init;

	// set up various PCB fields

	pcb->pid = pcb->ppid = PID_INIT;	// next PID is initially 1
	pcb->prio = PRIO_HIGH;
	pcb->children = 1000;

	// remember this PCB for use in reparenting orphan processes

	_init_pcb = pcb;

	// make it the first process

	_schedule( pcb );
	_dispatch();

	/*
	** Turn on the SIO receiver (the transmitter will be turned
	** on/off as characters are being sent)
	*/

	_sio_enable( SIO_RX );

	/*
	** END OF 20123-SPECIFIC CODE
	**
	** Finally, report that we're all done.
	*/

	c_puts( "System initialization complete.\n" );

}
Beispiel #3
0
void _zombify( pcb_t *pcb ) {
	estatus_t *esptr;
	pid_t *pidptr;
	pid_t ppid;
	pcb_t *parent, *p2;
	int i;
	key_t key;
	status_t stat;
	
	// mark the process as no longer runnable

	pcb->state = ZOMBIE;

	// find the parent

	ppid = pcb->ppid;
	for( i = 0; i < N_PCBS; ++i ) {
		if( _pcbs[i].pid == ppid && _pcbs[i].state != FREE ) {
			parent = &_pcbs[i];
			break;
		}
	}
	
	/*
	** If we didn't find a parent, or if the parent was
	** already unrunnable (zombied, killed), reparent this
	** process to the init process
	*/

	if( i >= N_PCBS || _pcbs[i].state >= FIRST_DEAD_STATE ) {
		ppid = pcb->ppid = PID_INIT;
		parent = _init_pcb;
	}

	/*
	** At this point, parent points to the parent's PCB, and ppid
	** contains the parent's PID.
	**
	** If the parent is on the wait() queue, we'll awaken it and give
	** it this child's information.
	**
	** Otherwise, we need to put this child on the zombie queue.
	*/

	if( parent->state == WAITING ) {

		// look for the parent on the wait queue

		key.u = ppid;
		stat = _q_remove_specific( &_waiting, (void **) &p2, key );
		if( stat != SUCCESS ) {
			_kpanic( "_zombify", "parent wait remove status %s",
				 stat );
		}

		// verify that we found the same process

		if( p2 != parent ) {
			_pcb_dump( "*** p2:     ", p2 );
			_pcb_dump( "*** parent: ", parent );
			_kpanic( "_zombify", "parent wait deque wrong",
				 FAILURE );
		}

		// OK, we have the right one.

		// Start by decrementing its "remaining children"
		// counter if it isn't the init process

		if( ppid != PID_INIT ) {
			parent->children -= 1;
		}
		
		// return the child's information to it.

		RET(parent) = U_SUCCESS;

		pidptr = (pid_t *) ARG(parent)[1];
		*pidptr = pcb->pid;

		esptr = (estatus_t *) ARG(parent)[2];
		*esptr = ARG(pcb)[1];
		
		// schedule the parent (who returns from wait())

		_schedule( parent );
		
		// clean up the child process
		_pcb_cleanup( pcb );

	} else {

		// place this child on the zombie queue, ordered by PID

		key.u = pcb->pid;
		pcb->status = ARG(pcb)[1];

		stat = _q_insert( &_zombie, (void *)pcb, key );
		if( stat != SUCCESS ) {
			_kpanic( "_zombify", "zombie insert status %s",
				 stat );
		}

	}
	
}
Beispiel #4
0
void _init( void ) {
    Pcb *pcb;

    //
    // BOILERPLATE CODE - taken from basic framework
    //
    // Initialize interrupt stuff.
    //

    __init_interrupts();	// IDT and PIC initialization

    //
    // I/O system.
    //

    c_io_init();
    c_clearscreen();
    c_setscroll( 0, 7, 99, 99 );
    c_puts_at( 0, 6, "================================================================================" );

    c_puts( "Init: " );

    //
    // 20073-SPECIFIC CODE STARTS HERE
    //

    //
    // Initialize various OS modules
    //

    _init_queues();		// must be first
    _init_memory();
    _init_processes();
    _init_stacks();
    _init_sio();
    _init_clock();
    _init_syscalls();

    c_puts( "\n" );

    //
    // Create the initial process
    //
    // Code mostly stolen from _sys_fork() and _sys_exec();
    // if either of those routines change, SO MUST THIS!!!
    //

    //
    // First, get a PCB and a stack
    //

    pcb = _get_pcb();
    if( pcb == 0 ) {
        _kpanic( "_init - can't allocate first pcb" );
    }

    pcb->stack = _get_stack();
    if( pcb->stack == 0 ) {
        _kpanic( "_init - can't allocate first stack" );
    }

    //
    // Next, set up various PCB fields
    //

    pcb->pid  = g_next_pid++;
    pcb->prio = PRI_NORMAL;

    //
    // Set up the initial process context.
    //
    // See _sys_exec() for an explanation of how this works.
    //

    pcb->context = _setup_stack( pcb->stack, (unsigned int) first_main );

    // Initialize memory segment. Equals that of the kernel's in the GDT.
    pcb->seg.mem.offset = 0x0;
    pcb->seg.mem.length = 0xFFFFFFFF;

    // Initialize LDT entries for this PCB
    // This is a "kernel" process, so we will just copy over the
    // descriptors from the GDT and stick them into this process' LDT.
    __copy_gdt_entry( &(pcb->seg.ldt.cseg), (GDT_INDEX(GDT_CODE)) );
    __copy_gdt_entry( &(pcb->seg.ldt.dseg), (GDT_INDEX(GDT_DATA)) );

    // Allocate a slot in the GDT for the LDT descriptor,
    // and initialize this PCB's LDT register variable.
    pcb->seg.ldtr = SEL_SETINDEX(_gdt_alloc()) | SEL_GDT | SEL_RPL(0);

    // Initialize the LDT descriptor located in the GDT
    __gdt_set_entry( SEL_GETINDEX(pcb->seg.ldtr),
                     (u32_t)&(pcb->seg.ldt), sizeof(ldt_t),
                     ACC_PRES | ACC_DPL(0) | ACC_SYS | SYS_LDT );

    //
    // Give it to the scheduler.
    //

    _schedule( pcb );

    //
    // Do it all again for the idle process.
    //

    pcb = _get_pcb();
    if( pcb == 0 ) {
        _kpanic( "_init - can't allocate idle pcb" );
    }

    pcb->stack = _get_stack();
    if( pcb->stack == 0 ) {
        _kpanic( "_init - can't allocate idle stack" );
    }

    pcb->pid  = g_next_pid++;
    pcb->prio = PRI_MINIMUM;

    pcb->context = _setup_stack( pcb->stack, (unsigned int) idle_main );

    pcb->seg.mem.offset = 0x0;
    pcb->seg.mem.length = 0xFFFFFFFF;

    __copy_gdt_entry( &(pcb->seg.ldt.cseg), (GDT_INDEX(GDT_CODE)) );
    __copy_gdt_entry( &(pcb->seg.ldt.dseg), (GDT_INDEX(GDT_DATA)) );

    pcb->seg.ldtr = SEL_SETINDEX(_gdt_alloc()) | SEL_GDT | SEL_RPL(0);

    __gdt_set_entry( SEL_GETINDEX(pcb->seg.ldtr),
                     (u32_t)&(pcb->seg.ldt), sizeof(ldt_t),
                     ACC_PRES | ACC_DPL(0) | ACC_SYS | SYS_LDT );

    _schedule( pcb );

    //
    // Dispatch the initial current process
    //

    _dispatch();

    //
    // END OF 20073-SPECIFIC CODE
    //
    // Finally, report that we're all done.
    //

    c_puts( "System initialization complete.\n" );

}
Beispiel #5
0
static void _clock_isr( int vector, int code ) {
	(void)(vector);
	(void)(code);

	pcb_t *pcb;

	// spin the pinwheel

	++_pinwheel;
	if( _pinwheel == (CLOCK_FREQUENCY / 10) ) {
		_pinwheel = 0;
		++_pindex;
		c_putchar_at( 79, 0, "|/-\\"[ _pindex & 3 ] );
	}

	// increment the system time

	++_system_time;

	/*
	** wake up any sleeper whose time has come
	**
	** we give awakened processes preference over the
	** current process (when it is scheduled again)
	*/

	while( !_queue_empty(_sleeping) &&
	       (uint32_t) _queue_kpeek(_sleeping) <= _system_time ) {

		// time to wake up!  remove it from the queue
		pcb = (pcb_t *) _queue_remove( _sleeping );
		if( pcb == NULL ) {
#ifdef DEBUG
			_kpanic( "_clock_isr", "NULL from sleep queue remove" );
#else
			c_puts( "*** _clock_isr: NULL from sleep queue\n" );
			break;
#endif
		}

		// and schedule it for dispatch
		_schedule( pcb );
	}

	// check the current process to see if it needs to be scheduled

	// sanity check!

	_current->quantum -= 1;
	if( _current->quantum < 1 ) {
		_schedule( _current );
		_dispatch();
	}

#ifdef DUMP_QUEUES
	// Approximately every 10 seconds, dump the queues, and
	// print the contents of the SIO buffers.

	if( (_system_time % SECONDS_TO_TICKS(10)) == 0 ) {
		c_printf( "Queue contents @%08x\n", _system_time );
		_queue_dump( "ready[0]", _ready[0] );
		_queue_dump( "ready[1]", _ready[1] );
		_queue_dump( "ready[2]", _ready[2] );
		_queue_dump( "ready[3]", _ready[3] );
		_queue_dump( "sleep", _sleeping );
		_sio_dump();
	}
#endif

	// tell the PIC we're done

	__outb( PIC_MASTER_CMD_PORT, PIC_EOI );

}
Beispiel #6
0
static void _isr_sio( int vector, int code ) {
	Pcb *pcb;
	int eir;
	int ch;

	//
	// Must process all pending events; loop until the EIR
	// says there's nothing else to do.
	//

	for( ; ; ) {
		// get the "pending event" indicator
		eir = __inb( UA4_EIR ) & UA4_EIR_INT_PRI_MASK;

		// process this event
		switch( eir ) {

		   case UA4_EIR_TX_INT_PENDING:
			// if there is another character, send it
			if( g_sending && g_outcount > 0 ) {
				__outb( UA4_TXD, *g_outnext );
				++g_outnext;
				--g_outcount;
			} else {
				// no more data - reset the output vars
				g_outcount = 0;
				g_outlast = g_outnext = g_outbuffer;
				g_sending = 0;
			}
			break;

		   case UA4_EIR_RX_INT_PENDING:
			// get the character
			ch = __inb( UA4_RXD );
			if( ch == '\r' ) {	// map CR to LF
				ch = '\n';
			}

			//
			// If there is a waiting process, this must be 
			// the first input character; give it to that
			// process and awaken the process.
			//

			if( g_sio_blocked.front != 0 ) {

				if( _deque(&g_sio_blocked,(void **)&pcb) != ERR_NONE ) {
					_kpanic( "sio isr - serial wakeup failed" );
				}
				pcb->context->eax = ch & 0xff;
				_schedule( pcb );

			} else {

				//
				// Nobody waiting - add to the input buffer
				// if there is room, otherwise just ignore it.
				//

				if( g_incount < BUF_SIZE ) {
					*g_inlast++ = ch;
					++g_incount;
				}
			
			}

			break;

		   case UA4_EIR_NO_INT:
			// nothing to do - tell the PIC we're done
			__outb( PIC_MASTER_CMD_PORT, PIC_EOI );
			return;

		   default:
			_kpanic( "sio isr - unknown device status" );

		}
	
	}

}