186 lines
5.1 KiB
ObjectPascal
186 lines
5.1 KiB
ObjectPascal
// Copyright 2021 Aaron Hance
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
{
|
|
Driver->Storage->IORequest - I/O request allocation and lifecycle helpers.
|
|
|
|
Provides fixed-pool allocation/free for TIORequest records used by the
|
|
submit_io / complete_io path in driver.storage.mgr.pas.
|
|
|
|
@author(Aaron Hance <[email protected]>)
|
|
}
|
|
unit driver.storage.iorequest;
|
|
|
|
interface
|
|
|
|
uses
|
|
memory.heap,
|
|
driver.storage.types;
|
|
|
|
{ Allocate a new TIORequest from the fixed request pool and initialise its core fields.
|
|
Caller, State, Error and ByteCount are zeroed (caller fills as needed). }
|
|
function ioreq_alloc(reqType : TIORequestType;
|
|
device : PStorage_Device;
|
|
lba : uint32;
|
|
sectors : uint32;
|
|
buf : pointer) : PIORequest;
|
|
|
|
{ Return a pooled TIORequest to the free list. Safe to call with nil. }
|
|
procedure ioreq_free(req : PIORequest);
|
|
|
|
{ Copy an existing TIORequest into a new pooled allocation (deep copy of the
|
|
record, NOT the buffer it points to). Used by submit_io before enqueueing
|
|
the owned pointer. Manager-only merge/timing fields are initialised here. }
|
|
function ioreq_copy(src : PIORequest) : PIORequest;
|
|
|
|
implementation
|
|
|
|
const
|
|
IOREQ_POOL_CAPACITY = 512;
|
|
IOREQ_REQ_OFFSET = sizeof(pointer);
|
|
|
|
type
|
|
PIORequestPoolNode = ^TIORequestPoolNode;
|
|
TIORequestPoolNode = record
|
|
Next : PIORequestPoolNode;
|
|
Req : TIORequest;
|
|
end;
|
|
|
|
var
|
|
ioreqPoolReady : boolean;
|
|
ioreqPoolBuf : pointer;
|
|
ioreqFreeList : PIORequestPoolNode;
|
|
|
|
procedure ioreq_pool_init();
|
|
var
|
|
i : uint32;
|
|
base : uint32;
|
|
node : PIORequestPoolNode;
|
|
begin
|
|
if ioreqPoolReady then exit;
|
|
|
|
ioreqPoolBuf := kalloc(IOREQ_POOL_CAPACITY * sizeof(TIORequestPoolNode));
|
|
if ioreqPoolBuf = nil then exit;
|
|
|
|
ioreqFreeList := nil;
|
|
base := uint32(ioreqPoolBuf);
|
|
if IOREQ_POOL_CAPACITY > 0 then
|
|
for i := 0 to IOREQ_POOL_CAPACITY - 1 do begin
|
|
node := PIORequestPoolNode(base + (i * sizeof(TIORequestPoolNode)));
|
|
node^.Next := ioreqFreeList;
|
|
ioreqFreeList := node;
|
|
end;
|
|
|
|
ioreqPoolReady := true;
|
|
end;
|
|
|
|
function ioreq_take() : PIORequest;
|
|
var
|
|
node : PIORequestPoolNode;
|
|
begin
|
|
if not ioreqPoolReady then
|
|
ioreq_pool_init();
|
|
if not ioreqPoolReady then begin
|
|
ioreq_take := nil;
|
|
exit;
|
|
end;
|
|
|
|
asm pushf; cli end;
|
|
node := ioreqFreeList;
|
|
if node <> nil then
|
|
ioreqFreeList := node^.Next;
|
|
asm popf end;
|
|
|
|
if node = nil then
|
|
ioreq_take := nil
|
|
else
|
|
ioreq_take := @node^.Req;
|
|
end;
|
|
|
|
procedure ioreq_release(req : PIORequest);
|
|
var
|
|
node : PIORequestPoolNode;
|
|
begin
|
|
if req = nil then exit;
|
|
node := PIORequestPoolNode(uint32(req) - IOREQ_REQ_OFFSET);
|
|
asm pushf; cli end;
|
|
node^.Next := ioreqFreeList;
|
|
ioreqFreeList := node;
|
|
asm popf end;
|
|
end;
|
|
|
|
function ioreq_alloc(reqType : TIORequestType;
|
|
device : PStorage_Device;
|
|
lba : uint32;
|
|
sectors : uint32;
|
|
buf : pointer) : PIORequest;
|
|
var
|
|
req : PIORequest;
|
|
begin
|
|
req := ioreq_take();
|
|
if req = nil then begin
|
|
ioreq_alloc := nil;
|
|
exit;
|
|
end;
|
|
req^.MergeNext := nil;
|
|
req^.OriginalSectors := sectors;
|
|
req^.QueuedTick := 0; req^.DispatchTick := 0;
|
|
req^.RequestType := reqType;
|
|
req^.State := iosPending;
|
|
req^.Device := device;
|
|
req^.LBA := lba;
|
|
req^.SectorCount := sectors;
|
|
req^.Buffer := buf;
|
|
req^.ByteCount := 0;
|
|
req^.Error := eNone;
|
|
req^.Caller := nil;
|
|
req^.UserData := nil;
|
|
req^.Callback := nil;
|
|
req^.CallbackData := nil;
|
|
ioreq_alloc := req;
|
|
end;
|
|
|
|
procedure ioreq_free(req : PIORequest);
|
|
begin
|
|
ioreq_release(req);
|
|
end;
|
|
|
|
function ioreq_copy(src : PIORequest) : PIORequest;
|
|
var
|
|
dst : PIORequest;
|
|
begin
|
|
dst := ioreq_take();
|
|
if dst = nil then begin
|
|
ioreq_copy := nil;
|
|
exit;
|
|
end;
|
|
dst^.MergeNext := nil;
|
|
dst^.OriginalSectors := src^.SectorCount;
|
|
dst^.QueuedTick := 0; dst^.DispatchTick := 0;
|
|
dst^.RequestType := src^.RequestType;
|
|
dst^.State := src^.State;
|
|
dst^.Device := src^.Device;
|
|
dst^.LBA := src^.LBA;
|
|
dst^.SectorCount := src^.SectorCount;
|
|
dst^.Buffer := src^.Buffer;
|
|
dst^.ByteCount := src^.ByteCount;
|
|
dst^.Error := src^.Error;
|
|
dst^.Caller := src^.Caller;
|
|
dst^.UserData := src^.UserData;
|
|
dst^.Callback := src^.Callback;
|
|
dst^.CallbackData := src^.CallbackData;
|
|
ioreq_copy := dst;
|
|
end;
|
|
|
|
end.
|