This repository has been archived by the owner on Nov 7, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
/
FreeIPC.f90
2904 lines (2298 loc) · 95.8 KB
/
FreeIPC.f90
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
!> \mainpage
!! FreeIPC - A module to allow Fortran programs that use MPI
!! to easily access shared memory within multicore nodes
!! \date 28th Nov 2009
!! \version 0.0
!! \author © Ian Bush
!!
!! \section Legal Legal
!!
!! This library is free software; you can redistribute it and/or
!! modify it under the terms of the GNU Lesser General Public
!! License as published by the Free Software Foundation; either
!! version 3.0 of the License, or (at your option) any later version.
!!
!! This library is distributed in the hope that it will be useful,
!! but WITHOUT ANY WARRANTY; without even the implied warranty of
!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
!! Lesser General Public License for more details.
!!
!! You should have received a copy of the GNU Lesser General Public
!! License along with this library; if not, write to the Free Software
!! Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
!!
!!
!! This library is released under LGPL. The full text of LGPL may be found
!! at http://www.gnu.org/licenses/lgpl-3.0.txt
!!
!! In particular, the terms of the GNU LGPL imply that you CAN use this library with
!! proprietary code with some restrictions (you can link, but not use the code directly).
!! Please consult the above URL for exact details.
!!
!! \section Introduction Introduction
!!
!! FreeIPC is a Fortran module that attempts to allow MPI programs easy access to
!! stard system V IPC facilities and related concepts. At present the following facilities
!! are supported:
!! - Creation and deletion of shared memory segments
!! - Critical regions
!! - intra-node synchronisation
!!
!! See
!!
!! http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_07.html#tag_02_07
!!
!! for more details.
!!
!! \section Compilation Compilation
!!
!! To module is written in standard fortran 95, except for using the the following fortran 2003
!! features
!! - Interoperability with C
!! - Intent for Pointer dummy arguments
!! - Allocatable components of derived types ( i.e. TR15581 )
!!
!! It has been shown to compile succesfully with the following compilers:
!! - gfortran ( requires version 4.3 or later )
!! - g95
!! - Intel
!! - Portland Group
!! - Pathscale
!! - Cray
!! - Sun
!! - IBM
!!
!! MPI must also be available
!!
!! \section Use Use
!!
!! As the code is a Fortran module to access the provided facilities simply
!!
!! \c Use \c FIPC_module
!!
!! is all that is required. FreeIPC reserves all symbols that start with the
!! characters \c FIPC_ for its own use, and programs that use FreeIPC should avoid
!! using such symbols to avoid name clashes.
!!
!! Before any FreeIPC facility is used MPI must be initialised. FreeIPC is itself
!! initialized by FIPC_init, and finalized with FIPC_finalize.
!!
!! The interface is deliberately very similar to MPI. In FreeIPC the place of the MPI
!! communicator is taken by a \e context.
!!
!! \subsection Contexts Contexts
!!
!! A context can be viewed as an extension to an MPI communicator
!! as it contains not only a set of processes but also information about how these map
!! onto any shared memory hardware. In fact it contains 3 communicators
!! - The world communicator: This is simply all processes spanned by the context
!! - The intra-communicator: Processes in the same intra-communicator may communicate with
!! each other through shared memory facilities. Therefore all proceeses
!! in an intra-communicator may all access, for example, the same shared
!! shared memory segment
!! - The extra-communicator: This contains all processes which have rank 0 in an intra communicator.
!! It is useful for communicating shared memory segments between nodes
!!
!! Programs may create their own contexts, and any shared memory features of the architecture
!! are automatically detected. Note that an intra-communicator need not span the whole of a shared
!! memory node, and it is possible to have many different contexts on a shared memory node each
!! spanning differnet subsets of the processors on the node.
!!
!! Unlike MPI a context is an opaque entity of derived type \c FIPC_ctxt. Once FreeIPC is initialised
!! the context \c FIPC_ctxt_world is available for use. This is the equivalent of MPI_comm_world; it spans
!! all processors over which FreeIPC is initialised and the intra-communicators spann all processes on the
!! ( autmoaticaly detected ) shared memory node.
!!
!! \subsection Seg_creat Shared Memory Segment Creation And Deletion
!!
!! Shared memory segments are created through the interface FIP_seg_create, and freed by
!! FIPC_seg_free. Arrays of 3 data types are supported
!! - Integer of kind c_int i.e. default integer
!! - Real of kind c_double i.e. "Double Precision"
!! - Complex of kind c_double_complex i.e. "Double Complex"
!! The arrays may be 1 to 7 dimensional. Segment creation occurs within a context,
!! and one segment is created per intra-communicator.
!! So, for example, if the context supplied is FIPC_ctxt_world, one segment is created
!! on each of the ( shared memory ) nodes of the machine.
!!
!! FIPC_seg_create returns a fortran pointer with the appropriate attributes for the
!! data type and kind required. Thus the program now views the segment as a normal
!! Fortran datatype, and the full power of the language is available to process data in it!
!!
!! \subsection Synchronization Synchronization
!!
!! As with MPI and OpenMP it is the duty of the application programmer to ensure that
!! the processes in the job are properly synchronized so as to avoid race conditions.
!! FreeIPC provides two synchronization mechanisms over and above those provided by MPI:
!! - Critical regions
!! - Intra-node barriers
!!
!! \subsection Example An Example Program
!!
!! \verbatim
!! Program FreeIPC_example
!!
!! Use MPI
!! Use FIPC_module
!!
!! Implicit None
!!
!! Integer, Dimension( : ), Pointer :: seg
!!
!! Integer :: rank
!! Integer :: error
!! Integer :: i
!!
!! Call MPI_init( error )
!! Call MPI_comm_rank( MPI_comm_world, rank, error )
!!
!! ! Start up FreeIPC
!! Call FIPC_init( MPI_comm_world, error )
!!
!! ! Create a segment that consists of one integer
!! Call FIPC_seg_create( FIPC_ctxt_world, (/ 1 /), seg, error )
!!
!! seg = 0
!! ! Make sure everybody has initialized seg
!! Call FIPC_node_barrier( FIPC_ctxt_world, error )
!!
!! ! A deliberate race condition !
!! Do i = 1, 1000
!! seg = seg + 1
!! End Do
!! ! Make sure everybody has finished the loop
!! Call FIPC_node_barrier( FIPC_ctxt_world, error )
!! If( rank == 0 ) Then
!! Write( *, * ) seg
!! End If
!! ! Make sure the result has been written out
!! Call FIPC_node_barrier( FIPC_ctxt_world, error )
!!
!! ! Now do it properly
!! seg = 0
!! ! Make sure everybody has initialized seg
!! Call FIPC_node_barrier( FIPC_ctxt_world, error )
!! Do i = 1, 1000
!! Call FIPC_critical_start( FIPC_ctxt_world, error )
!! seg = seg + 1
!! Call FIPC_critical_end( FIPC_ctxt_world, error )
!! End Do
!! ! Make sure everybody has finished the loop
!! Call FIPC_node_barrier( FIPC_ctxt_world, error )
!! If( rank == 0 ) Then
!! Write( *, * ) seg
!! End If
!! ! Make sure the result has been written out
!! Call FIPC_node_barrier( FIPC_ctxt_world, error )
!!
!! ! Free our segment
!! Call FIPC_seg_free( seg, error )
!!
!! ! Close down FreeIPC
!! Call FIPC_finalize( error )
!!
!! Call MPI_finalize( error )
!!
!! End Program FreeIPC_example
!! \endverbatim
!!
!! Example output:
!! \verbatim
!! Wot now ? mpirun -np 2 ./a.out
!! 1073
!! 2000
!! \endverbatim
Module FIPC_module
! A library to allow Fortran programs that use MPI to easily access
! shared memory within multicore nodes
! It uses standard Fortran 2003 and a few thin C wrappers. Fortran
! 2003 C interoperability is used extensively, however the rest of
! the code is standard Fortran 95, expcept for the use of allocatble
! components of derived types - again a standard Fortran 2003 language
! feature.
! The shared memory facilities are provided by use of the standard System V
! IPC facilities. See
!
! http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_07.html#tag_02_07
!
! for details
Use, Intrinsic :: iso_c_binding, Only : c_int, c_long, c_double, c_ptr, &
c_f_pointer, c_null_ptr, c_associated, c_loc
Use mpi
Implicit None
!
! Little type to handle communicators and associated data
!
!!!> \cond
Type, Private :: communicator
Private
!> \private
Logical :: initialized = .False.
!> \private
Integer :: handle
!> \private
Integer :: size
!> \private
Integer :: rank
End Type communicator
!!!> \endcond
!>
!! \brief An opaque type that represents a FIPC context.
!!
!! This type represents a FIPC context. It is an opaque data type with no public components
!! All operations occur within a context. It is very similar to
!! to a mpi communicator with a bit of extra stuff held to look
!! after the shared memory parts of the architecture.
!!
!! \if for_fipc_implementors
!! It consists of a:
!! INITIALIZED: Is this context set up ?
!! Note we only use the allocation status of the pointer to check this
!! WORLD_COMM : The communicator spanning all processes in this context
!! INTRA_COMM : A communicator spanning all process in the context on this shared memory node
!! EXTRA_COMM : A communicator spanning all the process zeros in all the intra_comms
!! on all the nodes which hold processes in WORLD_COMM
!! SEMID : The handle of a semaphore shared by members of the INTRA_COMM
!> \endif
!
Type, Public :: FIPC_ctxt
Private
!> \private
Logical , Pointer :: initialized => Null()
!> \private
Type( communicator ), Pointer :: world_comm
!> \private
Type( communicator ), Pointer :: intra_comm
!> \private
Type( communicator ), Pointer :: extra_comm
!> \private
Integer :: semid
End Type FIPC_ctxt
!> The "default" context. Compare MPI_COMM_WORLD.
Type( FIPC_ctxt ), Save, Public :: FIPC_ctxt_world
! Error flags. Note we avoid clashes with the mpi error flags.
!> Return value to indicate succesful completion
Integer, Parameter, Public :: FIPC_success = 0
!> Return value indicating an attempt was made to initialise FreeIPC when it was already initialised
Integer, Parameter, Public :: FIPC_already_initialized = 1 + MPI_ERR_LASTCODE
!> Return value indicating a memory allocation failed within FreeIPC
Integer, Parameter, Public :: FIPC_allocation_failed = 2 + MPI_ERR_LASTCODE
!> Return value indicating that an attempt to get a shared memory segment failed
Integer, Parameter, Public :: FIPC_seg_get_failed = 3 + MPI_ERR_LASTCODE
!> Return value indicating that an attempt to attach to a shared memory segment failed
Integer, Parameter, Public :: FIPC_seg_attach_failed = 4 + MPI_ERR_LASTCODE
!> Return value indicating that an attempt to inquire the properties shared memory segment failed
Integer, Parameter, Public :: FIPC_seg_inquire_failed = 5 + MPI_ERR_LASTCODE
!> Return value indicating that an attempt to detach from shared memory segment failed
Integer, Parameter, Public :: FIPC_seg_detach_failed = 6 + MPI_ERR_LASTCODE
!> Return value indicating that an attempt to remove a shared memory segment failed
Integer, Parameter, Public :: FIPC_seg_remove_failed = 7 + MPI_ERR_LASTCODE
!> Return value indicating that a FreeIPC internal consistency check failed
Integer, Parameter, Public :: FIPC_sanity_failed = 8 + MPI_ERR_LASTCODE
!> Return value indicating that an attempt was made to free FIPC_ctxt_world
Integer, Parameter, Public :: FIPC_freeing_ctxt_world = 9 + MPI_ERR_LASTCODE
!> Return value indicating that FreeIPC could not identify which shared memory segment is to be freed
Integer, Parameter, Public :: FIPC_seg_not_found = 10 + MPI_ERR_LASTCODE
!> Return value indicating that an attempt was made to free a NULL pointer
Integer, Parameter, Public :: FIPC_free_null_pointer = 11 + MPI_ERR_LASTCODE
!> Return value indicating that an insufficent dimensions were supplied when allocating a shared memory segment
Integer, Parameter, Public :: FIPC_insufficient_dims = 12 + MPI_ERR_LASTCODE
!> Return value indicating that FreeIPC was not initalized
Integer, Parameter, Public :: FIPC_not_initialized = 13 + MPI_ERR_LASTCODE
!> Return value indicating that an attempt was made to free a context that was still in use, for instance
!> a shared memory segment still exists within that context
Integer, Parameter, Public :: FIPC_ctxt_in_use = 14 + MPI_ERR_LASTCODE
!> Return value indicating that an attempt to get a semaphore failed
Integer, Parameter, Public :: FIPC_sem_get_failed = 15 + MPI_ERR_LASTCODE
!> Return value indicating that an attempt to remove a semaphore failed
Integer, Parameter, Public :: FIPC_sem_remove_failed = 16 + MPI_ERR_LASTCODE
!> Return value indicating that FreeIPC could not identify which semaphore is to be freed
Integer, Parameter, Public :: FIPC_sem_not_found = 17 + MPI_ERR_LASTCODE
!> Return value indicating that an attempt to start a critical region failed
Integer, Parameter, Public :: FIPC_critical_start_failed = 16 + MPI_ERR_LASTCODE
!> Return value indicating that an attempt to start a critical region failed
Integer, Parameter, Public :: FIPC_critical_end_failed = 17 + MPI_ERR_LASTCODE
!> Value to indicate that this process should not be in the context that results
!> from a FIPC_ctxt_split
Integer, Parameter, Public :: FIPC_undefined = MPI_undefined
!> Value to indicate that an attempt has been made to extract a non-existant communicator
!> from a context. The most common case is trying to extract the extra communicator on a process
!> that is not rank zero in an intra communicator
Integer, Parameter, Public :: FIPC_comm_null = MPI_comm_null
! Reductions available
!> Handle to indicate a global sum is to be performed in a reduction operation
Integer, Parameter, Public :: FIPC_sum = mpi_sum
!> Handle to indicate a global product is to be performed in a reduction operation
Integer, Parameter, Public :: FIPC_prod = mpi_prod
!> Handle to indicate a global minimum is to be performed in a reduction operation
Integer, Parameter, Public :: FIPC_max = mpi_max
!> Handle to indicate a global maximum is to be performed in a reduction operation
Integer, Parameter, Public :: FIPC_min = mpi_min
! Public interfaces
Public :: FIPC_init
Public :: FIPC_initialized
Public :: FIPC_finalize
Public :: FIPC_ctxt_dup
Public :: FIPC_ctxt_split
Public :: FIPC_ctxt_free
Public :: FIPC_ctxt_intra_comm
Public :: FIPC_ctxt_world_comm
Public :: FIPC_ctxt_extra_comm
Public :: FIPC_seg_create
Public :: FIPC_seg_free
Public :: FIPC_node_barrier
Public :: FIPC_critical_start
Public :: FIPC_critical_end
!!$ Public :: FIPC_allreduce
Private
!> \brief Create a shared memory segment.
!!
!! Sets up a shared memory segment on each of the shared memory nodes spanned by the context ctxt. The interface is\n
!! Subroutine FIPC_seg_create(
!! Type( FIPC_ctxt ),intent(in) ctxt,\n
!! Integer, Dimension( : ),intent(in) n,\n
!! <choice>,Dimension( <1-7d> ),intent(out) a,\n
!! Integer,intent(out) error )
!! \param ctxt The context within which to create the segment
!! \param n An array containg the dimensions of the arry which will be stored in the segment
!! \param a A pointer to a 1-7 dimensionsal array of type Integer( c_int ), Real( c_double ) or
!! Complex( complex ). On exit this points to the shared memory segment
!! \param error On success ERROR is set to FIPC_SUCCESS. Any other value indicates error.
!>
Interface FIPC_seg_create
Module Procedure seg_create_integer_1d_size_in_int
Module Procedure seg_create_integer_2d_size_in_int
Module Procedure seg_create_integer_3d_size_in_int
Module Procedure seg_create_integer_4d_size_in_int
Module Procedure seg_create_integer_5d_size_in_int
Module Procedure seg_create_integer_6d_size_in_int
Module Procedure seg_create_integer_7d_size_in_int
Module Procedure seg_create_double_1d_size_in_int
Module Procedure seg_create_double_2d_size_in_int
Module Procedure seg_create_double_3d_size_in_int
Module Procedure seg_create_double_4d_size_in_int
Module Procedure seg_create_double_5d_size_in_int
Module Procedure seg_create_double_6d_size_in_int
Module Procedure seg_create_double_7d_size_in_int
Module Procedure seg_create_complex_1d_size_in_int
Module Procedure seg_create_complex_2d_size_in_int
Module Procedure seg_create_complex_3d_size_in_int
Module Procedure seg_create_complex_4d_size_in_int
Module Procedure seg_create_complex_5d_size_in_int
Module Procedure seg_create_complex_6d_size_in_int
Module Procedure seg_create_complex_7d_size_in_int
End Interface
!>
!!
!! \brief Frees a shared memory segment.
!!
!! This routine frees a shared memory segment on each of the shared memory nodes spanned by the context ctxt
!>
Interface FIPC_seg_free
Module Procedure seg_free_integer_1d
Module Procedure seg_free_integer_2d
Module Procedure seg_free_integer_3d
Module Procedure seg_free_integer_4d
Module Procedure seg_free_integer_5d
Module Procedure seg_free_integer_6d
Module Procedure seg_free_integer_7d
Module Procedure seg_free_double_1d
Module Procedure seg_free_double_2d
Module Procedure seg_free_double_3d
Module Procedure seg_free_double_4d
Module Procedure seg_free_double_5d
Module Procedure seg_free_double_6d
Module Procedure seg_free_double_7d
Module Procedure seg_free_complex_1d
Module Procedure seg_free_complex_2d
Module Procedure seg_free_complex_3d
Module Procedure seg_free_complex_4d
Module Procedure seg_free_complex_5d
Module Procedure seg_free_complex_6d
Module Procedure seg_free_complex_7d
End Interface
!!!!> \cond for_fipc_implementors
! Error flags that can be returned by the System V routines
! Need to read these from the C header files
Integer, Private :: EACCES
Integer, Private :: EEXIST
Integer, Private :: EINVAL
Integer, Private :: ENFILE
Integer, Private :: ENOENT
Integer, Private :: ENOMEM
Integer, Private :: ENOSPC
! Flags for control of the creation of shared beasties
Integer( c_int ), Private :: SEG_NOCREATE = 0
Integer( c_int ), Private :: SEG_CREATE = 1
Integer( c_int ), Private :: SEG_NOEXCLUDE = 0
Integer( c_int ), Private :: SEG_EXCLUDE = 1
Integer( c_int ), Private :: SEG_UREAD = 4 * 8 * 8
Integer( c_int ), Private :: SEG_UWRITE = 2 * 8 * 8
Integer( c_int ), Private :: SEG_GREAD = 4 * 8
Integer( c_int ), Private :: SEG_GWRITE = 2 * 8
Integer( c_int ), Private :: SEG_WREAD = 4
Integer( c_int ), Private :: SEG_WWRITE = 2
Integer( c_int ), Private :: SEG_NOREADONLY = 0
Integer( c_int ), Private :: SEG_READONLY = 1
! Elements of seg inquire array
Integer( c_long ), Parameter, Private :: SEG_SEGSZ = 1 ! size of segment in bytes
Integer( c_long ), Parameter, Private :: SEG_LPID = 2 ! process ID of last shared memory operation
Integer( c_long ), Parameter, Private :: SEG_CPID = 3 ! process ID of creator
Integer( c_long ), Parameter, Private :: SEG_NATTCH = 4 ! number of current attaches
Integer( c_long ), Parameter, Private :: SEG_ATIME = 5 ! time of last shmat()
Integer( c_long ), Parameter, Private :: SEG_DTIME = 6 ! time of last shmdt()
Integer( c_long ), Parameter, Private :: SEG_CTIME = 7 ! time of last change by shmctl()
! For differentiating between data types
Integer, Parameter, Private :: integer_vals = 1
Integer, Parameter, Private :: double_vals = 2
Integer, Parameter, Private :: complex_vals = 3
! Debugging Flag. Set to false for production
Logical, Parameter, Private :: debug = .False.
! Derived type for storing data about a segment
Type, Private :: segment
Integer( c_int ) :: shmid
Type( c_ptr ) :: shmaddr
Type( FIPC_ctxt ) :: ctxt
Integer :: type
Integer( c_long ), Dimension( : ), Allocatable :: sizes
End Type segment
! Derived type for linked list for saving data about created segments
Type, Private :: segment_list_type
Type( segment ) :: data
Type( segment_list_type ), Pointer :: next => Null()
End Type segment_list_type
! Linked list of data about created segments
Type( segment_list_type ), Pointer, Private :: seg_list => Null()
! Derived type for storing data about a semaphore
Type, Private :: semaphore
Integer( c_int ) :: semid
Type( FIPC_ctxt ) :: ctxt
End Type semaphore
! Derived type for linked list for saving data about created semaphores
Type, Private :: semaphore_list_type
Integer( c_int ) :: semid
Integer :: intra_handle
Type( semaphore_list_type ), Pointer :: next => Null()
End Type semaphore_list_type
! Linked list of data about created segements
Type( semaphore_list_type ), Pointer, Private :: sem_list => Null()
! Largest allowed size for temporary buffers
Integer, Parameter, Private :: max_buff_size = 1024 * 1024 / 8 ! 1 Mbyte of reals
! Interfaces to C wrappers.
Interface
Subroutine FIPC_get_errval( EACCES, EEXIST, EINVAL, ENFILE, ENOENT, ENOMEM, ENOSPC ) Bind( C )
Use, Intrinsic :: iso_c_binding, Only : c_int
Implicit None
Integer( c_int ), Intent( In ) :: EACCES
Integer( c_int ), Intent( In ) :: EEXIST
Integer( c_int ), Intent( In ) :: EINVAL
Integer( c_int ), Intent( In ) :: ENFILE
Integer( c_int ), Intent( In ) :: ENOENT
Integer( c_int ), Intent( In ) :: ENOMEM
Integer( c_int ), Intent( In ) :: ENOSPC
End Subroutine FIPC_get_errval
Function FIPC_get_seg( size, create, exclusive, perms ) Bind( C )
Use, Intrinsic :: iso_c_binding, Only : c_int, c_long
Implicit None
Integer( c_int ) :: FIPC_get_seg
Integer( c_long ), Value, Intent( In ) :: size
Integer( c_int ), Value, Intent( In ) :: create
Integer( c_int ), Value, Intent( In ) :: exclusive
Integer( c_int ), Value, Intent( In ) :: perms
End Function FIPC_get_seg
Function FIPC_attach_seg( shmid, flag ) Bind( C )
Use, Intrinsic :: iso_c_binding, Only : c_int, c_ptr
Implicit None
Type( c_ptr ) :: FIPC_attach_seg
Integer( c_int ), Value, Intent( In ) :: shmid
Integer( c_int ), Value, Intent( In ) :: flag
End Function FIPC_attach_seg
Function FIPC_detach_seg( shmaddr ) Bind( C )
Use, Intrinsic :: iso_c_binding, Only : c_int, c_ptr
Implicit None
Integer( c_int ) :: FIPC_detach_seg
Type( c_ptr ), Value :: shmaddr ! No intent because this confuses
! the Cray compiler
End Function FIPC_detach_seg
Function FIPC_remove_seg( shmid ) Bind( C )
Use, Intrinsic :: iso_c_binding, Only : c_int
Implicit None
Integer( c_int ) :: FIPC_remove_seg
Integer( c_int ), Value, Intent( In ) :: shmid
End Function FIPC_remove_seg
Function FIPC_get_sem( create, exclusive, perms ) Bind( C )
Use, Intrinsic :: iso_c_binding, Only : c_int
Implicit None
Integer( c_int ) :: FIPC_get_sem
Integer( c_int ), Value, Intent( In ) :: create
Integer( c_int ), Value, Intent( In ) :: exclusive
Integer( c_int ), Value, Intent( In ) :: perms
End Function FIPC_get_sem
Function FIPC_crit_start( semid ) Bind( C )
Use, Intrinsic :: iso_c_binding, Only : c_int
Implicit None
Integer( c_int ) :: FIPC_crit_start
Integer( c_int ), Value, Intent( In ) :: semid
End Function FIPC_crit_start
Function FIPC_crit_end( semid ) Bind( C )
Use, Intrinsic :: iso_c_binding, Only : c_int
Implicit None
Integer( c_int ) :: FIPC_crit_end
Integer( c_int ), Value, Intent( In ) :: semid
End Function FIPC_crit_end
Function FIPC_remove_sem( semid ) Bind( C )
Use, Intrinsic :: iso_c_binding, Only : c_int
Implicit None
Integer( c_int ) :: FIPC_remove_sem
Integer( c_int ), Value, Intent( In ) :: semid
End Function FIPC_remove_sem
Function FIPC_inquire_seg( shmid, n, shm_data ) Bind( C )
Use, Intrinsic :: iso_c_binding, Only : c_int, c_long
Implicit None
Integer( c_int ) :: FIPC_inquire_seg
Integer( c_int ), Value , Intent( In ) :: shmid
Integer( c_int ), Value , Intent( In ) :: n
Integer( c_long ), Dimension( * ), Intent( Out ) :: shm_data
End Function FIPC_inquire_seg
Function FIPC_sizeof_c_int() Bind( C )
Use, Intrinsic :: iso_c_binding, Only : c_int
Implicit None
Integer( c_int ) :: FIPC_sizeof_c_int
End Function FIPC_sizeof_c_int
Function FIPC_sizeof_c_long() Bind( C )
Use, Intrinsic :: iso_c_binding, Only : c_int
Implicit None
Integer( c_int ) :: FIPC_sizeof_c_long
End Function FIPC_sizeof_c_long
Function FIPC_sizeof_c_double() Bind( C )
Use, Intrinsic :: iso_c_binding, Only : c_int
Implicit None
Integer( c_int ) :: FIPC_sizeof_c_double
End Function FIPC_sizeof_c_double
Function FIPC_sizeof_c_complex() Bind( C )
Use, Intrinsic :: iso_c_binding, Only : c_int
Implicit None
Integer( c_int ) :: FIPC_sizeof_c_complex
End Function FIPC_sizeof_c_complex
End Interface
! Interfaces for context comparison function
Interface operator( == )
Module Procedure test_eq_ctxt
End Interface
Interface operator( /= )
Module Procedure test_ne_ctxt
End Interface
! Interfaces for communicator comparison function
Interface operator( == )
Module Procedure test_eq_comm
End Interface
Interface operator( /= )
Module Procedure test_ne_comm
End Interface
!!!!> \endcond
! Overloaded interfaces
!!$ Interface FIPC_allreduce
!!$ Module Procedure allreduce_double
!!$ End Interface
Contains
!> \brief Initialise FreeIPC.
!!
!! This routine initializes FreeIPC. It sets up a context spanning all process in the MPI communicator
!! universe_comm, i.e. FIPC_ctxt_world, and determines which processes are on the smae shared memory node.
!! \param universe_comm The communicator that spans all the processes within which FreeIPC will work
!! \param error On success ERROR is set to FIPC_SUCCESS. Any other value indicates error.
!>
Subroutine FIPC_init( universe_comm, error )
Integer, Intent( In ) :: universe_comm
Integer, Intent( Out ) :: error
Integer :: world_comm, intra_comm, extra_comm
! Can only initialise once
If( Associated( FIPC_ctxt_world%initialized ) ) Then
error = FIPC_already_initialized
Return
End If
! Get the error values that the system V routine can return
Call FIPC_get_errval( EACCES, EEXIST, EINVAL, ENFILE, ENOENT, ENOMEM, ENOSPC )
! From the universe communicator generate the 3 communicators required
! to specify FIPC_ctxt_world
Call generate_base_comms( universe_comm, world_comm, intra_comm, extra_comm, error )
If( error /= FIPC_success ) Then
Return
End If
! From those communicators generate FIPC_ctxt_world
Call ctxt_create( world_comm, intra_comm, extra_comm, FIPC_ctxt_world, error )
If( error /= FIPC_success ) Then
Return
End If
error = FIPC_success
End Subroutine FIPC_init
!> \brief Test if FreeIPC is initialised.
!!
!! Test if FreeIPC is initialised.
!! \param flag On succesful exit this is set to .true. if FIPC is initialised, , .false. otherwise
!! \param error On success ERROR is set to FIPC_SUCCESS. Any other value indicates error.
!>
Subroutine FIPC_initialized( flag, error )
! Test whether FreeIPC has been initialized.
! On success return .True. in FLAG if is has, otherwise .FALSE., and
! set ERROR to FIPC_SUCCESS
! On error FLAG is undefined and ERROR is any value but FIPC_SUCCESS
Logical, Intent( Out ) :: flag
Integer, Intent( Out ) :: error
flag = Associated( FIPC_ctxt_world%initialized )
error = FIPC_success
End Subroutine FIPC_initialized
!> \brief Finalise FreeIPC.
!!
!! This routine closes FreeIPC down. It frees all shared memory segments and semaphores
!! that the user has created through FreeIPC, and frees FIPC_ctxt_world.
!! \param error On success ERROR is set to FIPC_SUCCESS. Any other value indicates error.
!>
Subroutine FIPC_finalize( error )
! Finalize FIPC.
!
! On success ERROR is set to FIPC_SUCCESS. Any other value
! indicates error. These can be compared to the symbolic constants
! defined above for better diagnosis
Integer, Intent( Out ) :: error
! Check things are initialized
If( .Not. Associated( FIPC_ctxt_world%initialized ) ) Then
error = FIPC_not_initialized
Return
End If
! Free all the segments we know about
Do While( Associated( seg_list ) )
Call segment_free( seg_list%data%shmid, error )
If( error /= FIPC_success ) Then
Return
End If
End Do
! And free the context
Call ctxt_free( FIPC_ctxt_world, error )
If( error /= 0 ) Then
Return
End If
! Finally free any outstanding semaphores we know about
Do While( Associated( sem_list ) )
Call semaphore_free( sem_list%semid, error )
If( error /= FIPC_success ) Then
Return
End If
End Do
error = FIPC_success
End Subroutine FIPC_finalize
!> \brief Duplicate a context
!!
!! This routine duplicates the context ctxt_1, returning a new context in ctxt_2. This is very similar to
!! mpi_comm_dup - see http://www.mcs.anl.gov/research/projects/mpi/www/www3/MPI_Comm_dup.html
!! \param ctxt_1 The input context
!! \param ctxt_2 The result context
!! \param error On success ERROR is set to FIPC_SUCCESS. Any other value indicates error.
!>
Subroutine FIPC_ctxt_dup( ctxt_1, ctxt_2, error )
! Duplicate the context CTXT_1, returning th new context in CTXT_2
!
! On success ERROR is set to FIPC_SUCCESS. Any other value
! indicates error. These can be compared to the symbolic constants
! defined above for better diagnosis
Type( FIPC_ctxt ), Intent( In ) :: ctxt_1
Type( FIPC_ctxt ), Intent( Out ) :: ctxt_2
Integer , Intent( Out ) :: error
Integer :: world_comm_2
Integer :: intra_comm_2
Integer :: extra_comm_2
! Check things are initialized
If( .Not. Associated( FIPC_ctxt_world%initialized ) ) Then
error = FIPC_not_initialized
Return
End If
! Duplicate the communicators
Call mpi_comm_dup( ctxt_1%world_comm%handle, world_comm_2, error )
If( error /= 0 ) Then
Return
End If
Call mpi_comm_dup( ctxt_1%intra_comm%handle, intra_comm_2, error )
If( error /= 0 ) Then
Return
End If
! Extra comm only defined on rank 0 of the intra comm
If( ctxt_1%intra_comm%rank == 0 ) Then
Call mpi_comm_dup( ctxt_1%extra_comm%handle, extra_comm_2, error )
If( error /= 0 ) Then
Return
End If
End If
! Now create the new context
Call ctxt_create( world_comm_2, intra_comm_2, extra_comm_2, ctxt_2, error )
If( error /= 0 ) Then
Return
End If
error = FIPC_success
End Subroutine FIPC_ctxt_dup
!> \brief Split a context
!!
!! This routine splits the context CTXT_1 according to the colours and keys given
!! by COLOUR and KEY, with the. Processes with the same value of COLOUR end up
!! in the same new context, the rank order being controlled by KEY. The special value FIPC_undefined
!! may be used to indicate that a process should not be in any of the new contexts that are
!! created by this routine. This is very
!! similar to MPI_COMM_SPLIT, see http://www.mcs.anl.gov/research/projects/mpi/www/www3/MPI_Comm_split.html
!! \param ctxt_1 The input context
!! \param colour Control of subset assignment (nonnegative integer or FIPC_undefined). Processes with the same color are
!! in the same new context
!! \param key Control of rank assigment
!! \param ctxt_2 The result context
!! \param error On success ERROR is set to FIPC_SUCCESS. Any other value indicates error.
!>
Subroutine FIPC_ctxt_split( ctxt_1, colour, key, ctxt_2, error )
Type( FIPC_ctxt ), Intent( In ) :: ctxt_1
Integer , Intent( In ) :: colour
Integer , Intent( In ) :: key
Type( FIPC_ctxt ), Intent( Out ) :: ctxt_2
Integer , Intent( Out ) :: error
Integer :: world_comm_2
Integer :: intra_comm_2
Integer :: extra_comm_2
Integer :: intra_rank, is_node_0
! Check things are initialized
If( .Not. Associated( FIPC_ctxt_world%initialized ) ) Then
error = FIPC_not_initialized
Return
End If
! Split the communicators
Call mpi_comm_split( ctxt_1%world_comm%handle, colour, key, world_comm_2, error )
If( error /= 0 ) Then
Return
End If
Call mpi_comm_split( ctxt_1%intra_comm%handle, colour, key, intra_comm_2, error )
If( error /= 0 ) Then
Return
End If
! Extra comm only defined on rank 0 of the intra comm
! BUT WHAT IF SPLIT WITHIN THE INTRA COMM. Need to think here ....
Call mpi_comm_rank( intra_comm_2, intra_rank, error )
If( error /= 0 ) Then
Return
End If
is_node_0 = merge( 1, MPI_UNDEFINED, intra_rank == 0 )
Call mpi_comm_split( world_comm_2, colour, key, extra_comm_2, error )
If( error /= 0 ) Then
Return
End If
! Now create the new context if required
If( colour /= FIPC_undefined ) Then
Call ctxt_create( world_comm_2, intra_comm_2, extra_comm_2, ctxt_2, error )
End If
If( error /= 0 ) Then
Return
End If
error = FIPC_success
End Subroutine FIPC_ctxt_split
!> \brief Free a context
!!
!! This routine frees the context CTXT. Compare MPI_COMM_FREE -
!! http://www.mcs.anl.gov/research/projects/mpi/www/www3/MPI_Comm_free.html
!! \param ctxt The context to be freed
!! \param error On success ERROR is set to FIPC_SUCCESS. Any other value indicates error.
!>
Subroutine FIPC_ctxt_free( ctxt, error )
Type( FIPC_ctxt ), Intent( InOut ) :: ctxt
Integer , Intent( Out ) :: error
Type( segment_list_type ), Pointer :: p
! Check things are initialized
If( .Not. Associated( FIPC_ctxt_world%initialized ) ) Then
error = FIPC_not_initialized
Return
End If
! Check not trying to free the base context
If( ctxt == FIPC_ctxt_world ) Then
error = FIPC_freeing_ctxt_world
Return
End If
! Check if anybody is still using this context
p => seg_list
Do While( Associated( p ) )
If( p%data%ctxt == ctxt ) Then
error = FIPC_ctxt_in_use
Return
End If
p => p%next
End Do
Call ctxt_free( ctxt, error )
If( error /= FIPC_SUCCESS ) Then
Return
End If
error = FIPC_success
End Subroutine FIPC_ctxt_free
!> \brief Extract the intra-node communicator
!!
!! This routine extracts from the context CTXT a communicator that spans the processes
!! within the context on the same shared memory node. The general syntax is similar to MPI_COMM_GROUP
!! http://www.mcs.anl.gov/research/projects/mpi/www/www3/MPI_Comm_group.html
!! \param ctxt The context
!! \param comm The intra-node communicator
!! \param error On success ERROR is set to FIPC_SUCCESS. Any other value indicates error.
!>
Subroutine FIPC_ctxt_intra_comm( ctxt, comm, error )
Type( FIPC_ctxt ), Intent( In ) :: ctxt
Integer , Intent( Out ) :: comm
Integer , Intent( Out ) :: error
! Check things are initialized
If( .Not. Associated( FIPC_ctxt_world%initialized ) ) Then
error = FIPC_not_initialized
Return
End If
comm = ctxt%intra_comm%handle
error = FIPC_success
End Subroutine FIPC_ctxt_intra_comm
!> \brief Extract the world communicator
!!
!! This routine extracts from the context CTXT a communicator that spans all the processes
!! within the context. The general syntax is similar to MPI_COMM_GROUP
!! http://www.mcs.anl.gov/research/projects/mpi/www/www3/MPI_Comm_group.html
!! \param ctxt The context
!! \param comm The world communicator
!! \param error On success ERROR is set to FIPC_SUCCESS. Any other value indicates error.
!>
Subroutine FIPC_ctxt_world_comm( ctxt, comm, error )
Type( FIPC_ctxt ), Intent( In ) :: ctxt
Integer , Intent( Out ) :: comm
Integer , Intent( Out ) :: error
! Check things are initialized
If( .Not. Associated( FIPC_ctxt_world%initialized ) ) Then
error = FIPC_not_initialized
Return
End If