mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-05 11:18:18 +02:00
248 lines
5.2 KiB
ObjectPascal
248 lines
5.2 KiB
ObjectPascal
{%skiptarget=$nothread }
|
|
{ %TIMEOUT=105 }
|
|
{$mode objfpc}{$h+}
|
|
|
|
{$ifdef CPUWASM32}
|
|
{ This test runs out of memory, when using the default WebAssembly shared
|
|
memory limit of 256 MiB, so we increase it to 512 MiB }
|
|
{$M 1048576,536870912,536870912}
|
|
{$endif}
|
|
|
|
uses
|
|
{$ifdef UNIX}
|
|
cthreads,
|
|
{$endif}
|
|
sysutils,
|
|
classes;
|
|
|
|
const
|
|
fifolength = 1024;
|
|
type
|
|
tpair = class;
|
|
|
|
tproducethread = class(tthread)
|
|
running: boolean;
|
|
pair: tpair;
|
|
constructor create(apair: tpair);
|
|
procedure execute; override;
|
|
end;
|
|
|
|
tconsumethread = class(tthread)
|
|
running: boolean;
|
|
pair: tpair;
|
|
constructor create(apair: tpair);
|
|
procedure execute; override;
|
|
end;
|
|
|
|
tpair = class(tobject)
|
|
public
|
|
readindex: integer;
|
|
writeindex: integer;
|
|
fifo: array[0..fifolength-1] of pointer;
|
|
shared: pointer;
|
|
freefifolock: trtlcriticalsection;
|
|
produce_thread: tproducethread;
|
|
consume_thread: tconsumethread;
|
|
|
|
constructor create;
|
|
destructor destroy; override;
|
|
|
|
procedure resume;
|
|
procedure waitfor;
|
|
end;
|
|
|
|
var
|
|
done: boolean;
|
|
|
|
constructor tproducethread.create(apair: tpair);
|
|
begin
|
|
pair := apair;
|
|
inherited create(false);
|
|
end;
|
|
|
|
constructor tconsumethread.create(apair: tpair);
|
|
begin
|
|
pair := apair;
|
|
inherited create(false);
|
|
end;
|
|
|
|
constructor tpair.create;
|
|
begin
|
|
filldword(fifo, sizeof(fifo) div sizeof(dword), 0);
|
|
readindex := 0;
|
|
writeindex := 0;
|
|
initcriticalsection(freefifolock);
|
|
produce_thread := tproducethread.create(self);
|
|
consume_thread := tconsumethread.create(self);
|
|
end;
|
|
|
|
destructor tpair.destroy;
|
|
begin
|
|
produce_thread.free;
|
|
consume_thread.free;
|
|
donecriticalsection(freefifolock);
|
|
end;
|
|
|
|
procedure tpair.resume;
|
|
begin
|
|
produce_thread.resume;
|
|
consume_thread.resume;
|
|
end;
|
|
|
|
procedure tpair.waitfor;
|
|
begin
|
|
produce_thread.waitfor;
|
|
consume_thread.waitfor;
|
|
end;
|
|
|
|
type
|
|
ttestarray = array[0..31] of pointer;
|
|
|
|
procedure exercise_heap(var p: ttestarray; var i, j: integer);
|
|
begin
|
|
if p[i] = nil then
|
|
p[i] := getmem(((j*11) mod 532)+8)
|
|
else begin
|
|
freemem(p[i]);
|
|
p[i] := nil;
|
|
end;
|
|
inc(i);
|
|
if i >= 32 then
|
|
dec(i, 32);
|
|
inc(j, 13);
|
|
if j >= 256 then
|
|
dec(j, 256);
|
|
end;
|
|
|
|
procedure freearray(p: ppointer; count: integer);
|
|
var
|
|
i: integer;
|
|
begin
|
|
for i := 0 to count-1 do
|
|
begin
|
|
freemem(p[i]);
|
|
p[i] := nil;
|
|
end;
|
|
end;
|
|
|
|
procedure producer(pair: tpair);
|
|
var
|
|
p: ttestarray;
|
|
i, j, k: longint;
|
|
begin
|
|
done := false;
|
|
filldword(p, sizeof(p) div sizeof(dword), 0);
|
|
i := 0;
|
|
j := 0;
|
|
k := 0;
|
|
while not done do
|
|
begin
|
|
if ((pair.writeindex+1) mod fifolength) <> pair.readindex then
|
|
begin
|
|
{ counterpart for the writebarrier in the consumer: ensure that we see
|
|
the write to pair.fifo[pair.readindex] now that we've seen the write
|
|
to pair.readindex }
|
|
readbarrier;
|
|
freemem(pair.fifo[pair.writeindex]);
|
|
pair.fifo[pair.writeindex] := getmem(((pair.writeindex*17) mod 520)+8);
|
|
writebarrier;
|
|
pair.writeindex := (pair.writeindex + 1) mod 1024;
|
|
end else begin
|
|
exercise_heap(p,i,j);
|
|
inc(k);
|
|
if k = 100 then
|
|
begin
|
|
k := 0;
|
|
ThreadSwitch;
|
|
end;
|
|
end;
|
|
end;
|
|
freearray(p, sizeof(p) div sizeof(pointer));
|
|
entercriticalsection(pair.freefifolock);
|
|
sleep(200);
|
|
freearray(pair.fifo, sizeof(pair.fifo) div sizeof(pointer));
|
|
freemem(pair.shared);
|
|
leavecriticalsection(pair.freefifolock);
|
|
end;
|
|
|
|
procedure consumer(pair: tpair);
|
|
var
|
|
p: ttestarray;
|
|
i, j, k: longint;
|
|
begin
|
|
done := false;
|
|
filldword(p, sizeof(p) div sizeof(dword), 0);
|
|
i := 0;
|
|
j := 0;
|
|
k := 0;
|
|
entercriticalsection(pair.freefifolock);
|
|
while not done do
|
|
begin
|
|
if pair.readindex <> pair.writeindex then
|
|
begin
|
|
{ counterpart for the writebarrier in the producer: ensure that we see
|
|
the write to pair.fifo[pair.writeindex] now that we've seen the write
|
|
to pair.writeindex }
|
|
readbarrier;
|
|
freemem(pair.fifo[pair.readindex]);
|
|
pair.fifo[pair.readindex] := getmem(((pair.writeindex*17) mod 520)+8);
|
|
writebarrier;
|
|
pair.readindex := (pair.readindex + 1) mod fifolength;
|
|
end else begin
|
|
exercise_heap(p,i,j);
|
|
inc(k);
|
|
if k = 100 then
|
|
begin
|
|
k := 0;
|
|
ThreadSwitch;
|
|
end;
|
|
end;
|
|
end;
|
|
pair.shared := getmem(12);
|
|
leavecriticalsection(pair.freefifolock);
|
|
freearray(p, sizeof(p) div sizeof(pointer));
|
|
end;
|
|
|
|
procedure tproducethread.execute;
|
|
begin
|
|
running:=true;
|
|
producer(pair);
|
|
end;
|
|
|
|
procedure tconsumethread.execute;
|
|
begin
|
|
running:=true;
|
|
consumer(pair);
|
|
end;
|
|
|
|
const
|
|
numpairs = 2;
|
|
var
|
|
pairs: array[1..numpairs] of tpair;
|
|
i, iter, num_iterations: integer;
|
|
begin
|
|
num_iterations := 20;
|
|
if paramcount > 0 then
|
|
num_iterations := strtointdef(paramstr(1), num_iterations);
|
|
for iter := 1 to num_iterations do
|
|
begin
|
|
done := false;
|
|
for i := low(pairs) to high(pairs) do
|
|
pairs[i] := tpair.create;
|
|
for i := low(pairs) to high(pairs) do
|
|
pairs[i].resume;
|
|
|
|
{ wait till all threads are really resumed }
|
|
for i := low(pairs) to high(pairs) do
|
|
while not(pairs[i].produce_thread.running) or not(pairs[i].consume_thread.running) do
|
|
sleep(100);
|
|
|
|
done := true;
|
|
for i := low(pairs) to high(pairs) do
|
|
begin
|
|
pairs[i].waitfor;
|
|
pairs[i].free;
|
|
end;
|
|
end;
|
|
end.
|