That's called a pipe 
On Linux? Because on Windows pipe - is just console-like way to send data between processes. I mean, creating process for every single plugin - is still very costly thing. But this is the only way to do it, if you want to have separate address spaces for your plugins, i.e. if you want them to be 100% safe, so crash of any plugin won't crash whole application and unsafe 3rd party plugins won't be able to steal any confidential data from core of your application. Some middle ground should be found between simple dll plugin (possibly using threads) and having plugin container process for every single plugin.
I've just tried to implement MDI on Lazarus via old trick, I've been using on Delphi - i.e. the fact, that each thread has it's own message queue and form is bound to thread, it's created in. But Lazarus doesn't allow both Application.Run and Application.Process messages to be run in any other thread, except main one.

Yeah, due to some reasons Memo can't get input focus (I have to right-click it) and sometimes application crashes at the end (due to some sync issues, I guess), but at least it compiles and works.
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TMDIThread = class(TThread)
protected
FFormClass:TFormClass;
FParent:TForm;
procedure Execute;override;
public
constructor Create(AFormClass:TFormClass;AParent:TForm);
end;
var
Form1: TForm1;
constructor TMDIThread.Create(AFormClass:TFormClass;AParent:TForm);
begin
FreeOnTerminate := True;
FFormClass := AFormClass;
FParent := AParent;
inherited Create(False);
end;
procedure TMDIThread.Execute;
var MDIApplication:TApplication;
MDIForm:TForm;
begin
MDIApplication := TApplication.Create(nil);
MDIApplication.CreateForm(FFormClass, MDIForm);
MDIForm.Parent := FParent;
MDIForm.Show;
MDIApplication.Run;
MDIApplication.Free;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
TMDIThread.Create(TForm2, Self);
end;