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;
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!
}
}
- 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);
}
-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