void free_all_ports(const int owner) {
     register int i;
 /* Loop over all ports in the table. */
 for(i=0; i<MAX_NUMBER_OF_PORTS; i++)
 {
  /* Return as soon as we find a match. */
  if ((owner == port_table[i].owner))
  {
        port_table[i].owner = -1;
        port_table[i].id = -1;


        // Mark all processes wating to send to this process with ERROR
        while(!thread_queue_is_empty(&port_table[i].sender_queue)) {
            int sender_thread;
            sender_thread = thread_queue_dequeue(&port_table[i].sender_queue);
            thread_queue_enqueue(&ready_queue, sender_thread);

            // Setting the RAX register of the thread enables calling processes
            // to detect that messages have not been transferred.
            thread_table[sender_thread].data.registers.integer_registers.rax = ERROR;
        }
  }
 }
}
extern void
timer_interrupt_handler(void)
{
 /* Increment system time. */
 system_time++;

 /* Check if there are any thread that we should make ready.
    First check if there are any threads at all in the timer
    queue. */
 if (-1 != timer_queue_head)
 {
  /* Then decrement the list_data in the head. */
  thread_table[timer_queue_head].data.list_data-=1;

  /* Then remove all elements including with a list_data equal to zero
     and insert them into the ready queue. These are the threads that
     should be woken up. */
  while((-1 != timer_queue_head) &&
        /* We remove all entries less than or equal to 0. Equality should be
           enough but checking with less than or equal may hide the symptoms
           of some bugs and make the system more stable. */
        (thread_table[timer_queue_head].data.list_data<=0))
  {
   register int tmp_thread_index=timer_queue_head;
   /* Remove the head element.*/
   timer_queue_head=thread_table[tmp_thread_index].data.next;

   /* Let the woken thread run if the CPU is not running any thread. */
   if (-1 == cpu_private_data.thread_index)
   {
    cpu_private_data.thread_index = tmp_thread_index;

    cpu_private_data.page_table_root = 
     process_table[thread_table[tmp_thread_index].data.owner].
      page_table_root;
   }
   else
   {
    /* Or insert it into the ready queue. */
    thread_queue_enqueue(&ready_queue, tmp_thread_index);
   }
  }
 }
#include "pscheduler.c"
}
/*! Keyboard interrupt handler. */
static inline void
keyboard_interrupt_handler(void)
{
 register unsigned char status_byte=inb(0x64);

 if ((status_byte&1)==1)
 {
  register unsigned char data=inb(0x60);

  /* Is a thread waiting for data? */
  if (thread_queue_is_empty(&keyboard_blocked_threads))
  {
   /* Store scan code in the buffer if there is space in the buffer. */
   register int buffer_size=keyboard_scancode_high_marker-
                            keyboard_scancode_low_marker;
   if (buffer_size<KEYBOARD_BUFFER_SIZE)
   {
    keyboard_scancode_buffer
     [(keyboard_scancode_high_marker++)&(KEYBOARD_BUFFER_SIZE-1)]=data;
   }
  }
  else
  {
   /* Let the first blocked thread get the scan code. */
   register int blocked_thread_index=
    thread_queue_dequeue(&keyboard_blocked_threads);
   thread_table[blocked_thread_index].data.registers.integer_registers.rax=
    data;

   /* Let the woken thread run if the CPU is not running any thread. */
   if (-1 == cpu_private_data.thread_index)
   {
    cpu_private_data.thread_index = blocked_thread_index;

    cpu_private_data.page_table_root = 
     process_table[thread_table[blocked_thread_index].data.owner].
      page_table_root;
   }
   else
   {
    thread_queue_enqueue(&ready_queue, blocked_thread_index);
   }
  }
 }
}
Exemple #4
0
int
system_call_implementation(void)
{
 register int schedule=0;
 /*!< System calls may set this variable to 1. The variable is used as
      input to the scheduler to indicate if scheduling is necessary. */
 switch(SYSCALL_ARGUMENTS.rax)
 {
  case SYSCALL_PRINTS:
  {
   kprints((char*) (SYSCALL_ARGUMENTS.rdi));
   SYSCALL_ARGUMENTS.rax = ALL_OK;

   break;
  }

  case SYSCALL_PRINTHEX:
  {
   kprinthex(SYSCALL_ARGUMENTS.rdi);
   SYSCALL_ARGUMENTS.rax = ALL_OK;
   break;
  }

  case SYSCALL_DEBUGGER:
  {
   /* Enable the bochs iodevice and force a return to the debugger. */
   outw(0x8a00, 0x8a00);
   outw(0x8a00, 0x8ae0);

   SYSCALL_ARGUMENTS.rax = ALL_OK;
   break;
  }

	case SYSCALL_VERSION: {
		SYSCALL_ARGUMENTS.rax = KERNEL_VERSION;
		break;
	}

	case SYSCALL_CREATEPROCESS: {

		int process_number, thread_number;
		long int executable_number = SYSCALL_ARGUMENTS.rdi;
		struct prepare_process_return_value prepare_process_ret_val;


		for (process_number = 0; process_number < MAX_NUMBER_OF_PROCESSES && process_table[process_number].threads > 0; process_number++) {
		}
		prepare_process_ret_val = prepare_process(
				executable_table[executable_number].elf_image,
				process_number,
				executable_table[executable_number].memory_footprint_size);

		if(0 == prepare_process_ret_val.first_instruction_address) {
			kprints("Error starting image\n");
		}

		process_table[process_number].parent = thread_table[cpu_private_data.thread_index].data.owner;

		thread_number = allocate_thread();

		thread_table[thread_number].data.owner = process_number;
		thread_table[thread_number].data.registers.integer_registers.rflags = 0x200;
		thread_table[thread_number].data.registers.integer_registers.rip = prepare_process_ret_val.first_instruction_address;

		process_table[process_number].threads += 1;

		SYSCALL_ARGUMENTS.rax = ALL_OK;

		thread_queue_enqueue(&ready_queue,thread_number);
		/*cpu_private_data.thread_index = thread_number;*/


		break;
	}
	case SYSCALL_TERMINATE:
	{
		int i;
		int owner_process = thread_table[cpu_private_data.thread_index].data.owner;
		int parent_process = process_table[owner_process].parent;

		thread_table[cpu_private_data.thread_index].data.owner = -1; /* Terminate Thread */

		process_table[owner_process].threads -= 1; /* Decrement Thread count */

		if(process_table[owner_process].threads < 1) {
			cleanup_process(owner_process);
		}

		for(i=0; i < MAX_NUMBER_OF_THREADS && thread_table[i].data.owner != parent_process; i++) {
		}

		/*cpu_private_data.thread_index = i;*/
		/*thread_queue_dequeue(&ready_queue);*/
		schedule = 1;

		break;

	}


  /* Do not touch any lines above or including this line. */

  /* Add the implementation of more system calls here. */


  /* Do not touch any lines below or including this line. */
  default:
  {
   /* No system call defined. */
   SYSCALL_ARGUMENTS.rax = ERROR_ILLEGAL_SYSCALL;
  }
 }

 return schedule;
}
extern void
system_call_handler(void)
{
 register int schedule=0;
 /*!< System calls may set this variable to 1. The variable is used as
      input to the scheduler to indicate that scheduling is not necessary. */

 /* Reset the interrupt flag indicating that the context of the caller was
    saved by the system call routine. */
 thread_table[cpu_private_data.thread_index].data.registers.from_interrupt=0;

 switch(SYSCALL_ARGUMENTS.rax)
 {
  case SYSCALL_PAUSE:
  {
   register int  tmp_thread_index;
   unsigned long timer_ticks=SYSCALL_ARGUMENTS.rdi;

   /* Set the return value before doing anything else. We will switch to a new
      thread very soon! */
   SYSCALL_ARGUMENTS.rax=ALL_OK;

   if (0 == timer_ticks)
   {
    /* We should not wait if we are asked to wait for less then one tick. */
    break;
   }

   /* Get the current thread. */
   tmp_thread_index=cpu_private_data.thread_index;

   /* Force a re-schedule. */
   schedule=1;

   /* And insert the thread into the timer queue. */

   /* The timer queue is a linked list of threads. The head (first entry)
      (thread) in the list has a list_data field that holds the number of
      ticks to wait before the thread is made ready. The next entries (threads)
      has a list_data field that holds the number of ticks to wait after the
      previous thread is made ready. This is called to use a delta-time and
      makes the code to test if threads should be made ready very quick. It
      also, unfortunately, makes the code that insert code into the queue
      rather complex. */

   /* If the queue is empty put the thread as only entry. */
   if (-1 == timer_queue_head)
   {
    thread_table[tmp_thread_index].data.next=-1;
    thread_table[tmp_thread_index].data.list_data=timer_ticks;
    timer_queue_head=tmp_thread_index;
   }
   else
   {
    /* Check if the thread should be made ready before the head of the
       previous timer queue. */
    register int curr_timer_queue_entry=timer_queue_head;

    if (thread_table[curr_timer_queue_entry].data.list_data>timer_ticks)
    {
     /* If so set it up as the head in the new timer queue. */

     thread_table[curr_timer_queue_entry].data.list_data-=timer_ticks;
     thread_table[tmp_thread_index].data.next=curr_timer_queue_entry;
     thread_table[tmp_thread_index].data.list_data=timer_ticks;
     timer_queue_head=tmp_thread_index;
    }
    else
    {
     register int prev_timer_queue_entry = curr_timer_queue_entry;

     /* Search until the end of the queue or until we found the right spot. */
     while((-1 != thread_table[curr_timer_queue_entry].data.next) &&
           (timer_ticks>=thread_table[curr_timer_queue_entry].data.list_data))
     {
      timer_ticks-=thread_table[curr_timer_queue_entry].data.list_data;
      prev_timer_queue_entry=curr_timer_queue_entry;
      curr_timer_queue_entry=thread_table[curr_timer_queue_entry].data.next;
     }


     if (timer_ticks>=thread_table[curr_timer_queue_entry].data.list_data)
     {
      /* Insert the thread into the queue after the existing entry. */
      thread_table[tmp_thread_index].data.next=
       thread_table[curr_timer_queue_entry].data.next;
      thread_table[curr_timer_queue_entry].data.next=tmp_thread_index;
      thread_table[tmp_thread_index].data.list_data=timer_ticks-
       thread_table[curr_timer_queue_entry].data.list_data;
     }
     else
     {
      /* Insert the thread into the queue before the existing entry. */
      thread_table[tmp_thread_index].data.next=
       curr_timer_queue_entry;
      thread_table[prev_timer_queue_entry].data.next=tmp_thread_index;
      thread_table[tmp_thread_index].data.list_data=timer_ticks;
      thread_table[curr_timer_queue_entry].data.list_data-=timer_ticks;
     }
    }
   }
   break;
  }

  case SYSCALL_TIME:
  {
   /* Returns the current system time to the program. */
   SYSCALL_ARGUMENTS.rax=system_time;
   break;
  }

  case SYSCALL_FREE:
  {
   SYSCALL_ARGUMENTS.rax=kfree(SYSCALL_ARGUMENTS.rdi);
   break;
  }

  case SYSCALL_ALLOCATE:
  {
   /* Check the flags. */
   if (0!=SYSCALL_ARGUMENTS.rsi & ~(ALLOCATE_FLAG_READONLY|ALLOCATE_FLAG_EX))
   {
    /* Return if the flags were not properly set. */
    SYSCALL_ARGUMENTS.rax = ERROR;
    break;
   }


   SYSCALL_ARGUMENTS.rax=kalloc(
           SYSCALL_ARGUMENTS.rdi,
           thread_table[cpu_private_data.thread_index].data.owner,
           SYSCALL_ARGUMENTS.rsi & (ALLOCATE_FLAG_READONLY|ALLOCATE_FLAG_EX));
   break;
  }

  case SYSCALL_ALLOCATEPORT:
  {
   int port=allocate_port(SYSCALL_ARGUMENTS.rdi,
                          thread_table[cpu_private_data.thread_index].
                           data.owner);

   /* Return an error if a port cannot be allocated. */
   if (port<0)
   {
    SYSCALL_ARGUMENTS.rax=ERROR;
    break;
   }

   SYSCALL_ARGUMENTS.rax=port;
   break;
  }

  case SYSCALL_FINDPORT:
  {
   int port;
   unsigned long process=SYSCALL_ARGUMENTS.rsi;

   /* Return an error if the process argument is wrong. */
   if (process >= MAX_NUMBER_OF_PROCESSES)
   {
    SYSCALL_ARGUMENTS.rax=ERROR;
    break;
   }

   port=find_port(SYSCALL_ARGUMENTS.rdi,
                  process);

   if (port<0)
   {
    SYSCALL_ARGUMENTS.rax=ERROR;
    break;
   }

   SYSCALL_ARGUMENTS.rax=port;
   break;
  }

  case SYSCALL_GETPID:
  {
   SYSCALL_ARGUMENTS.rax =
    thread_table[cpu_private_data.thread_index].data.owner;
  break;
  }

  case SYSCALL_GETSCANCODE:
  {
   /* Check if there is data in the scan code buffer. */
   if (keyboard_scancode_high_marker!=keyboard_scancode_low_marker)
   {
    /* There is data in the buffer. Get it! */
    SYSCALL_ARGUMENTS.rax=keyboard_scancode_buffer
     [(keyboard_scancode_low_marker++)&(KEYBOARD_BUFFER_SIZE-1)];
   }
   else
   {
    /* No data in the buffer. We will block waiting for data. */
    register int current_thread_index;

    /* Set the default return value to be an error. */
    SYSCALL_ARGUMENTS.rax=ERROR;
    /* Take the current thread out of the ready queue. */
    current_thread_index=cpu_private_data.thread_index;
    /* Tell the scheduler that it will have to reschedule. */
    schedule=1;
    thread_queue_enqueue(&keyboard_blocked_threads, current_thread_index);
   }
   break;
  }

#include "syscall.c"
  default:
  {
   /* No system call defined. */
   SYSCALL_ARGUMENTS.rax=ERROR_ILLEGAL_SYSCALL;
  }
 }
#include "scheduler.c"
}