Page 1 of 1

Resource Control Questions...

Posted: Tue Jan 15, 2008 1:27 pm
by astrocrep
Resource Control...

Basically for every requestable resource (not timer) there will be a resource structure to control it.

Here is what I have envisioned:

(Psuedo Code...)

Code: Select all

struct {
  long pID;
  waiting_queue *next;
} waiting_queue;

struct {
  char name[128];
  long active_pID;
  long handle;
  waiting_queue *line;
  (void *resource_handler)(int param_count, param_array[8]);
  resource *next;
} resource;

This is very generalized, basically a resource will have other fields as well, but for the sake of easy reading, just a name, and active_pid, and a queue of threads waiting to run (FIFO). There is also a function pointer, but we'll get to that later.

Now lets pretend we have a resource for "FLOPPY0", and I wish to access that resource. What will happen is the requesting thread will call the kernel to aquire resource, with a fail timeout. Something like this:

Code: Select all

u32int resource_request(char *resource_name, fail_time)
{
 resource_t *res;
 u32int my_pid;
 u32int handle;

 res = get_resource_entry(char *resource_name);   	//Finds and returns the resource_struct
 my_pid = get_pid();			      	//This Gets my PID

 if (res == 0)
	return -1; //We Failed to find the resource 

 int ticket = add_resource_request(res);	//This adds us to the waiting queue.

 int fail_time = get_ticks() + timespan_to_ticks(fail_time);

 for (;;)
 {

  //If the resource is now open!
  if (get_resource_serving(res) == my_pid)	//This sees if the active_pid == mypid
   return get_resource_handle(res);  		//This returns a unique handle to the resource

  if fail_time <= get_ticks()
  {
   destroy_resource_request();			//We remove ourselves from the waiting queue.
   return -1; //We failed to get the resource
  }
  switch_task();				//Nothing to do, reschedule!
 }
}
So a couple of things, get_resource_entry, will look through the linked list of resource entries and return a pointer to the struct. This is ok, because this function is inside the kernel code, whoever calls request_resource will never see the struct.
- add_resource_request, will add a new entry to the waiting line and return how many places back we are.
- get_resource_serving will simply return the active_pid of a resource
- get_resource_handle creates a new handle for this thread to access the resource, this will help with concurrency.
- destroy_resource_request, simply will remove our spot in line.

- add_resource_request and destroy_resource_request will have a secure mutex lock around them to prevent multiple threads injecting themselves into the kernel data structure.

Once we have aquired a resource, I envision something like this:

Code: Select all

void ReadSectors(...)
{
  u32int floppy_handle;
  char *buffer;

  buffer = kmalloc(4096);

  floppy_handle = resource_request("FLOPPY0",300);

  if (floppy_handle < 1)
   {
     //Failed to get the floppy resource in 3 seconds...
     return;
   }

  resource_call1(floppy_handle, FLOPPY_CMD_SEEK_HEAD);	//Return to the head of the disk
  resource_call4(floppy_handle, FLOPPY_CMD_READ,12,7,&buffer);  //12 = start sector, 7 = length lba... fill up buffer.
  
  resource_release("FLOPPY0", floppy_handle);
}
A couple of points of interest:
-resource_callX will call the virtual function attached to the resource block and pass the params. This assignment is done at resource creation, and all resources must implement this single interface.
-resource_release takes both the driver name and handle as a sanity check, also in this code block, the next thread waiting for the resource is taken off the line and made active.
-This read sectors call would actual reside inside of the floppy driver code, and would be called by an outside process.

How have other people done this? Simplicity over efficiency, for the time being, is my goal. I think this would work well.

Comments and Suggestions appricaited!

Thanks,
Rich

Posted: Wed Jan 16, 2008 3:10 am
by JamesM
I suggest having some sort of timeout on the resource holder, as at the moment your system relies totally on programs "playing nice".

For example, my Evil Process (tm) consists of:

Code: Select all

int main(char argc, char **argv)
{
  resource_t *resources = malloc(sizeof(resource_t)*2048);
  int nresources =enumerate_every_resource_in_the_system(resources);
  for(int i = 0; i < nresources; i++)
  {
    request_resource(resources[i], 0xFFFFFFFF); // max timeout.
  }
  for(;;);
}
Daa Daaaaaa!! System Killer extraordinaire!