//
// Free Pascal program demonstrates basic use
// of the Ubuntu Shared Memory API within the MPI framework.
// Author: Rick Reeves, NCEAS, July 23 2010
//
program MpiSharedMemoryDemoGolden;

{$mode objfpc}{$H+}
{$IFDEF Unix}
{$Linklib c}
{$ENDIF}
// if you get the error: undefined reference to 'pthread_getspcific' then enable the following:
{off $Linklib pthread}

uses
 MPI, IPC, Baseunix;

type PInt = ^Integer;
 var
    myid,
    mysize: integer;

var key: Tkey;
    shmid: cint;
    segptr: PInt;

// for shmctl (shared memory control) call:

    PShmid_DS: ^TShmid_ds;

Const cFilterDim = 9;
Const SegSize = 64; // 8 x 8 matrix
const ftokpath = '.'#0;

 begin

// even though we are not using it, 
// initialize the MPI infrastructure


    MPI_Init(@argc,@argv);
    MPI_Comm_rank(MPI_COMM_WORLD,@myid);
    MPI_Comm_size(MPI_COMM_WORLD,@mysize);
    writeln('Our NEW MPI id= ',myid,'mysize= ',mysize,'cFilterDim= ',cFilterDim);

// Obtain a block of Shared Memory

  key := ftok (pchar(@ftokpath[1]),ord('R'));

// resume creating shared memory

  shmid := shmget(key,SegSize,IPC_CREAT or IPC_EXCL or 438);
  writeln ('Creating new shared memory segment.');
  segptr:=shmat(shmid,nil,0);
  segptr[1] := 100; // a test

// access and modify the new shared memory segment
// for test, first attatch, then re-attach the pointer

  shmdt(segptr);
  segptr := nil;
  shmid := shmget(key, segsize, 0);

  segptr := shmat(shmid,nil, 0);

// set the shared memory array to some values

  segptr[1] := 1;
  segptr[2] := 20;
  segptr[63] := 3000;

// detach shared memory block from the session, 
// then, reconnect, read the shared memory, check the values

  shmdt(segptr);
  segptr := nil;
  shmid := shmget(key, segsize, 0);
  segptr := shmat(shmid,nil, 0);

 writeln('shared memory values: [1]: ',segptr[1],' [2]: ',segptr[2],' [3]: ',segptr[63]);

// release the shared memory: detach from the process,
// then mark the shared memory for deletion

    shmdt(segptr);
    shmctl (shmid,IPC_RMID,PShmid_DS);

//  end the MPI Session...
    MPI_Finalize;
end.
