update mpich linux
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -12,6 +12,12 @@
|
||||
|
||||
#include "mpi.h"
|
||||
|
||||
#if defined(HAVE_VISIBILITY)
|
||||
#define ROMIO_API_PUBLIC __attribute__((visibility ("default")))
|
||||
#else
|
||||
#define ROMIO_API_PUBLIC
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -24,7 +30,9 @@ extern "C" {
|
||||
typedef struct ADIOI_FileD *MPI_File;
|
||||
#endif
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#define HAVE_MPI_GREQUEST 1
|
||||
/* *INDENT-ON* */
|
||||
#ifndef HAVE_MPI_GREQUEST
|
||||
typedef struct ADIOI_RequestD *MPIO_Request;
|
||||
#else
|
||||
@@ -39,7 +47,9 @@ typedef struct ADIOI_RequestD *MPIO_Request;
|
||||
#define MPIO_REQUEST_DEFINED
|
||||
|
||||
#ifndef HAVE_MPI_OFFSET
|
||||
/* *INDENT-OFF* */
|
||||
typedef long long MPI_Offset;
|
||||
/* *INDENT-ON* */
|
||||
/* If we needed to define MPI_Offset, then we also need to make
|
||||
this definition. */
|
||||
#ifndef HAVE_MPI_DATAREP_FUNCTIONS
|
||||
@@ -52,14 +62,18 @@ typedef int (MPI_Datarep_extent_function)(MPI_Datatype datatype, MPI_Aint *,
|
||||
#endif
|
||||
|
||||
#ifndef NEEDS_MPI_FINT
|
||||
/* *INDENT-OFF* */
|
||||
|
||||
/* *INDENT-ON* */
|
||||
#endif
|
||||
#ifdef NEEDS_MPI_FINT
|
||||
typedef int MPI_Fint;
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_MPI_INFO
|
||||
/* *INDENT-OFF* */
|
||||
#define HAVE_MPI_INFO
|
||||
/* *INDENT-ON* */
|
||||
#endif
|
||||
#ifndef HAVE_MPI_INFO
|
||||
typedef struct MPIR_Info *MPI_Info;
|
||||
@@ -99,7 +113,9 @@ typedef int MPI_Fint;
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_MPI_DARRAY_SUBARRAY
|
||||
/* *INDENT-OFF* */
|
||||
#define HAVE_MPI_DARRAY_SUBARRAY
|
||||
/* *INDENT-ON* */
|
||||
#endif
|
||||
#ifndef HAVE_MPI_DARRAY_SUBARRAY
|
||||
# define MPI_ORDER_C 56
|
||||
@@ -120,150 +136,150 @@ typedef int MPI_Fint;
|
||||
|
||||
/* Section 9.2 */
|
||||
/* Begin Prototypes */
|
||||
int MPI_File_open(MPI_Comm comm, const char *filename, int amode, MPI_Info info, MPI_File *fh);
|
||||
int MPI_File_close(MPI_File *fh);
|
||||
int MPI_File_delete(const char *filename, MPI_Info info);
|
||||
int MPI_File_set_size(MPI_File fh, MPI_Offset size);
|
||||
int MPI_File_preallocate(MPI_File fh, MPI_Offset size);
|
||||
int MPI_File_get_size(MPI_File fh, MPI_Offset *size);
|
||||
int MPI_File_get_group(MPI_File fh, MPI_Group *group);
|
||||
int MPI_File_get_amode(MPI_File fh, int *amode);
|
||||
int MPI_File_set_info(MPI_File fh, MPI_Info info);
|
||||
int MPI_File_get_info(MPI_File fh, MPI_Info *info_used);
|
||||
int MPI_File_open(MPI_Comm comm, const char *filename, int amode, MPI_Info info, MPI_File *fh) ROMIO_API_PUBLIC;
|
||||
int MPI_File_close(MPI_File *fh) ROMIO_API_PUBLIC;
|
||||
int MPI_File_delete(const char *filename, MPI_Info info) ROMIO_API_PUBLIC;
|
||||
int MPI_File_set_size(MPI_File fh, MPI_Offset size) ROMIO_API_PUBLIC;
|
||||
int MPI_File_preallocate(MPI_File fh, MPI_Offset size) ROMIO_API_PUBLIC;
|
||||
int MPI_File_get_size(MPI_File fh, MPI_Offset *size) ROMIO_API_PUBLIC;
|
||||
int MPI_File_get_group(MPI_File fh, MPI_Group *group) ROMIO_API_PUBLIC;
|
||||
int MPI_File_get_amode(MPI_File fh, int *amode) ROMIO_API_PUBLIC;
|
||||
int MPI_File_set_info(MPI_File fh, MPI_Info info) ROMIO_API_PUBLIC;
|
||||
int MPI_File_get_info(MPI_File fh, MPI_Info *info_used) ROMIO_API_PUBLIC;
|
||||
|
||||
/* Section 9.3 */
|
||||
int MPI_File_set_view(MPI_File fh, MPI_Offset disp, MPI_Datatype etype, MPI_Datatype filetype,
|
||||
const char *datarep, MPI_Info info);
|
||||
const char *datarep, MPI_Info info) ROMIO_API_PUBLIC;
|
||||
int MPI_File_get_view(MPI_File fh, MPI_Offset *disp, MPI_Datatype *etype, MPI_Datatype *filetype,
|
||||
char *datarep);
|
||||
char *datarep) ROMIO_API_PUBLIC;
|
||||
|
||||
/* Section 9.4.2 */
|
||||
int MPI_File_read_at(MPI_File fh, MPI_Offset offset, void *buf, int count, MPI_Datatype datatype,
|
||||
MPI_Status *status) MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5);
|
||||
MPI_Status *status) MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5) ROMIO_API_PUBLIC;
|
||||
int MPI_File_read_at_all(MPI_File fh, MPI_Offset offset, void * buf, int count,
|
||||
MPI_Datatype datatype, MPI_Status *status)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5) ROMIO_API_PUBLIC;
|
||||
int MPI_File_write_at(MPI_File fh, MPI_Offset offset, const void * buf, int count,
|
||||
MPI_Datatype datatype, MPI_Status *status)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5) ROMIO_API_PUBLIC;
|
||||
int MPI_File_write_at_all(MPI_File fh, MPI_Offset offset, const void *buf, int count,
|
||||
MPI_Datatype datatype, MPI_Status *status)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5) ROMIO_API_PUBLIC;
|
||||
|
||||
/* nonblocking calls currently use MPIO_Request, because generalized
|
||||
requests not yet implemented. For the same reason, MPIO_Test and
|
||||
MPIO_Wait are used to test and wait on nonblocking I/O requests */
|
||||
int MPI_File_iread_at(MPI_File fh, MPI_Offset offset, void *buf, int count, MPI_Datatype datatype,
|
||||
MPIO_Request *request) MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5);
|
||||
MPIO_Request *request) MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5) ROMIO_API_PUBLIC;
|
||||
int MPI_File_iwrite_at(MPI_File fh, MPI_Offset offset, const void *buf, int count,
|
||||
MPI_Datatype datatype, MPIO_Request *request)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5) ROMIO_API_PUBLIC;
|
||||
|
||||
/* Section 9.4.3 */
|
||||
int MPI_File_read(MPI_File fh, void *buf, int count, MPI_Datatype datatype, MPI_Status *status)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
int MPI_File_read_all(MPI_File fh, void *buf, int count, MPI_Datatype datatype, MPI_Status *status)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
int MPI_File_write(MPI_File fh, const void *buf, int count, MPI_Datatype datatype,
|
||||
MPI_Status *status) MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
MPI_Status *status) MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
int MPI_File_write_all(MPI_File fh, const void *buf, int count, MPI_Datatype datatype,
|
||||
MPI_Status *status) MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
MPI_Status *status) MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
|
||||
/* nonblocking calls currently use MPIO_Request, because generalized
|
||||
requests not yet implemented. For the same reason, MPIO_Test and
|
||||
MPIO_Wait are used to test and wait on nonblocking I/O requests */
|
||||
|
||||
int MPI_File_iread(MPI_File fh, void *buf, int count, MPI_Datatype datatype, MPIO_Request *request)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
int MPI_File_iwrite(MPI_File fh, const void *buf, int count, MPI_Datatype datatype,
|
||||
MPIO_Request *request) MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
MPIO_Request *request) MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
|
||||
int MPI_File_seek(MPI_File fh, MPI_Offset offset, int whence);
|
||||
int MPI_File_get_position(MPI_File fh, MPI_Offset *offset);
|
||||
int MPI_File_get_byte_offset(MPI_File fh, MPI_Offset offset, MPI_Offset *disp);
|
||||
int MPI_File_seek(MPI_File fh, MPI_Offset offset, int whence) ROMIO_API_PUBLIC;
|
||||
int MPI_File_get_position(MPI_File fh, MPI_Offset *offset) ROMIO_API_PUBLIC;
|
||||
int MPI_File_get_byte_offset(MPI_File fh, MPI_Offset offset, MPI_Offset *disp) ROMIO_API_PUBLIC;
|
||||
|
||||
/* Section 9.4.4 */
|
||||
int MPI_File_read_shared(MPI_File fh, void *buf, int count, MPI_Datatype datatype,
|
||||
MPI_Status *status) MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
MPI_Status *status) MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
int MPI_File_write_shared(MPI_File fh, const void *buf, int count, MPI_Datatype datatype,
|
||||
MPI_Status *status) MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
MPI_Status *status) MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
int MPI_File_iread_shared(MPI_File fh, void *buf, int count, MPI_Datatype datatype,
|
||||
MPIO_Request *request) MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
MPIO_Request *request) MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
int MPI_File_iwrite_shared(MPI_File fh, const void *buf, int count, MPI_Datatype datatype,
|
||||
MPIO_Request *request) MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
MPIO_Request *request) MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
int MPI_File_read_ordered(MPI_File fh, void *buf, int count, MPI_Datatype datatype,
|
||||
MPI_Status *status) MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
MPI_Status *status) MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
int MPI_File_write_ordered(MPI_File fh, const void *buf, int count, MPI_Datatype datatype,
|
||||
MPI_Status *status) MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
int MPI_File_seek_shared(MPI_File fh, MPI_Offset offset, int whence);
|
||||
int MPI_File_get_position_shared(MPI_File fh, MPI_Offset *offset);
|
||||
MPI_Status *status) MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
int MPI_File_seek_shared(MPI_File fh, MPI_Offset offset, int whence) ROMIO_API_PUBLIC;
|
||||
int MPI_File_get_position_shared(MPI_File fh, MPI_Offset *offset) ROMIO_API_PUBLIC;
|
||||
|
||||
/* Section 9.4.5 */
|
||||
int MPI_File_read_at_all_begin(MPI_File fh, MPI_Offset offset, void *buf, int count,
|
||||
MPI_Datatype datatype) MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5);
|
||||
int MPI_File_read_at_all_end(MPI_File fh, void *buf, MPI_Status *status);
|
||||
MPI_Datatype datatype) MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5) ROMIO_API_PUBLIC;
|
||||
int MPI_File_read_at_all_end(MPI_File fh, void *buf, MPI_Status *status) ROMIO_API_PUBLIC;
|
||||
int MPI_File_write_at_all_begin(MPI_File fh, MPI_Offset offset, const void *buf, int count,
|
||||
MPI_Datatype datatype) MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5);
|
||||
int MPI_File_write_at_all_end(MPI_File fh, const void *buf, MPI_Status *status);
|
||||
MPI_Datatype datatype) MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5) ROMIO_API_PUBLIC;
|
||||
int MPI_File_write_at_all_end(MPI_File fh, const void *buf, MPI_Status *status) ROMIO_API_PUBLIC;
|
||||
int MPI_File_read_all_begin(MPI_File fh, void *buf, int count, MPI_Datatype datatype)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
int MPI_File_read_all_end(MPI_File fh, void *buf, MPI_Status *status);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
int MPI_File_read_all_end(MPI_File fh, void *buf, MPI_Status *status) ROMIO_API_PUBLIC;
|
||||
int MPI_File_write_all_begin(MPI_File fh, const void *buf, int count, MPI_Datatype datatype)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
int MPI_File_write_all_end(MPI_File fh, const void *buf, MPI_Status *status);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
int MPI_File_write_all_end(MPI_File fh, const void *buf, MPI_Status *status) ROMIO_API_PUBLIC;
|
||||
int MPI_File_read_ordered_begin(MPI_File fh, void *buf, int count, MPI_Datatype datatype)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
int MPI_File_read_ordered_end(MPI_File fh, void *buf, MPI_Status *status);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
int MPI_File_read_ordered_end(MPI_File fh, void *buf, MPI_Status *status) ROMIO_API_PUBLIC;
|
||||
int MPI_File_write_ordered_begin(MPI_File fh, const void *buf, int count, MPI_Datatype datatype)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
int MPI_File_write_ordered_end(MPI_File fh, const void *buf, MPI_Status *status);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
int MPI_File_write_ordered_end(MPI_File fh, const void *buf, MPI_Status *status) ROMIO_API_PUBLIC;
|
||||
|
||||
/* Section 9.5.1 */
|
||||
int MPI_File_get_type_extent(MPI_File fh, MPI_Datatype datatype, MPI_Aint *extent);
|
||||
int MPI_File_get_type_extent(MPI_File fh, MPI_Datatype datatype, MPI_Aint *extent) ROMIO_API_PUBLIC;
|
||||
|
||||
/* Section 9.5.3 */
|
||||
int MPI_Register_datarep(const char *datarep, MPI_Datarep_conversion_function *read_conversion_fn,
|
||||
MPI_Datarep_conversion_function *write_conversion_fn,
|
||||
MPI_Datarep_extent_function *dtype_file_extent_fn, void *extra_state);
|
||||
MPI_Datarep_extent_function *dtype_file_extent_fn, void *extra_state) ROMIO_API_PUBLIC;
|
||||
|
||||
/* Section 9.6.1 */
|
||||
int MPI_File_set_atomicity(MPI_File fh, int flag);
|
||||
int MPI_File_get_atomicity(MPI_File fh, int *flag);
|
||||
int MPI_File_sync(MPI_File fh);
|
||||
int MPI_File_set_atomicity(MPI_File fh, int flag) ROMIO_API_PUBLIC;
|
||||
int MPI_File_get_atomicity(MPI_File fh, int *flag) ROMIO_API_PUBLIC;
|
||||
int MPI_File_sync(MPI_File fh) ROMIO_API_PUBLIC;
|
||||
|
||||
/* Section 4.13.3 */
|
||||
#ifndef MPICH
|
||||
/* MPICH provides these definitions */
|
||||
int MPI_File_set_errhandler(MPI_File file, MPI_Errhandler errhandler);
|
||||
int MPI_File_get_errhandler(MPI_File file, MPI_Errhandler *errhandler);
|
||||
int MPI_File_set_errhandler(MPI_File file, MPI_Errhandler errhandler) ROMIO_API_PUBLIC;
|
||||
int MPI_File_get_errhandler(MPI_File file, MPI_Errhandler *errhandler) ROMIO_API_PUBLIC;
|
||||
#endif
|
||||
|
||||
/* For MPI 3.1 */
|
||||
int MPI_File_iread_at_all(MPI_File fh, MPI_Offset offset, void *buf, int count,
|
||||
MPI_Datatype datatype, MPI_Request *request)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5) ROMIO_API_PUBLIC;
|
||||
int MPI_File_iwrite_at_all(MPI_File fh, MPI_Offset offset, const void *buf, int count,
|
||||
MPI_Datatype datatype, MPI_Request *request)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5) ROMIO_API_PUBLIC;
|
||||
int MPI_File_iread_all(MPI_File fh, void *buf, int count, MPI_Datatype datatype,
|
||||
MPI_Request *request)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
int MPI_File_iwrite_all(MPI_File fh, const void *buf, int count, MPI_Datatype datatype,
|
||||
MPI_Request *request)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
/* End Prototypes */
|
||||
|
||||
#ifndef HAVE_MPI_DARRAY_SUBARRAY
|
||||
/* Section 4.14.4 */
|
||||
int MPI_Type_create_subarray(int ndims, const int array_of_sizes[], const int array_of_subsizes[],
|
||||
const int array_of_starts[], int order, MPI_Datatype oldtype,
|
||||
MPI_Datatype *newtype);
|
||||
MPI_Datatype *newtype) ROMIO_API_PUBLIC;
|
||||
|
||||
/* Section 4.14.5 */
|
||||
int MPI_Type_create_darray(int size, int rank, int ndims, const int array_of_gsizes[],
|
||||
const int array_of_distribs[], const int array_of_dargs[],
|
||||
const int array_of_psizes, int order, MPI_Datatype oldtype,
|
||||
MPI_Datatype *newtype);
|
||||
MPI_Datatype *newtype) ROMIO_API_PUBLIC;
|
||||
#endif
|
||||
|
||||
/* The globus2 device has to rename MPI_ symbols in order to use the vendor
|
||||
@@ -279,43 +295,43 @@ int MPI_Type_create_darray(int size, int rank, int ndims, const int array_of_gsi
|
||||
#endif
|
||||
#endif
|
||||
/* above needed for some versions of mpi.h in MPICH!! */
|
||||
MPI_File MPI_File_f2c(MPI_Fint file);
|
||||
MPI_Fint MPI_File_c2f(MPI_File file);
|
||||
MPI_File MPI_File_f2c(MPI_Fint file) ROMIO_API_PUBLIC;
|
||||
MPI_Fint MPI_File_c2f(MPI_File file) ROMIO_API_PUBLIC;
|
||||
|
||||
|
||||
#ifndef HAVE_MPI_GREQUEST
|
||||
/* The following functions are required if generalized requests are not
|
||||
available, because in that case, an MPIO_Request object
|
||||
is currently used for nonblocking I/O. */
|
||||
int MPIO_Test(MPIO_Request *request, int *flag, MPI_Status *status);
|
||||
int MPIO_Wait(MPIO_Request *request, MPI_Status *status);
|
||||
int MPIO_Test(MPIO_Request *request, int *flag, MPI_Status *status) ROMIO_API_PUBLIC;
|
||||
int MPIO_Wait(MPIO_Request *request, MPI_Status *status) ROMIO_API_PUBLIC;
|
||||
int MPIO_Testall(int count, MPIO_Request array_of_requests[], int *flag,
|
||||
MPI_Status array_of_statuses[]);
|
||||
int MPIO_Waitall(int count, MPIO_Request array_of_requests[], MPI_Status array_of_statuses[]);
|
||||
MPI_Status array_of_statuses[]) ROMIO_API_PUBLIC;
|
||||
int MPIO_Waitall(int count, MPIO_Request array_of_requests[], MPI_Status array_of_statuses[]) ROMIO_API_PUBLIC;
|
||||
int MPIO_Testany(int count, MPIO_Request array_of_requests[], int *indx, int *flag,
|
||||
MPI_Status *status);
|
||||
int MPIO_Waitany(int count, MPIO_Request array_of_requests[], int *indx, MPI_Status *status);
|
||||
MPI_Status *status) ROMIO_API_PUBLIC;
|
||||
int MPIO_Waitany(int count, MPIO_Request array_of_requests[], int *indx, MPI_Status *status) ROMIO_API_PUBLIC;
|
||||
int MPIO_Waitsome(int incount, MPIO_Request array_of_requests[], int *outcount,
|
||||
int array_of_indices[], MPI_Status array_of_statuses[]);
|
||||
int array_of_indices[], MPI_Status array_of_statuses[]) ROMIO_API_PUBLIC;
|
||||
int MPIO_Testsome(int incount, MPIO_Request array_of_requests[], int *outcount,
|
||||
int array_of_indices[], MPI_Status array_of_statuses[]);
|
||||
int array_of_indices[], MPI_Status array_of_statuses[]) ROMIO_API_PUBLIC;
|
||||
|
||||
MPI_Fint MPIO_Request_c2f(MPIO_Request request);
|
||||
MPIO_Request MPIO_Request_f2c(MPI_Fint request);
|
||||
MPI_Fint MPIO_Request_c2f(MPIO_Request request) ROMIO_API_PUBLIC;
|
||||
MPIO_Request MPIO_Request_f2c(MPI_Fint request) ROMIO_API_PUBLIC;
|
||||
#endif /* HAVE_MPI_GREQUEST */
|
||||
|
||||
/* info functions if not defined in the MPI implementation */
|
||||
#ifndef HAVE_MPI_INFO
|
||||
|
||||
int MPI_Info_create(MPI_Info *info);
|
||||
int MPI_Info_set(MPI_Info info, const char *key, const char *value);
|
||||
int MPI_Info_delete(MPI_Info info, const char *key);
|
||||
int MPI_Info_get(MPI_Info info, const char *key, int valuelen, char *value, int *flag);
|
||||
int MPI_Info_get_valuelen(MPI_Info info, const char *key, int *valuelen, int *flag);
|
||||
int MPI_Info_get_nkeys(MPI_Info info, int *nkeys);
|
||||
int MPI_Info_get_nthkey(MPI_Info info, int n, char *key);
|
||||
int MPI_Info_dup(MPI_Info info, MPI_Info *newinfo);
|
||||
int MPI_Info_free(MPI_Info *info);
|
||||
int MPI_Info_create(MPI_Info *info) ROMIO_API_PUBLIC;
|
||||
int MPI_Info_set(MPI_Info info, const char *key, const char *value) ROMIO_API_PUBLIC;
|
||||
int MPI_Info_delete(MPI_Info info, const char *key) ROMIO_API_PUBLIC;
|
||||
int MPI_Info_get(MPI_Info info, const char *key, int valuelen, char *value, int *flag) ROMIO_API_PUBLIC;
|
||||
int MPI_Info_get_valuelen(MPI_Info info, const char *key, int *valuelen, int *flag) ROMIO_API_PUBLIC;
|
||||
int MPI_Info_get_nkeys(MPI_Info info, int *nkeys) ROMIO_API_PUBLIC;
|
||||
int MPI_Info_get_nthkey(MPI_Info info, int n, char *key) ROMIO_API_PUBLIC;
|
||||
int MPI_Info_dup(MPI_Info info, MPI_Info *newinfo) ROMIO_API_PUBLIC;
|
||||
int MPI_Info_free(MPI_Info *info) ROMIO_API_PUBLIC;
|
||||
|
||||
/* The globus2 device has to rename MPI_ symbols in order to use the vendor
|
||||
MPI as one of its transport mechanisms. Therefore, the following undefines
|
||||
@@ -329,8 +345,8 @@ int MPI_Info_free(MPI_Info *info);
|
||||
#endif
|
||||
#endif
|
||||
/* above needed for some versions of mpi.h in MPICH!! */
|
||||
MPI_Fint MPI_Info_c2f(MPI_Info info);
|
||||
MPI_Info MPI_Info_f2c(MPI_Fint info);
|
||||
MPI_Fint MPI_Info_c2f(MPI_Info info) ROMIO_API_PUBLIC;
|
||||
MPI_Info MPI_Info_f2c(MPI_Fint info) ROMIO_API_PUBLIC;
|
||||
#endif
|
||||
|
||||
#endif /* HAVE_PRAGMA_HP_SEC_DEF */
|
||||
@@ -340,36 +356,36 @@ MPI_Info MPI_Info_f2c(MPI_Fint info);
|
||||
|
||||
|
||||
/* Section 9.2 */
|
||||
int PMPI_File_open(MPI_Comm, const char *, int, MPI_Info, MPI_File *);
|
||||
int PMPI_File_close(MPI_File *);
|
||||
int PMPI_File_delete(const char *, MPI_Info);
|
||||
int PMPI_File_set_size(MPI_File, MPI_Offset);
|
||||
int PMPI_File_preallocate(MPI_File, MPI_Offset);
|
||||
int PMPI_File_get_size(MPI_File, MPI_Offset *);
|
||||
int PMPI_File_get_group(MPI_File, MPI_Group *);
|
||||
int PMPI_File_get_amode(MPI_File, int *);
|
||||
int PMPI_File_set_info(MPI_File, MPI_Info);
|
||||
int PMPI_File_get_info(MPI_File, MPI_Info *);
|
||||
int PMPI_File_open(MPI_Comm, const char *, int, MPI_Info, MPI_File *) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_close(MPI_File *) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_delete(const char *, MPI_Info) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_set_size(MPI_File, MPI_Offset) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_preallocate(MPI_File, MPI_Offset) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_get_size(MPI_File, MPI_Offset *) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_get_group(MPI_File, MPI_Group *) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_get_amode(MPI_File, int *) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_set_info(MPI_File, MPI_Info) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_get_info(MPI_File, MPI_Info *) ROMIO_API_PUBLIC;
|
||||
|
||||
/* Section 9.3 */
|
||||
int PMPI_File_set_view(MPI_File, MPI_Offset,
|
||||
MPI_Datatype, MPI_Datatype, const char *, MPI_Info);
|
||||
MPI_Datatype, MPI_Datatype, const char *, MPI_Info) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_get_view(MPI_File, MPI_Offset *,
|
||||
MPI_Datatype *, MPI_Datatype *, char *);
|
||||
MPI_Datatype *, MPI_Datatype *, char *) ROMIO_API_PUBLIC;
|
||||
|
||||
/* Section 9.4.2 */
|
||||
int PMPI_File_read_at(MPI_File, MPI_Offset, void *,
|
||||
int, MPI_Datatype, MPI_Status *)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_read_at_all(MPI_File, MPI_Offset, void *,
|
||||
int, MPI_Datatype, MPI_Status *)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_write_at(MPI_File, MPI_Offset, const void *,
|
||||
int, MPI_Datatype, MPI_Status *)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_write_at_all(MPI_File, MPI_Offset, const void *,
|
||||
int, MPI_Datatype, MPI_Status *)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5) ROMIO_API_PUBLIC;
|
||||
|
||||
/* nonblocking calls currently use MPIO_Request, because generalized
|
||||
requests not yet implemented. For the same reason, MPIO_Test and
|
||||
@@ -377,155 +393,155 @@ int PMPI_File_write_at_all(MPI_File, MPI_Offset, const void *,
|
||||
|
||||
int PMPI_File_iread_at(MPI_File, MPI_Offset, void *,
|
||||
int, MPI_Datatype, MPIO_Request *)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_iwrite_at(MPI_File, MPI_Offset, const void *,
|
||||
int, MPI_Datatype, MPIO_Request *)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5) ROMIO_API_PUBLIC;
|
||||
|
||||
/* Section 9.4.3 */
|
||||
int PMPI_File_read(MPI_File, void *, int, MPI_Datatype, MPI_Status *)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_read_all(MPI_File, void *, int, MPI_Datatype, MPI_Status *)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_write(MPI_File, const void *, int, MPI_Datatype, MPI_Status *)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_write_all(MPI_File, const void *, int, MPI_Datatype, MPI_Status *)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
|
||||
/* nonblocking calls currently use MPIO_Request, because generalized
|
||||
requests not yet implemented. For the same reason, MPIO_Test and
|
||||
MPIO_Wait are used to test and wait on nonblocking I/O requests */
|
||||
|
||||
int PMPI_File_iread(MPI_File, void *, int, MPI_Datatype, MPIO_Request *)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_iwrite(MPI_File, const void *, int, MPI_Datatype, MPIO_Request *)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
|
||||
int PMPI_File_seek(MPI_File, MPI_Offset, int);
|
||||
int PMPI_File_get_position(MPI_File, MPI_Offset *);
|
||||
int PMPI_File_get_byte_offset(MPI_File, MPI_Offset, MPI_Offset *);
|
||||
int PMPI_File_seek(MPI_File, MPI_Offset, int) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_get_position(MPI_File, MPI_Offset *) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_get_byte_offset(MPI_File, MPI_Offset, MPI_Offset *) ROMIO_API_PUBLIC;
|
||||
|
||||
/* Section 9.4.4 */
|
||||
int PMPI_File_read_shared(MPI_File, void *, int, MPI_Datatype, MPI_Status *)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_write_shared(MPI_File, const void *, int, MPI_Datatype, MPI_Status *)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_iread_shared(MPI_File, void *, int,
|
||||
MPI_Datatype, MPIO_Request *)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_iwrite_shared(MPI_File, const void *, int,
|
||||
MPI_Datatype, MPIO_Request *)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_read_ordered(MPI_File, void *, int, MPI_Datatype, MPI_Status *)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_write_ordered(MPI_File, const void *, int, MPI_Datatype, MPI_Status *)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
int PMPI_File_seek_shared(MPI_File, MPI_Offset, int);
|
||||
int PMPI_File_get_position_shared(MPI_File, MPI_Offset *);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_seek_shared(MPI_File, MPI_Offset, int) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_get_position_shared(MPI_File, MPI_Offset *) ROMIO_API_PUBLIC;
|
||||
|
||||
/* Section 9.4.5 */
|
||||
int PMPI_File_read_at_all_begin(MPI_File, MPI_Offset, void *,
|
||||
int, MPI_Datatype)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5);
|
||||
int PMPI_File_read_at_all_end(MPI_File, void *, MPI_Status *);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_read_at_all_end(MPI_File, void *, MPI_Status *) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_write_at_all_begin(MPI_File, MPI_Offset, const void *,
|
||||
int, MPI_Datatype)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5);
|
||||
int PMPI_File_write_at_all_end(MPI_File, const void *, MPI_Status *);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_write_at_all_end(MPI_File, const void *, MPI_Status *) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_read_all_begin(MPI_File, void *, int, MPI_Datatype)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
int PMPI_File_read_all_end(MPI_File, void *, MPI_Status *);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_read_all_end(MPI_File, void *, MPI_Status *) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_write_all_begin(MPI_File, const void *, int, MPI_Datatype)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
int PMPI_File_write_all_end(MPI_File, const void *, MPI_Status *);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_write_all_end(MPI_File, const void *, MPI_Status *) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_read_ordered_begin(MPI_File, void *, int, MPI_Datatype)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
int PMPI_File_read_ordered_end(MPI_File, void *, MPI_Status *);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_read_ordered_end(MPI_File, void *, MPI_Status *) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_write_ordered_begin(MPI_File, const void *, int, MPI_Datatype)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
int PMPI_File_write_ordered_end(MPI_File, const void *, MPI_Status *);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_write_ordered_end(MPI_File, const void *, MPI_Status *) ROMIO_API_PUBLIC;
|
||||
|
||||
/* Section 9.5.1 */
|
||||
int PMPI_File_get_type_extent(MPI_File, MPI_Datatype, MPI_Aint *);
|
||||
int PMPI_File_get_type_extent(MPI_File, MPI_Datatype, MPI_Aint *) ROMIO_API_PUBLIC;
|
||||
|
||||
/* Section 9.5.3 */
|
||||
int PMPI_Register_datarep(const char *,
|
||||
MPI_Datarep_conversion_function *,
|
||||
MPI_Datarep_conversion_function *,
|
||||
MPI_Datarep_extent_function *,
|
||||
void *);
|
||||
void *) ROMIO_API_PUBLIC;
|
||||
|
||||
/* Section 9.6.1 */
|
||||
int PMPI_File_set_atomicity(MPI_File, int);
|
||||
int PMPI_File_get_atomicity(MPI_File, int *);
|
||||
int PMPI_File_sync(MPI_File);
|
||||
int PMPI_File_set_atomicity(MPI_File, int) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_get_atomicity(MPI_File, int *) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_sync(MPI_File) ROMIO_API_PUBLIC;
|
||||
|
||||
/* Section 4.13.3 */
|
||||
#ifndef MPICH
|
||||
/* MPICH provides these definitions */
|
||||
int PMPI_File_set_errhandler( MPI_File, MPI_Errhandler );
|
||||
int PMPI_File_get_errhandler( MPI_File, MPI_Errhandler * );
|
||||
int PMPI_File_set_errhandler( MPI_File, MPI_Errhandler ) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_get_errhandler( MPI_File, MPI_Errhandler * ) ROMIO_API_PUBLIC;
|
||||
#endif
|
||||
|
||||
/* For MPI 3.1 */
|
||||
int PMPI_File_iread_at_all(MPI_File fh, MPI_Offset offset, void *buf, int count,
|
||||
MPI_Datatype datatype, MPI_Request *request)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_iwrite_at_all(MPI_File fh, MPI_Offset offset, const void *buf, int count,
|
||||
MPI_Datatype datatype, MPI_Request *request)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_iread_all(MPI_File fh, void *buf, int count, MPI_Datatype datatype,
|
||||
MPI_Request *request)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
int PMPI_File_iwrite_all(MPI_File fh, const void *buf, int count, MPI_Datatype datatype,
|
||||
MPI_Request *request)
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
|
||||
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4) ROMIO_API_PUBLIC;
|
||||
|
||||
#ifndef HAVE_MPI_DARRAY_SUBARRAY
|
||||
/* Section 4.14.4 */
|
||||
int PMPI_Type_create_subarray(int, int *, int *, int *, int,
|
||||
MPI_Datatype, MPI_Datatype *);
|
||||
MPI_Datatype, MPI_Datatype *) ROMIO_API_PUBLIC;
|
||||
|
||||
/* Section 4.14.5 */
|
||||
int PMPI_Type_create_darray(int, int, int, int *, int *,
|
||||
int *, int *, int, MPI_Datatype, MPI_Datatype *);
|
||||
int *, int *, int, MPI_Datatype, MPI_Datatype *) ROMIO_API_PUBLIC;
|
||||
#endif
|
||||
|
||||
/* Section 4.12.4 */
|
||||
MPI_File PMPI_File_f2c(MPI_Fint);
|
||||
MPI_Fint PMPI_File_c2f(MPI_File);
|
||||
MPI_File PMPI_File_f2c(MPI_Fint) ROMIO_API_PUBLIC;
|
||||
MPI_Fint PMPI_File_c2f(MPI_File) ROMIO_API_PUBLIC;
|
||||
|
||||
#ifndef HAVE_MPI_GREQUEST
|
||||
/* The following functions are required if generalized requests are not
|
||||
available, because in that case, an MPIO_Request object
|
||||
is currently used for nonblocking I/O. */
|
||||
int PMPIO_Test(MPIO_Request *, int *, MPI_Status *);
|
||||
int PMPIO_Wait(MPIO_Request *, MPI_Status *);
|
||||
int PMPIO_Testall(int, MPIO_Request *, int *, MPI_Status *);
|
||||
int PMPIO_Waitall(int, MPIO_Request *, MPI_Status *);
|
||||
int PMPIO_Testany(int, MPIO_Request *, int *, int *, MPI_Status *);
|
||||
int PMPIO_Waitany(int, MPIO_Request *, int *, MPI_Status *);
|
||||
int PMPIO_Waitsome(int, MPIO_Request *, int *, int *, MPI_Status *);
|
||||
int PMPIO_Testsome(int, MPIO_Request *, int *, int *, MPI_Status *);
|
||||
MPI_Fint PMPIO_Request_c2f(MPIO_Request);
|
||||
MPIO_Request PMPIO_Request_f2c(MPI_Fint);
|
||||
int PMPIO_Test(MPIO_Request *, int *, MPI_Status *) ROMIO_API_PUBLIC;
|
||||
int PMPIO_Wait(MPIO_Request *, MPI_Status *) ROMIO_API_PUBLIC;
|
||||
int PMPIO_Testall(int, MPIO_Request *, int *, MPI_Status *) ROMIO_API_PUBLIC;
|
||||
int PMPIO_Waitall(int, MPIO_Request *, MPI_Status *) ROMIO_API_PUBLIC;
|
||||
int PMPIO_Testany(int, MPIO_Request *, int *, int *, MPI_Status *) ROMIO_API_PUBLIC;
|
||||
int PMPIO_Waitany(int, MPIO_Request *, int *, MPI_Status *) ROMIO_API_PUBLIC;
|
||||
int PMPIO_Waitsome(int, MPIO_Request *, int *, int *, MPI_Status *) ROMIO_API_PUBLIC;
|
||||
int PMPIO_Testsome(int, MPIO_Request *, int *, int *, MPI_Status *) ROMIO_API_PUBLIC;
|
||||
MPI_Fint PMPIO_Request_c2f(MPIO_Request) ROMIO_API_PUBLIC;
|
||||
MPIO_Request PMPIO_Request_f2c(MPI_Fint) ROMIO_API_PUBLIC;
|
||||
#endif /* HAVE_MPI_GREQUEST */
|
||||
|
||||
/* info functions if not defined in the MPI implementation */
|
||||
#ifndef HAVE_MPI_INFO
|
||||
|
||||
int PMPI_Info_create(MPI_Info *);
|
||||
int PMPI_Info_set(MPI_Info, char *, char *);
|
||||
int PMPI_Info_delete(MPI_Info, char *);
|
||||
int PMPI_Info_get(MPI_Info, char *, int, char *, int *);
|
||||
int PMPI_Info_get_valuelen(MPI_Info, char *, int *, int *);
|
||||
int PMPI_Info_get_nkeys(MPI_Info, int *);
|
||||
int PMPI_Info_get_nthkey(MPI_Info, int, char *);
|
||||
int PMPI_Info_dup(MPI_Info, MPI_Info *);
|
||||
int PMPI_Info_free(MPI_Info *);
|
||||
int PMPI_Info_create(MPI_Info *) ROMIO_API_PUBLIC;
|
||||
int PMPI_Info_set(MPI_Info, char *, char *) ROMIO_API_PUBLIC;
|
||||
int PMPI_Info_delete(MPI_Info, char *) ROMIO_API_PUBLIC;
|
||||
int PMPI_Info_get(MPI_Info, char *, int, char *, int *) ROMIO_API_PUBLIC;
|
||||
int PMPI_Info_get_valuelen(MPI_Info, char *, int *, int *) ROMIO_API_PUBLIC;
|
||||
int PMPI_Info_get_nkeys(MPI_Info, int *) ROMIO_API_PUBLIC;
|
||||
int PMPI_Info_get_nthkey(MPI_Info, int, char *) ROMIO_API_PUBLIC;
|
||||
int PMPI_Info_dup(MPI_Info, MPI_Info *) ROMIO_API_PUBLIC;
|
||||
int PMPI_Info_free(MPI_Info *) ROMIO_API_PUBLIC;
|
||||
|
||||
MPI_Fint PMPI_Info_c2f(MPI_Info);
|
||||
MPI_Info PMPI_Info_f2c(MPI_Fint);
|
||||
MPI_Fint PMPI_Info_c2f(MPI_Info) ROMIO_API_PUBLIC;
|
||||
MPI_Info PMPI_Info_f2c(MPI_Fint) ROMIO_API_PUBLIC;
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
|
||||
@@ -1,241 +0,0 @@
|
||||
#ifndef _SRC_OPA_CONFIG_H
|
||||
#define _SRC_OPA_CONFIG_H 1
|
||||
|
||||
/* src/opa_config.h. Generated automatically at end of configure. */
|
||||
/* src/config.h. Generated from config.h.in by configure. */
|
||||
/* src/config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
|
||||
/*
|
||||
* (C) 2008 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
|
||||
|
||||
/* define if lock-based emulation was explicitly requested at configure time
|
||||
via --with-atomic-primitives=no */
|
||||
/* #undef EXPLICIT_EMULATION */
|
||||
|
||||
/* Define to 1 if you have the <atomic.h> header file. */
|
||||
/* #undef HAVE_ATOMIC_H */
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#ifndef OPA_HAVE_DLFCN_H
|
||||
#define OPA_HAVE_DLFCN_H 1
|
||||
#endif
|
||||
|
||||
/* define to 1 if we have support for gcc ARM atomics */
|
||||
/* #undef HAVE_GCC_AND_ARM_ASM */
|
||||
|
||||
/* define to 1 if we have support for gcc ia64 primitives */
|
||||
/* #undef HAVE_GCC_AND_IA64_ASM */
|
||||
|
||||
/* define to 1 if we have support for gcc PowerPC atomics */
|
||||
/* #undef HAVE_GCC_AND_POWERPC_ASM */
|
||||
|
||||
/* define to 1 if we have support for gcc SiCortex atomics */
|
||||
/* #undef HAVE_GCC_AND_SICORTEX_ASM */
|
||||
|
||||
/* Define if GNU __attribute__ is supported */
|
||||
#ifndef OPA_HAVE_GCC_ATTRIBUTE
|
||||
#define OPA_HAVE_GCC_ATTRIBUTE 1
|
||||
#endif
|
||||
|
||||
/* define to 1 if we have support for gcc atomic intrinsics */
|
||||
#ifndef OPA_HAVE_GCC_INTRINSIC_ATOMICS
|
||||
#define OPA_HAVE_GCC_INTRINSIC_ATOMICS 1
|
||||
#endif
|
||||
|
||||
/* define to 1 if we have support for gcc x86/x86_64 primitives */
|
||||
#ifndef OPA_HAVE_GCC_X86_32_64
|
||||
#define OPA_HAVE_GCC_X86_32_64 1
|
||||
#endif
|
||||
|
||||
/* define to 1 if we have support for gcc x86 primitives for pre-Pentium 4 */
|
||||
#ifndef OPA_HAVE_GCC_X86_32_64_P3
|
||||
#define OPA_HAVE_GCC_X86_32_64_P3 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the <intrin.h> header file. */
|
||||
/* #undef HAVE_INTRIN_H */
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#ifndef OPA_HAVE_INTTYPES_H
|
||||
#define OPA_HAVE_INTTYPES_H 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the `pthread' library (-lpthread). */
|
||||
#ifndef OPA_HAVE_LIBPTHREAD
|
||||
#define OPA_HAVE_LIBPTHREAD 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#ifndef OPA_HAVE_MEMORY_H
|
||||
#define OPA_HAVE_MEMORY_H 1
|
||||
#endif
|
||||
|
||||
/* define to 1 if we have support for Windows NT atomic intrinsics */
|
||||
/* #undef HAVE_NT_INTRINSICS */
|
||||
|
||||
/* Define to 1 if you have the <pthread.h> header file. */
|
||||
#ifndef OPA_HAVE_PTHREAD_H
|
||||
#define OPA_HAVE_PTHREAD_H 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the `pthread_yield' function. */
|
||||
#ifndef OPA_HAVE_PTHREAD_YIELD
|
||||
#define OPA_HAVE_PTHREAD_YIELD 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the `sched_yield' function. */
|
||||
/* #undef HAVE_SCHED_YIELD */
|
||||
|
||||
/* Define to 1 if you have the <stddef.h> header file. */
|
||||
#ifndef OPA_HAVE_STDDEF_H
|
||||
#define OPA_HAVE_STDDEF_H 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#ifndef OPA_HAVE_STDINT_H
|
||||
#define OPA_HAVE_STDINT_H 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#ifndef OPA_HAVE_STDLIB_H
|
||||
#define OPA_HAVE_STDLIB_H 1
|
||||
#endif
|
||||
|
||||
/* Define if strict checking of atomic operation fairness is desired */
|
||||
/* #undef HAVE_STRICT_FAIRNESS_CHECKS */
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#ifndef OPA_HAVE_STRINGS_H
|
||||
#define OPA_HAVE_STRINGS_H 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#ifndef OPA_HAVE_STRING_H
|
||||
#define OPA_HAVE_STRING_H 1
|
||||
#endif
|
||||
|
||||
/* define to 1 if we have support for Sun atomic operations library */
|
||||
/* #undef HAVE_SUN_ATOMIC_OPS */
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#ifndef OPA_HAVE_SYS_STAT_H
|
||||
#define OPA_HAVE_SYS_STAT_H 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#ifndef OPA_HAVE_SYS_TYPES_H
|
||||
#define OPA_HAVE_SYS_TYPES_H 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#ifndef OPA_HAVE_UNISTD_H
|
||||
#define OPA_HAVE_UNISTD_H 1
|
||||
#endif
|
||||
|
||||
/* Define to the sub-directory where libtool stores uninstalled libraries. */
|
||||
#ifndef OPA_LT_OBJDIR
|
||||
#define OPA_LT_OBJDIR ".libs/"
|
||||
#endif
|
||||
|
||||
/* define to the maximum number of simultaneous threads */
|
||||
#ifndef OPA_MAX_NTHREADS
|
||||
#define OPA_MAX_NTHREADS 100
|
||||
#endif
|
||||
|
||||
/* Define to 1 if assertions should be disabled. */
|
||||
/* #undef NDEBUG */
|
||||
|
||||
/* Name of package */
|
||||
#ifndef OPA_PACKAGE
|
||||
#define OPA_PACKAGE "openpa"
|
||||
#endif
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#ifndef OPA_PACKAGE_BUGREPORT
|
||||
#define OPA_PACKAGE_BUGREPORT "https://trac.mcs.anl.gov/projects/openpa/newticket"
|
||||
#endif
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#ifndef OPA_PACKAGE_NAME
|
||||
#define OPA_PACKAGE_NAME "OpenPA"
|
||||
#endif
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#ifndef OPA_PACKAGE_STRING
|
||||
#define OPA_PACKAGE_STRING "OpenPA 1.0.3"
|
||||
#endif
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#ifndef OPA_PACKAGE_TARNAME
|
||||
#define OPA_PACKAGE_TARNAME "openpa"
|
||||
#endif
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#ifndef OPA_PACKAGE_URL
|
||||
#define OPA_PACKAGE_URL ""
|
||||
#endif
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#ifndef OPA_PACKAGE_VERSION
|
||||
#define OPA_PACKAGE_VERSION "1.0.3"
|
||||
#endif
|
||||
|
||||
/* The size of `int', as computed by sizeof. */
|
||||
#ifndef OPA_SIZEOF_INT
|
||||
#define OPA_SIZEOF_INT 4
|
||||
#endif
|
||||
|
||||
/* The size of `void *', as computed by sizeof. */
|
||||
#ifndef OPA_SIZEOF_VOID_P
|
||||
#define OPA_SIZEOF_VOID_P 8
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#ifndef OPA_STDC_HEADERS
|
||||
#define OPA_STDC_HEADERS 1
|
||||
#endif
|
||||
|
||||
/* define to 1 to force using lock-based atomic primitives */
|
||||
/* #undef USE_LOCK_BASED_PRIMITIVES */
|
||||
|
||||
/* define to 1 if unsafe (non-atomic) primitives should be used */
|
||||
/* #undef USE_UNSAFE_PRIMITIVES */
|
||||
|
||||
/* Version number of package */
|
||||
#ifndef OPA_VERSION
|
||||
#define OPA_VERSION "1.0.3"
|
||||
#endif
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
/* #undef const */
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
/* #undef inline */
|
||||
#endif
|
||||
|
||||
/* Define to the equivalent of the C99 'restrict' keyword, or to
|
||||
nothing if this is not supported. Do not define if restrict is
|
||||
supported directly. */
|
||||
#ifndef _opa_restrict
|
||||
#define _opa_restrict __restrict
|
||||
#endif
|
||||
/* Work around a bug in Sun C++: it does not support _Restrict or
|
||||
__restrict__, even though the corresponding Sun C compiler ends up with
|
||||
"#define restrict _Restrict" or "#define restrict __restrict__" in the
|
||||
previous line. Perhaps some future version of Sun C++ will work with
|
||||
restrict; if so, hopefully it defines __RESTRICT like Sun C does. */
|
||||
#if defined __SUNPRO_CC && !defined __RESTRICT
|
||||
# define _Restrict
|
||||
# define __restrict__
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* once: _SRC_OPA_CONFIG_H */
|
||||
#endif
|
||||
@@ -1,160 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
|
||||
/*
|
||||
* (C) 2008 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef OPA_PRIMITIVES_H_INCLUDED
|
||||
#define OPA_PRIMITIVES_H_INCLUDED
|
||||
|
||||
#include "opa_config.h"
|
||||
#include "opa_util.h"
|
||||
|
||||
/* Clean up some of the opa_config.h definitions. This is a consequence
|
||||
of using the AX_PREFIX_CONFIG_H macro. Autoconf won't define inline
|
||||
or _opa_inline when a real "inline" works. Since we are
|
||||
unconditionally using _opa_inline we must define it ourselves in this
|
||||
case. */
|
||||
#ifndef _opa_inline
|
||||
#define _opa_inline inline
|
||||
#endif
|
||||
#ifndef _opa_restrict
|
||||
#define _opa_restrict restrict
|
||||
#endif
|
||||
#ifndef _opa_const
|
||||
#define _opa_const const
|
||||
#endif
|
||||
|
||||
/*
|
||||
Primitive atomic functions
|
||||
--------------------------
|
||||
|
||||
The included file is responsible for defining the types of OPA_int_t and
|
||||
OPA_ptr_t as well as a set of functions for operating on these
|
||||
types. If you have the following declaration:
|
||||
|
||||
OPA_int_t atomic_var;
|
||||
|
||||
Then in order for the emulation functions to compile, the underlying value of
|
||||
atomic_var should be accessible via:
|
||||
|
||||
atomic_var.v;
|
||||
|
||||
The same goes for OPA_ptr_t.
|
||||
|
||||
The atomic functions that must be ported for each architecture:
|
||||
|
||||
static _opa_inline int OPA_load_int(_opa_const OPA_int_t *ptr);
|
||||
static _opa_inline void OPA_store_int(OPA_int_t *ptr, int val);
|
||||
static _opa_inline void *OPA_load_ptr(_opa_const OPA_ptr_t *ptr);
|
||||
static _opa_inline void OPA_store_ptr(OPA_ptr_t *ptr, void *val);
|
||||
|
||||
static _opa_inline void OPA_add_int(OPA_int_t *ptr, int val);
|
||||
static _opa_inline void OPA_incr_int(OPA_int_t *ptr);
|
||||
static _opa_inline void OPA_decr_int(OPA_int_t *ptr);
|
||||
|
||||
static _opa_inline int OPA_decr_and_test_int(OPA_int_t *ptr);
|
||||
static _opa_inline int OPA_fetch_and_add_int(OPA_int_t *ptr, int val);
|
||||
static _opa_inline int OPA_fetch_and_incr_int(OPA_int_t *ptr);
|
||||
static _opa_inline int OPA_fetch_and_decr_int(OPA_int_t *ptr);
|
||||
|
||||
static _opa_inline void *OPA_cas_ptr(OPA_ptr_t *ptr, void *oldv, void *newv);
|
||||
static _opa_inline int OPA_cas_int(OPA_int_t *ptr, int oldv, int newv);
|
||||
|
||||
static _opa_inline void *OPA_swap_ptr(OPA_ptr_t *ptr, void *val);
|
||||
static _opa_inline int OPA_swap_int(OPA_int_t *ptr, int val);
|
||||
|
||||
// (the memory barriers may be macros instead of inline functions)
|
||||
static _opa_inline void OPA_write_barrier();
|
||||
static _opa_inline void OPA_read_barrier();
|
||||
static _opa_inline void OPA_read_write_barrier();
|
||||
|
||||
// Loads and stores with memory ordering guarantees (also may be macros):
|
||||
static _opa_inline int OPA_load_acquire_int(_opa_const OPA_int_t *ptr);
|
||||
static _opa_inline void OPA_store_release_int(OPA_int_t *ptr, int val);
|
||||
static _opa_inline void *OPA_load_acquire_ptr(_opa_const OPA_ptr_t *ptr);
|
||||
static _opa_inline void OPA_store_release_ptr(OPA_ptr_t *ptr, void *val);
|
||||
|
||||
// Compiler barrier, only preventing compiler reordering, *not* CPU
|
||||
// reordering (may be a macro):
|
||||
static _opa_inline void OPA_compiler_barrier();
|
||||
|
||||
// The following need to be ported only for architectures supporting LL/SC:
|
||||
static _opa_inline int OPA_LL_int(OPA_int_t *ptr);
|
||||
static _opa_inline int OPA_SC_int(OPA_int_t *ptr, int val);
|
||||
static _opa_inline void *OPA_LL_ptr(OPA_ptr_t *ptr);
|
||||
static _opa_inline int OPA_SC_ptr(OPA_ptr_t *ptr, void *val);
|
||||
|
||||
// Additionally, the following initializer macros must be defined:
|
||||
#define OPA_INT_T_INITIALIZER(val_) ...
|
||||
#define OPA_PTR_T_INITIALIZER(val_) ...
|
||||
|
||||
// They should be useable as C89 static initializers like so:
|
||||
|
||||
struct { int x; OPA_int_t y; OPA_ptr_t z; } foo = { 35, OPA_INT_T_INITIALIZER(1), OPA_PTR_T_INITIALIZER(NULL) };
|
||||
*/
|
||||
|
||||
/* Include the appropriate header for the architecture */
|
||||
#if defined(OPA_USE_UNSAFE_PRIMITIVES)
|
||||
/* comes first to permit user overrides in the style of NDEBUG */
|
||||
#include "primitives/opa_unsafe.h"
|
||||
#elif defined(OPA_HAVE_GCC_AND_POWERPC_ASM)
|
||||
#include "primitives/opa_gcc_ppc.h"
|
||||
#elif defined(OPA_HAVE_GCC_AND_ARM_ASM)
|
||||
#include "primitives/opa_gcc_arm.h"
|
||||
#elif defined(OPA_HAVE_GCC_X86_32_64)
|
||||
#include "primitives/opa_gcc_intel_32_64.h"
|
||||
#elif defined(OPA_HAVE_GCC_X86_32_64_P3)
|
||||
#include "primitives/opa_gcc_intel_32_64_p3.h"
|
||||
#elif defined(OPA_HAVE_GCC_AND_IA64_ASM)
|
||||
#include "primitives/opa_gcc_ia64.h"
|
||||
#elif defined(OPA_HAVE_GCC_AND_SICORTEX_ASM)
|
||||
#include "primitives/opa_gcc_sicortex.h"
|
||||
#elif defined(OPA_HAVE_GCC_INTRINSIC_ATOMICS)
|
||||
#include "primitives/opa_gcc_intrinsics.h"
|
||||
#elif defined(OPA_HAVE_SUN_ATOMIC_OPS)
|
||||
#include "primitives/opa_sun_atomic_ops.h"
|
||||
#elif defined(OPA_HAVE_NT_INTRINSICS)
|
||||
#include "primitives/opa_nt_intrinsics.h"
|
||||
#elif defined(OPA_USE_LOCK_BASED_PRIMITIVES)
|
||||
#include "primitives/opa_by_lock.h"
|
||||
#else
|
||||
#error no primitives implementation specified
|
||||
#endif
|
||||
|
||||
/*
|
||||
This routine is needed because the MPIU_THREAD_XXX_CS_{ENTER,EXIT} macros do
|
||||
not provide synchronization across multiple processes, only across multiple
|
||||
threads within a process. In order to safely emulate atomic operations on a
|
||||
shared memory region, we need a shared memory backed lock mechanism.
|
||||
|
||||
This routine must be called by any subsystem that intends to use the atomic
|
||||
abstractions if the cpp directive OPA_USE_LOCK_BASED_PRIMITIVES is defined. It must
|
||||
be called exactly once by _all_ processes, not just a single leader. This
|
||||
function will initialize the contents of the lock variable if the caller
|
||||
specifies (isLeader==true). Note that multiple initialization is forbidden
|
||||
by several lock implementations, especially pthreads.
|
||||
|
||||
Inputs:
|
||||
shm_lock - A pointer to an allocated piece of shared memory that can hold
|
||||
a mutex (e.g., pthread_mutex_t). This is not portable to
|
||||
non-pthreads systems at this time.
|
||||
isLeader - This boolean value should be set to true for exactly one
|
||||
thread/process of the group that calls this function.
|
||||
*/
|
||||
#if defined(OPA_HAVE_PTHREAD_H)
|
||||
# include <pthread.h>
|
||||
typedef pthread_mutex_t OPA_emulation_ipl_t;
|
||||
int OPA_Interprocess_lock_init(OPA_emulation_ipl_t *shm_lock, int isLeader);
|
||||
#endif
|
||||
|
||||
|
||||
/* FIXME This should probably be pushed down into the platform-specific headers. */
|
||||
#if defined(OPA_HAVE_SCHED_YIELD)
|
||||
# include <sched.h>
|
||||
# define OPA_busy_wait() sched_yield()
|
||||
#else
|
||||
# define OPA_busy_wait() do { } while (0)
|
||||
#endif
|
||||
|
||||
#endif /* defined(OPA_PRIMITIVES_H_INCLUDED) */
|
||||
@@ -1,286 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
|
||||
/*
|
||||
* (C) 2008 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
|
||||
/* Implements a fast, lockfree, multi-producer, single-consumer queue. It's
|
||||
* important to note the *single-consumer* piece of this, since multithreaded
|
||||
* consumption will surely lead to data corruption and/or other problems. */
|
||||
|
||||
#ifndef OPA_QUEUE_H_INCLUDED
|
||||
#define OPA_QUEUE_H_INCLUDED
|
||||
|
||||
#include "opa_primitives.h"
|
||||
#ifdef OPA_HAVE_STDDEF_H
|
||||
#include <stddef.h>
|
||||
#endif /* OPA_HAVE_STDDEF_H */
|
||||
|
||||
/* This value is used to indicate NULL in the OPA_Shm_asymm_base_addr
|
||||
variable. It is non-zero because one of the likely base addresses is zero
|
||||
(indicating memory is actually symmetrically mapped). The value 64 was used
|
||||
because it is unlikely that mmap will choose an address this low for a
|
||||
mapping. */
|
||||
/* XXX DJG TODO put some conditionally compiled error checking in that uses this */
|
||||
#define OPA_SHM_ASYMM_NULL_VAL 64
|
||||
|
||||
extern char *OPA_Shm_asymm_base_addr;
|
||||
|
||||
/* Used to initialize the base address for relative pointers. This interface
|
||||
assumes that there is only one shared memory segment. If this turns out to
|
||||
not be the case in the future, we should probably add support for multiple
|
||||
shm segments.
|
||||
|
||||
This function will return an error if it has already been called. */
|
||||
int OPA_Shm_asymm_init(char *base);
|
||||
|
||||
/* Relative addressing macros. These are for manipulating addresses relative
|
||||
to the start of a shared memory region. */
|
||||
#define OPA_SHM_REL_NULL (0x0)
|
||||
#define OPA_SHM_IS_REL_NULL(rel_ptr) (OPA_load_ptr(&(rel_ptr).offset) == OPA_SHM_REL_NULL)
|
||||
#define OPA_SHM_SET_REL_NULL(rel_ptr) (OPA_store_ptr(&(rel_ptr).offset, OPA_SHM_REL_NULL))
|
||||
#define OPA_SHM_REL_ARE_EQUAL(rel_ptr1, rel_ptr2) \
|
||||
(OPA_load_ptr(&(rel_ptr1).offset) == OPA_load_ptr(&(rel_ptr2).offset))
|
||||
|
||||
/* This structure exists such that it is possible to expand the expressiveness
|
||||
of a relative address at some point in the future. It also provides a
|
||||
modicum of type safety to help prevent certain flavors of errors.
|
||||
|
||||
For example, instead of referencing an offset from a global base address, it
|
||||
might make sense for there to be multiple base addresses. These base
|
||||
addresses could correspond to the start of a segment or region of shared
|
||||
memory. This structure could store the segment number that is used to lookup
|
||||
a base address in a non-shared table. Note that you would have to be very
|
||||
careful about all of this because if you add the segment number as a separate
|
||||
field you can no longer (compare and) swap a relative address atomically. So
|
||||
you'll either have to shave bits from the pointer or make some sort of
|
||||
requirement that relative addresses can only be swapped within the same
|
||||
segment. */
|
||||
typedef struct OPA_Shm_rel_addr_t {
|
||||
OPA_ptr_t offset;
|
||||
} OPA_Shm_rel_addr_t;
|
||||
|
||||
/* converts a relative pointer to an absolute pointer */
|
||||
static _opa_inline
|
||||
void *OPA_Shm_rel_to_abs(OPA_Shm_rel_addr_t r)
|
||||
{
|
||||
void *offset = OPA_load_ptr(&r.offset);
|
||||
OPA_assert((size_t)OPA_Shm_asymm_base_addr != OPA_SHM_ASYMM_NULL_VAL);
|
||||
return (void*)(OPA_Shm_asymm_base_addr + (size_t)offset);
|
||||
}
|
||||
|
||||
/* converts an absolute pointer to a relative pointer */
|
||||
static _opa_inline
|
||||
OPA_Shm_rel_addr_t OPA_Shm_abs_to_rel(void *a)
|
||||
{
|
||||
OPA_Shm_rel_addr_t ret;
|
||||
|
||||
OPA_assert((size_t)OPA_Shm_asymm_base_addr != OPA_SHM_ASYMM_NULL_VAL);
|
||||
OPA_store_ptr(&ret.offset, (void*)((size_t)a - (size_t)OPA_Shm_asymm_base_addr));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static _opa_inline
|
||||
OPA_Shm_rel_addr_t OPA_Shm_swap_rel(OPA_Shm_rel_addr_t *addr, OPA_Shm_rel_addr_t newv) {
|
||||
OPA_Shm_rel_addr_t oldv;
|
||||
OPA_store_ptr(&oldv.offset, OPA_swap_ptr(&addr->offset, OPA_load_ptr(&newv.offset)));
|
||||
return oldv;
|
||||
}
|
||||
|
||||
/* Compare the relative pointer to (relative) null and swap if equal. Prevents
|
||||
the guts of the _rel_addr_t abstraction from bleeding up into the
|
||||
enqueue/dequeue operations. */
|
||||
static _opa_inline
|
||||
OPA_Shm_rel_addr_t OPA_Shm_cas_rel_null(OPA_Shm_rel_addr_t *addr, OPA_Shm_rel_addr_t oldv) {
|
||||
OPA_Shm_rel_addr_t prev;
|
||||
OPA_store_ptr(&prev.offset, OPA_cas_ptr(&(addr->offset), OPA_load_ptr(&oldv.offset), (void*)OPA_SHM_REL_NULL));
|
||||
return prev;
|
||||
}
|
||||
|
||||
/* The shadow head pointer makes this queue implementation perform much better
|
||||
than a standard queue. Unfortunately, it also makes it a bit non-intuitive
|
||||
when read the code. The following is an excerpt from "Design and Evaluation
|
||||
of Nemesis, a Scalable, Low-Latency, Message-Passing Communication
|
||||
Subsystem" by D. Buntinas, G. Mercier, and W. Gropp that gives an
|
||||
explanation:
|
||||
|
||||
A process must access both the head and tail of the queue when it is
|
||||
enqueuing an element on an empty queue or when it is dequeuing an element
|
||||
that is the last element in the queue. In these cases, if the head and
|
||||
tail were in the same cache line, only one L2 cache miss would be
|
||||
encountered. If the queue has more elements in it, however, then the
|
||||
enqueuer only needs to access the tail, and the dequeuer only needs to
|
||||
access the head. If the head and tail were in the same cache line, then
|
||||
there would be L2 misses encountered as a result of false sharing each
|
||||
time a process enqueues an element after another has been dequeued from
|
||||
the same queue, and vice versa. In this case it would be better if the
|
||||
head and tail were in separate cache lines.
|
||||
|
||||
Our solution is to put the head and tail in the same cache line and have a
|
||||
shadow head pointer in a separate cache line. The shadow head is
|
||||
initialized to NULL. The dequeuer uses the shadow head in place of the
|
||||
real head except when the shadow head is NULL, meaning that the queue has
|
||||
become empty. If the shadow head is NULL when the dequeuer tries to
|
||||
dequeue, it checks the value of the real head. If the real head is not
|
||||
NULL, meaning that an element has been enqueued on the queue since the
|
||||
last time the queue became empty, the dequeuer initializes its shadow head
|
||||
to the value of the real head and sets the real head to NULL. In this way,
|
||||
only one L2 cache miss is encountered when enqueuing onto an empty queue
|
||||
or dequeuing from a queue with one element. And because the tail and
|
||||
shadow head are in separate cache lines, there are no L2 cache misses from
|
||||
false sharing.
|
||||
|
||||
We found that using a shadow head pointer reduced one-way latency by about
|
||||
200 ns on a dual 2 GHz Xeon node.
|
||||
*/
|
||||
|
||||
/* Pick an arbitrary cacheline size for now, we can setup a mechanism to detect
|
||||
it at build time later on. This should work well on most intel systems at
|
||||
the very least. */
|
||||
#define OPA_QUEUE_CACHELINE_PADDING 128
|
||||
|
||||
/* All absolute and relative pointers point to the start of the enclosing element. */
|
||||
typedef struct OPA_Queue_info_t {
|
||||
OPA_Shm_rel_addr_t head; /* holds the offset pointer, not the abs ptr */
|
||||
OPA_Shm_rel_addr_t tail; /* holds the offset pointer, not the abs ptr */
|
||||
char padding1[OPA_QUEUE_CACHELINE_PADDING-2*sizeof(OPA_Shm_rel_addr_t)];
|
||||
OPA_Shm_rel_addr_t shadow_head; /* holds the offset pointer, not the abs ptr */
|
||||
char padding2[OPA_QUEUE_CACHELINE_PADDING-sizeof(OPA_Shm_rel_addr_t)];
|
||||
} OPA_Queue_info_t;
|
||||
|
||||
/* Using this header struct even though it's just one element gives us the
|
||||
opportunity to vary the implementation more easily in the future without
|
||||
updating all callers. */
|
||||
typedef struct OPA_Queue_element_hdr_t {
|
||||
OPA_Shm_rel_addr_t next; /* holds the offset pointer, not the abs ptr */
|
||||
} OPA_Queue_element_hdr_t;
|
||||
|
||||
|
||||
/* Used to initialize a queue structure. */
|
||||
void OPA_Queue_init(OPA_Queue_info_t *qhead);
|
||||
|
||||
/* Used to initialize a queue element header. */
|
||||
void OPA_Queue_header_init(OPA_Queue_element_hdr_t *hdr);
|
||||
|
||||
static _opa_inline
|
||||
int OPA_Queue_is_empty(OPA_Queue_info_t *qhead)
|
||||
{
|
||||
int __ret = 0;
|
||||
if (OPA_SHM_IS_REL_NULL (qhead->shadow_head)) {
|
||||
if (OPA_SHM_IS_REL_NULL(qhead->head)) {
|
||||
__ret = 1;
|
||||
}
|
||||
else {
|
||||
qhead->shadow_head = qhead->head;
|
||||
OPA_SHM_SET_REL_NULL(qhead->head); /* reset it for next time */
|
||||
}
|
||||
}
|
||||
return __ret;
|
||||
}
|
||||
|
||||
/* Returns a pointer to the element at the head of the queue. The current
|
||||
implementation of these queue algorithms imposes several notable
|
||||
restrictions on the use of this function:
|
||||
- The caller must currently hold the critical section, just as if you were
|
||||
calling OPA_Queue_dequeue. Failure to do could easily produce incorrect
|
||||
results.
|
||||
- OPA_Queue_is_empty must be called on this queue prior to calling this
|
||||
function. Furthermore, there must be no intervening calls to any
|
||||
OPA_Queue_* functions (for this queue) between _is_empty and _peek_head.
|
||||
Failure to do so will produce incorrect results.
|
||||
|
||||
This operation is effectively the same as the dequeue operation (insofar as
|
||||
it shares the same calling restrictions) but it does not disturb the actual
|
||||
contents of the queue. */
|
||||
static _opa_inline
|
||||
void *OPA_Queue_peek_head(OPA_Queue_info_t *qhead_ptr)
|
||||
{
|
||||
OPA_assert(qhead_ptr != NULL);
|
||||
|
||||
if (OPA_SHM_IS_REL_NULL(qhead_ptr->shadow_head)) {
|
||||
return NULL;
|
||||
}
|
||||
return OPA_Shm_rel_to_abs(qhead_ptr->shadow_head);
|
||||
}
|
||||
|
||||
/* This macro atomically enqueues an element (elt for short) into the queue
|
||||
indicated by qhead_ptr. You need to pass several arguments:
|
||||
qhead_ptr - a pointer to a OPA_Queue_info_t structure to which the
|
||||
element should be enqueued
|
||||
elt_ptr - a pointer to an element structure type that is to be enqueued
|
||||
elt_type - The base type of elt_ptr. That is, if elt_ptr is a
|
||||
'(struct example_t *)' then elt_type is 'struct example_t'.
|
||||
elt_hdr_field - This is the member name of elt_type that is a
|
||||
OPA_Queue_element_hdr_t.
|
||||
|
||||
This queue implementation is loosely modeled after the linked lists used in
|
||||
the linux kernel. You put the list header structure inside of the client
|
||||
structure, rather than the other way around.
|
||||
*/
|
||||
#define OPA_Queue_enqueue(qhead_ptr, elt_ptr, elt_type, elt_hdr_field) \
|
||||
do { \
|
||||
OPA_Shm_rel_addr_t r_prev; \
|
||||
OPA_Shm_rel_addr_t r_elt = OPA_Shm_abs_to_rel(elt_ptr); \
|
||||
\
|
||||
OPA_SHM_SET_REL_NULL((elt_ptr)->elt_hdr_field.next); \
|
||||
\
|
||||
OPA_write_barrier(); \
|
||||
\
|
||||
r_prev = OPA_Shm_swap_rel(&((qhead_ptr)->tail), r_elt); \
|
||||
\
|
||||
if (OPA_SHM_IS_REL_NULL(r_prev)) { \
|
||||
(qhead_ptr)->head = r_elt; \
|
||||
} \
|
||||
else { \
|
||||
elt_type *abs_prev = (elt_type *)OPA_Shm_rel_to_abs(r_prev); \
|
||||
abs_prev->elt_hdr_field.next = r_elt; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* This macro atomically dequeues an element (elt for short) from the queue
|
||||
indicated by qhead_ptr. You need to pass several arguments:
|
||||
qhead_ptr - a pointer to a OPA_Queue_info_t structure to which the
|
||||
element should be dequeued
|
||||
elt_ptr - A pointer to an element structure type that should be populated
|
||||
with the dequeued value. Must be an lvalue.
|
||||
elt_type - The base type of elt_ptr. That is, if elt_ptr is a
|
||||
'(struct example_t *)' then elt_type is 'struct example_t'.
|
||||
elt_hdr_field - This is the member name of elt_type that is a
|
||||
OPA_Queue_element_hdr_t.
|
||||
|
||||
This queue implementation is loosely modeled after the linked lists used in
|
||||
the linux kernel. You put the list header structure inside of the client
|
||||
structure, rather than the other way around.
|
||||
|
||||
NOTE: you must *always* call _is_empty() prior to this function */
|
||||
#define OPA_Queue_dequeue(qhead_ptr, elt_ptr, elt_type, elt_hdr_field) \
|
||||
do { \
|
||||
elt_type *_e; \
|
||||
OPA_Shm_rel_addr_t _r_e; \
|
||||
\
|
||||
_r_e = (qhead_ptr)->shadow_head; \
|
||||
_e = OPA_Shm_rel_to_abs(_r_e); \
|
||||
\
|
||||
if (!OPA_SHM_IS_REL_NULL(_e->elt_hdr_field.next)) { \
|
||||
(qhead_ptr)->shadow_head = _e->elt_hdr_field.next; \
|
||||
} \
|
||||
else { \
|
||||
OPA_Shm_rel_addr_t old_tail; \
|
||||
\
|
||||
OPA_SHM_SET_REL_NULL((qhead_ptr)->shadow_head); \
|
||||
\
|
||||
old_tail = OPA_Shm_cas_rel_null(&((qhead_ptr)->tail), _r_e); \
|
||||
\
|
||||
if (!OPA_SHM_REL_ARE_EQUAL(old_tail, _r_e)) { \
|
||||
while (OPA_SHM_IS_REL_NULL(_e->elt_hdr_field.next)) { \
|
||||
OPA_busy_wait(); \
|
||||
} \
|
||||
(qhead_ptr)->shadow_head = _e->elt_hdr_field.next; \
|
||||
} \
|
||||
} \
|
||||
OPA_SHM_SET_REL_NULL(_e->elt_hdr_field.next); \
|
||||
OPA_read_barrier(); \
|
||||
elt_ptr = _e; \
|
||||
} while (0)
|
||||
|
||||
#endif /* OPA_QUEUE_H_INCLUDED */
|
||||
@@ -1,27 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
|
||||
/*
|
||||
* (C) 2008 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef OPA_UTIL_H_INCLUDED
|
||||
#define OPA_UTIL_H_INCLUDED
|
||||
|
||||
#define OPA_QUOTE(x_) OPA_QUOTE2(x_)
|
||||
#define OPA_QUOTE2(x_) #x_
|
||||
|
||||
#if defined(OPA_HAVE_GCC_ATTRIBUTE)
|
||||
# define OPA_ATTRIBUTE(x_) __attribute__ (x_)
|
||||
#else
|
||||
# define OPA_ATTRIBUTE(x_)
|
||||
#endif
|
||||
|
||||
/* FIXME this just needs a total rework in general with an OPA_NDEBUG or similar. */
|
||||
#define OPA_assert(expr_) do {} while (0)
|
||||
#define OPA_assertp(expr_) do { if (!(expr_)) ++((int *)NULL) } while (0) /* SEGV intentionally */
|
||||
|
||||
/* A compile-time assertion macro. It should cause a compilation error if (expr_) is false. */
|
||||
#define OPA_COMPILE_TIME_ASSERT(expr_) \
|
||||
do { switch(0) { case 0: case (expr_): default: break; } } while (0)
|
||||
|
||||
#endif /* OPA_UTIL_H_INCLUDED */
|
||||
@@ -1,205 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
|
||||
/*
|
||||
* (C) 2008 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef OPA_BY_LOCK_H_INCLUDED
|
||||
#define OPA_BY_LOCK_H_INCLUDED
|
||||
|
||||
/* FIXME For now we rely on pthreads for our IPC locks. This is fairly
|
||||
portable, although it is obviously not 100% portable. Some day when we
|
||||
refactor the OPA_Process_locks code we should be able to use that again. */
|
||||
#if defined(OPA_HAVE_PTHREAD_H)
|
||||
#include <pthread.h>
|
||||
|
||||
/* defined in opa_primitives.c */
|
||||
extern pthread_mutex_t *OPA_emulation_lock;
|
||||
|
||||
/* FIXME these make less sense now that OPA is not inside of MPICH. Is there a
|
||||
simpler name/scheme that could be used here instead? [goodell@ 2009-02-19] */
|
||||
#define OPA_IPC_SINGLE_CS_ENTER(msg) \
|
||||
do { \
|
||||
OPA_assert(OPA_emulation_lock); \
|
||||
pthread_mutex_lock(OPA_emulation_lock); \
|
||||
} while (0)
|
||||
|
||||
#define OPA_IPC_SINGLE_CS_EXIT(msg) \
|
||||
do { \
|
||||
OPA_assert(OPA_emulation_lock); \
|
||||
pthread_mutex_unlock(OPA_emulation_lock); \
|
||||
} while (0)
|
||||
|
||||
typedef struct { volatile int v; } OPA_int_t;
|
||||
typedef struct { int * volatile v; } OPA_ptr_t;
|
||||
|
||||
#define OPA_INT_T_INITIALIZER(val_) { (val_) }
|
||||
#define OPA_PTR_T_INITIALIZER(val_) { (val_) }
|
||||
|
||||
/*
|
||||
Emulated atomic primitives
|
||||
--------------------------
|
||||
|
||||
These are versions of the atomic primitives that emulate the proper behavior
|
||||
via the use of an inter-process lock. For more information on their
|
||||
individual behavior, please see the comment on the corresponding top level
|
||||
function.
|
||||
|
||||
In general, these emulated primitives should _not_ be used. Most algorithms
|
||||
can be more efficiently implemented by putting most or all of the algorithm
|
||||
inside of a single critical section. These emulated primitives exist to
|
||||
ensure that there is always a fallback if no machine-dependent version of a
|
||||
particular operation has been defined. They also serve as a very readable
|
||||
reference for the exact semantics of our OPA_* ops.
|
||||
*/
|
||||
|
||||
static _opa_inline int OPA_load_int(_opa_const OPA_int_t *ptr)
|
||||
{
|
||||
int retval;
|
||||
OPA_IPC_SINGLE_CS_ENTER("atomic_add");
|
||||
retval = ptr->v;
|
||||
OPA_IPC_SINGLE_CS_EXIT("atomic_add");
|
||||
return retval;
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_store_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
OPA_IPC_SINGLE_CS_ENTER("atomic_add");
|
||||
ptr->v = val;
|
||||
OPA_IPC_SINGLE_CS_EXIT("atomic_add");
|
||||
}
|
||||
|
||||
static _opa_inline void *OPA_load_ptr(_opa_const OPA_ptr_t *ptr)
|
||||
{
|
||||
int *retval;
|
||||
OPA_IPC_SINGLE_CS_ENTER("atomic_add");
|
||||
retval = ptr->v;
|
||||
OPA_IPC_SINGLE_CS_EXIT("atomic_add");
|
||||
return retval;
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_store_ptr(OPA_ptr_t *ptr, void *val)
|
||||
{
|
||||
OPA_IPC_SINGLE_CS_ENTER("atomic_add");
|
||||
ptr->v = val;
|
||||
OPA_IPC_SINGLE_CS_EXIT("atomic_add");
|
||||
}
|
||||
|
||||
/* normal loads/stores are fully ordered, so just use them */
|
||||
#define OPA_load_acquire_int(ptr_) OPA_load_int((ptr_))
|
||||
#define OPA_store_release_int(ptr_,val_) OPA_store_int((ptr_),(val_))
|
||||
#define OPA_load_acquire_ptr(ptr_) OPA_load_ptr((ptr_))
|
||||
#define OPA_store_release_ptr(ptr_,val_) OPA_store_ptr((ptr_),(val_))
|
||||
|
||||
static _opa_inline void OPA_add_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
OPA_IPC_SINGLE_CS_ENTER("atomic_add");
|
||||
ptr->v += val;
|
||||
OPA_IPC_SINGLE_CS_EXIT("atomic_add");
|
||||
}
|
||||
|
||||
static _opa_inline void *OPA_cas_ptr(OPA_ptr_t *ptr, int *oldv, int *newv)
|
||||
{
|
||||
int *prev;
|
||||
OPA_IPC_SINGLE_CS_ENTER("atomic_cas");
|
||||
prev = ptr->v;
|
||||
if (prev == oldv) {
|
||||
ptr->v = newv;
|
||||
}
|
||||
OPA_IPC_SINGLE_CS_EXIT("atomic_cas");
|
||||
return prev;
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_cas_int(OPA_int_t *ptr, int oldv, int newv)
|
||||
{
|
||||
int prev;
|
||||
OPA_IPC_SINGLE_CS_ENTER("atomic_cas");
|
||||
prev = ptr->v;
|
||||
if (prev == oldv) {
|
||||
ptr->v = newv;
|
||||
}
|
||||
OPA_IPC_SINGLE_CS_EXIT("atomic_cas");
|
||||
return prev;
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_decr_and_test_int(OPA_int_t *ptr)
|
||||
{
|
||||
int new_val;
|
||||
OPA_IPC_SINGLE_CS_ENTER("atomic_decr_and_test");
|
||||
new_val = --(ptr->v);
|
||||
OPA_IPC_SINGLE_CS_EXIT("atomic_decr_and_test");
|
||||
return (0 == new_val);
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_decr_int(OPA_int_t *ptr)
|
||||
{
|
||||
OPA_IPC_SINGLE_CS_ENTER("atomic_decr");
|
||||
--(ptr->v);
|
||||
OPA_IPC_SINGLE_CS_EXIT("atomic_decr");
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_fetch_and_add_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
int prev;
|
||||
OPA_IPC_SINGLE_CS_ENTER("atomic_fetch_and_add");
|
||||
prev = ptr->v;
|
||||
ptr->v += val;
|
||||
OPA_IPC_SINGLE_CS_EXIT("atomic_fetch_and_add");
|
||||
return prev;
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_fetch_and_decr_int(OPA_int_t *ptr)
|
||||
{
|
||||
int prev;
|
||||
OPA_IPC_SINGLE_CS_ENTER("atomic_fetch_and_decr");
|
||||
prev = ptr->v;
|
||||
--(ptr->v);
|
||||
OPA_IPC_SINGLE_CS_EXIT("atomic_fetch_and_decr");
|
||||
return prev;
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_fetch_and_incr_int(OPA_int_t *ptr)
|
||||
{
|
||||
int prev;
|
||||
OPA_IPC_SINGLE_CS_ENTER("atomic_fetch_and_incr");
|
||||
prev = ptr->v;
|
||||
++(ptr->v);
|
||||
OPA_IPC_SINGLE_CS_EXIT("atomic_fetch_and_incr");
|
||||
return prev;
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_incr_int(OPA_int_t *ptr)
|
||||
{
|
||||
OPA_IPC_SINGLE_CS_ENTER("atomic_incr");
|
||||
++(ptr->v);
|
||||
OPA_IPC_SINGLE_CS_EXIT("atomic_incr");
|
||||
}
|
||||
|
||||
static _opa_inline void *OPA_swap_ptr(OPA_ptr_t *ptr, void *val)
|
||||
{
|
||||
int *prev;
|
||||
OPA_IPC_SINGLE_CS_ENTER("atomic_swap_ptr");
|
||||
prev = ptr->v;
|
||||
ptr->v = val;
|
||||
OPA_IPC_SINGLE_CS_EXIT("atomic_swap_ptr");
|
||||
return prev;
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_swap_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
int prev;
|
||||
OPA_IPC_SINGLE_CS_ENTER("atomic_swap_int");
|
||||
prev = ptr->v;
|
||||
ptr->v = val;
|
||||
OPA_IPC_SINGLE_CS_EXIT("atomic_swap_int");
|
||||
return (int)prev;
|
||||
}
|
||||
|
||||
/* lock/unlock provides barrier */
|
||||
#define OPA_write_barrier() do {} while (0)
|
||||
#define OPA_read_barrier() do {} while (0)
|
||||
#define OPA_read_write_barrier() do {} while (0)
|
||||
|
||||
|
||||
#endif /* defined(OPA_HAVE_PTHREAD_H) */
|
||||
#endif /* !defined(OPA_BY_LOCK_H_INCLUDED) */
|
||||
@@ -1,192 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
|
||||
/*
|
||||
* (C) 2008 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef OPA_EMULATED_H_INCLUDED
|
||||
#define OPA_EMULATED_H_INCLUDED
|
||||
|
||||
/* Functions emulated using other atomics
|
||||
|
||||
This header should be included at the bottom of any atomic
|
||||
primitives header that needs to implement an atomic op in terms of
|
||||
another atomic.
|
||||
*/
|
||||
|
||||
/* Emulating using LL/SC */
|
||||
#if defined(OPA_LL_SC_SUPPORTED)
|
||||
static _opa_inline int OPA_fetch_and_add_int_by_llsc(OPA_int_t *ptr, int val)
|
||||
{
|
||||
int prev;
|
||||
do {
|
||||
prev = OPA_LL_int(ptr);
|
||||
} while (!OPA_SC_int(ptr, prev + val));
|
||||
return prev;
|
||||
}
|
||||
|
||||
|
||||
static _opa_inline void OPA_add_int_by_llsc(OPA_int_t *ptr, int val)
|
||||
{
|
||||
OPA_fetch_and_add_int_by_llsc(ptr, val);
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_incr_int_by_llsc(OPA_int_t *ptr)
|
||||
{
|
||||
OPA_add_int_by_llsc(ptr, 1);
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_decr_int_by_llsc(OPA_int_t *ptr)
|
||||
{
|
||||
OPA_add_int_by_llsc(ptr, -1);
|
||||
}
|
||||
|
||||
|
||||
static _opa_inline int OPA_fetch_and_decr_int_by_llsc(OPA_int_t *ptr)
|
||||
{
|
||||
return OPA_fetch_and_add_int_by_llsc(ptr, -1);
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_fetch_and_incr_int_by_llsc(OPA_int_t *ptr)
|
||||
{
|
||||
return OPA_fetch_and_add_int_by_llsc(ptr, 1);
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_decr_and_test_int_by_llsc(OPA_int_t *ptr)
|
||||
{
|
||||
int prev = OPA_fetch_and_decr_int_by_llsc(ptr);
|
||||
return prev == 1;
|
||||
}
|
||||
|
||||
static _opa_inline void *OPA_cas_ptr_by_llsc(OPA_ptr_t *ptr, void *oldv, void *newv)
|
||||
{
|
||||
void *prev;
|
||||
do {
|
||||
prev = OPA_LL_ptr(ptr);
|
||||
} while (prev == oldv && !OPA_SC_ptr(ptr, newv));
|
||||
return prev;
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_cas_int_by_llsc(OPA_int_t *ptr, int oldv, int newv)
|
||||
{
|
||||
int prev;
|
||||
do {
|
||||
prev = OPA_LL_int(ptr);
|
||||
} while (prev == oldv && !OPA_SC_int(ptr, newv));
|
||||
return prev;
|
||||
}
|
||||
|
||||
|
||||
static _opa_inline void *OPA_swap_ptr_by_llsc(OPA_ptr_t *ptr, void *val)
|
||||
{
|
||||
void *prev;
|
||||
do {
|
||||
prev = OPA_LL_ptr(ptr);
|
||||
} while (!OPA_SC_ptr(ptr, val));
|
||||
return prev;
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_swap_int_by_llsc(OPA_int_t *ptr, int val)
|
||||
{
|
||||
int prev;
|
||||
do {
|
||||
prev = OPA_LL_int(ptr);
|
||||
} while (!OPA_SC_int(ptr, val));
|
||||
return prev;
|
||||
}
|
||||
|
||||
#endif /* OPA_LL_SC_SUPPORTED */
|
||||
|
||||
static _opa_inline int OPA_fetch_and_add_int_by_cas(OPA_int_t *ptr, int val)
|
||||
{
|
||||
int cmp;
|
||||
int prev = OPA_load_int(ptr);
|
||||
|
||||
do {
|
||||
cmp = prev;
|
||||
prev = OPA_cas_int(ptr, cmp, prev + val);
|
||||
} while (prev != cmp);
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_fetch_and_incr_int_by_faa(OPA_int_t *ptr)
|
||||
{
|
||||
return OPA_fetch_and_add_int(ptr, 1);
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_fetch_and_decr_int_by_faa(OPA_int_t *ptr)
|
||||
{
|
||||
return OPA_fetch_and_add_int(ptr, -1);
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_decr_and_test_int_by_fad(OPA_int_t *ptr)
|
||||
{
|
||||
return OPA_fetch_and_decr_int(ptr) == 1;
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_add_int_by_faa(OPA_int_t *ptr, int val)
|
||||
{
|
||||
OPA_fetch_and_add_int(ptr, val);
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_incr_int_by_faa(OPA_int_t *ptr)
|
||||
{
|
||||
return OPA_fetch_and_add_int(ptr, 1);
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_incr_int_by_add(OPA_int_t *ptr)
|
||||
{
|
||||
OPA_add_int(ptr, 1);
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_incr_int_by_fai(OPA_int_t *ptr)
|
||||
{
|
||||
OPA_fetch_and_incr_int(ptr);
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_decr_int_by_faa(OPA_int_t *ptr)
|
||||
{
|
||||
return OPA_fetch_and_add_int(ptr, -1);
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_decr_int_by_add(OPA_int_t *ptr)
|
||||
{
|
||||
OPA_add_int(ptr, -1);
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_decr_int_by_fad(OPA_int_t *ptr)
|
||||
{
|
||||
OPA_fetch_and_decr_int(ptr);
|
||||
}
|
||||
|
||||
|
||||
/* Swap using CAS */
|
||||
|
||||
static _opa_inline void *OPA_swap_ptr_by_cas(OPA_ptr_t *ptr, void *val)
|
||||
{
|
||||
void *cmp;
|
||||
void *prev = OPA_load_ptr(ptr);
|
||||
|
||||
do {
|
||||
cmp = prev;
|
||||
prev = OPA_cas_ptr(ptr, cmp, val);
|
||||
} while (prev != cmp);
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_swap_int_by_cas(OPA_int_t *ptr, int val)
|
||||
{
|
||||
int cmp;
|
||||
int prev = OPA_load_int(ptr);
|
||||
|
||||
do {
|
||||
cmp = prev;
|
||||
prev = OPA_cas_int(ptr, cmp, val);
|
||||
} while (prev != cmp);
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
#endif /* OPA_EMULATED_H_INCLUDED */
|
||||
@@ -1,216 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
|
||||
/*
|
||||
* (C) 2008 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
|
||||
/* NOTE: We (@ANL) do not have easy access to any ia64 hosts, so it is difficult
|
||||
* to develop and test updates to this file. Any help in this regard is greatly
|
||||
* appreciated. */
|
||||
|
||||
#ifndef OPA_GCC_IA64_H_INCLUDED
|
||||
#define OPA_GCC_IA64_H_INCLUDED
|
||||
|
||||
/* FIXME do we need to align these? */
|
||||
typedef struct { volatile int v; } OPA_int_t;
|
||||
typedef struct { void * volatile v; } OPA_ptr_t;
|
||||
|
||||
#define OPA_INT_T_INITIALIZER(val_) { (val_) }
|
||||
#define OPA_PTR_T_INITIALIZER(val_) { (val_) }
|
||||
|
||||
/* Aligned loads and stores are atomic on ia64. */
|
||||
static _opa_inline int OPA_load_int(_opa_const OPA_int_t *ptr)
|
||||
{
|
||||
return ptr->v;
|
||||
}
|
||||
|
||||
/* Aligned loads and stores are atomic on ia64. */
|
||||
static _opa_inline void OPA_store_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
ptr->v = val;
|
||||
}
|
||||
|
||||
/* Aligned loads and stores are atomic on ia64. */
|
||||
static _opa_inline void *OPA_load_ptr(_opa_const OPA_ptr_t *ptr)
|
||||
{
|
||||
return ptr->v;
|
||||
}
|
||||
|
||||
/* Aligned loads and stores are atomic on ia64. */
|
||||
static _opa_inline void OPA_store_ptr(OPA_ptr_t *ptr, void *val)
|
||||
{
|
||||
ptr->v = val;
|
||||
}
|
||||
|
||||
|
||||
/* NOTE-IA64-1 ia64 suports half-fence suffixes to ld/st instructions. It seems
|
||||
* that compilers also treat any C-language load/store from/to a volatile
|
||||
* variable as acquire/release and append the corresponding suffix accordingly.
|
||||
* But we don't have extensive testing to back this up, so we'll explicitly
|
||||
* force these instructions for now. When using the C-level approach, it's not
|
||||
* clear what instructions the compiler is allowed to reorder. */
|
||||
|
||||
#if 0
|
||||
/* acquire means operations after the acquire will see any memory opeations
|
||||
* performed before the corresponding paired release operation */
|
||||
static _opa_inline int OPA_load_acquire_int(_opa_const OPA_int_t *ptr)
|
||||
{
|
||||
int tmp;
|
||||
__asm__ __volatile__ ("ld.acq %0=[%1]"
|
||||
: "=r" (tmp)
|
||||
: "r" (ptr->v)
|
||||
: "memory");
|
||||
return tmp;
|
||||
}
|
||||
static _opa_inline void OPA_store_release_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
__asm__ __volatile__ ("st.rel [%0]=%1"
|
||||
: "=m" (ptr->v)
|
||||
: "r" (val)
|
||||
: "memory");
|
||||
}
|
||||
static _opa_inline void *OPA_load_acquire_ptr(_opa_const OPA_ptr_t *ptr)
|
||||
{
|
||||
int tmp;
|
||||
__asm__ __volatile__ ("ld.acq %0=[%1]"
|
||||
: "=r" (tmp)
|
||||
: "r" (ptr->v)
|
||||
: "memory");
|
||||
return tmp;
|
||||
}
|
||||
static _opa_inline void OPA_store_release_ptr(OPA_ptr_t *ptr, void *val)
|
||||
{
|
||||
__asm__ __volatile__ ("st.rel [%0]=%1"
|
||||
: "=m" (ptr->v)
|
||||
: "r" (val)
|
||||
: "memory");
|
||||
}
|
||||
#else
|
||||
/* FIXME because we can't test these implementations, they are currently
|
||||
* disabled. The above impls are rough starting points, but probably won't
|
||||
* compile/assemble correctly as-is. Patches are welcome :) */
|
||||
#define OPA_load_acquire_int(ptr_) ::"choke me"
|
||||
#define OPA_store_release_int(ptr_,val_) ::"choke me"
|
||||
#define OPA_load_acquire_ptr(ptr_) ::"choke me"
|
||||
#define OPA_store_release_ptr(ptr_,val_) ::"choke me"
|
||||
#endif
|
||||
|
||||
|
||||
#define OPA_add_int_by_faa OPA_add_int
|
||||
#define OPA_incr_int_by_faa OPA_incr_int
|
||||
#define OPA_decr_int_by_faa OPA_decr_int
|
||||
#define OPA_fetch_and_decr_int_by_faa OPA_fetch_and_decr_int
|
||||
#define OPA_fetch_and_incr_int_by_faa OPA_fetch_and_incr_int
|
||||
|
||||
static _opa_inline int OPA_decr_and_test_int(OPA_int_t *ptr)
|
||||
{
|
||||
int val;
|
||||
__asm__ __volatile__ ("fetchadd4.rel %0=[%2],%3"
|
||||
: "=r"(val), "=m"(ptr->v)
|
||||
: "r"(&ptr->v), "i"(-1));
|
||||
return val == 1;
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_cas_int(OPA_int_t *ptr, int oldv, int newv)
|
||||
{
|
||||
int prev;
|
||||
|
||||
#if OPA_SIZEOF_INT == 8
|
||||
__asm__ __volatile__ ("mov ar.ccv=%1;;"
|
||||
"cmpxchg8.rel %0=[%3],%4,ar.ccv"
|
||||
: "=r"(prev), "=m"(ptr->v)
|
||||
: "rO"(oldv), "r"(&ptr->v), "r"(newv)
|
||||
: "memory");
|
||||
break;
|
||||
#elif OPA_SIZEOF_INT == 4
|
||||
__asm__ __volatile__ ("zxt4 %1=%1;;" /* don't want oldv sign-extended to 64 bits */
|
||||
"mov ar.ccv=%1;;"
|
||||
"cmpxchg4.rel %0=[%3],%4,ar.ccv"
|
||||
: "=r"(prev), "=m"(ptr->v)
|
||||
: "r0"(oldv), "r"(&ptr->v), "r"(newv)
|
||||
: "memory");
|
||||
#else
|
||||
#error OPA_SIZEOF_INT is not 4 or 8
|
||||
#endif
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
/* IA64 has a fetch-and-add instruction that only accepts immediate
|
||||
values of -16, -8, -4, -1, 1, 4, 8, and 16. So we check for these
|
||||
values before falling back to the CAS implementation. */
|
||||
#define OPA_IA64_FAA_CASE_MACRO(ptr, val) case val: { \
|
||||
int prev; \
|
||||
__asm__ __volatile__ ("fetchadd4.rel %0=[%2],%3" \
|
||||
: "=r"(prev), "=m"(ptr->v) \
|
||||
: "r"(&ptr->v), "i"(val)); \
|
||||
return prev; \
|
||||
} \
|
||||
break
|
||||
|
||||
|
||||
static _opa_inline int OPA_fetch_and_add_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
switch (val)
|
||||
{
|
||||
OPA_IA64_FAA_CASE_MACRO(ptr, -16);
|
||||
OPA_IA64_FAA_CASE_MACRO(ptr, -8);
|
||||
OPA_IA64_FAA_CASE_MACRO(ptr, -4);
|
||||
OPA_IA64_FAA_CASE_MACRO(ptr, -1);
|
||||
OPA_IA64_FAA_CASE_MACRO(ptr, 1);
|
||||
OPA_IA64_FAA_CASE_MACRO(ptr, 4);
|
||||
OPA_IA64_FAA_CASE_MACRO(ptr, 8);
|
||||
OPA_IA64_FAA_CASE_MACRO(ptr, 16);
|
||||
default:
|
||||
{
|
||||
int cmp;
|
||||
int prev = OPA_load_int(ptr);
|
||||
|
||||
do {
|
||||
cmp = prev;
|
||||
prev = OPA_cas_int(ptr, cmp, val);
|
||||
} while (prev != cmp);
|
||||
|
||||
return prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
#undef OPA_IA64_FAA_CASE_MACRO
|
||||
|
||||
|
||||
static _opa_inline void *OPA_cas_ptr(OPA_ptr_t *ptr, void *oldv, void *newv)
|
||||
{
|
||||
void *prev;
|
||||
__asm__ __volatile__ ("mov ar.ccv=%1;;"
|
||||
"cmpxchg8.rel %0=[%3],%4,ar.ccv"
|
||||
: "=r"(prev), "=m"(ptr->v)
|
||||
: "rO"(oldv), "r"(&ptr->v), "r"(newv));
|
||||
return prev;
|
||||
}
|
||||
|
||||
static _opa_inline void *OPA_swap_ptr(OPA_ptr_t *ptr, void *val)
|
||||
{
|
||||
__asm__ __volatile__ ("xchg8 %0=[%2],%3"
|
||||
: "=r" (val), "=m" (ptr->v)
|
||||
: "r" (&ptr->v), "0" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
static _opa_inline int OPA_swap_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
__asm__ __volatile__ ("xchg8 %0=[%2],%3"
|
||||
: "=r" (val), "=m" (ptr->v)
|
||||
: "r" (&ptr->v), "0" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
#define OPA_write_barrier() __asm__ __volatile__ ("mf" ::: "memory" )
|
||||
#define OPA_read_barrier() __asm__ __volatile__ ("mf" ::: "memory" )
|
||||
#define OPA_read_write_barrier() __asm__ __volatile__ ("mf" ::: "memory" )
|
||||
#define OPA_compiler_barrier() __asm__ __volatile__ ("" ::: "memory" )
|
||||
|
||||
#include "opa_emulated.h"
|
||||
|
||||
#endif /* OPA_GCC_IA64_H_INCLUDED */
|
||||
@@ -1,15 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
|
||||
/*
|
||||
* (C) 2008 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef OPA_GCC_INTEL_32_64_H_INCLUDED
|
||||
#define OPA_GCC_INTEL_32_64_H_INCLUDED
|
||||
|
||||
#include "opa_gcc_intel_32_64_barrier.h"
|
||||
#include "opa_gcc_intel_32_64_ops.h"
|
||||
|
||||
#include "opa_emulated.h"
|
||||
|
||||
#endif /* OPA_GCC_INTEL_32_64_H_INCLUDED */
|
||||
@@ -1,25 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
|
||||
/*
|
||||
* (C) 2008 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef OPA_GCC_INTEL_32_64_BARRIER_H_INCLUDED
|
||||
#define OPA_GCC_INTEL_32_64_BARRIER_H_INCLUDED
|
||||
|
||||
#define OPA_compiler_barrier() __asm__ __volatile__ ( "" ::: "memory" )
|
||||
|
||||
/* For all regular memory (write-back cacheable, not driver/graphics
|
||||
* memory), there is only one general ordering relaxation permitted by
|
||||
* x86/x86_64 processors: earlier stores may be retired after later
|
||||
* stores. The "clflush" and "movnt*" instructions also don't follow
|
||||
* general ordering constraints, although any code using these
|
||||
* instructions should be responsible for ensuring proper ordering
|
||||
* itself. So our read and write barriers may be implemented as simple
|
||||
* compiler barriers. */
|
||||
#define OPA_write_barrier() OPA_compiler_barrier()
|
||||
#define OPA_read_barrier() OPA_compiler_barrier()
|
||||
|
||||
#define OPA_read_write_barrier() __asm__ __volatile__ ( "mfence" ::: "memory" )
|
||||
|
||||
#endif /* OPA_GCC_INTEL_32_64_BARRIER_H_INCLUDED */
|
||||
@@ -1,173 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
|
||||
/*
|
||||
* (C) 2008 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef OPA_GCC_INTEL_32_64_OPS_H_INCLUDED
|
||||
#define OPA_GCC_INTEL_32_64_OPS_H_INCLUDED
|
||||
|
||||
#ifndef OPA_SIZEOF_INT
|
||||
#error OPA_SIZEOF_INT is not defined
|
||||
#endif
|
||||
|
||||
/* Set OPA_SS (Size Suffix) which is to be appended to asm ops for
|
||||
specifying 4 or 8 byte operands */
|
||||
#if OPA_SIZEOF_INT == 4
|
||||
#define OPA_SS "l"
|
||||
#elif OPA_SIZEOF_INT == 8
|
||||
#define OPA_SS "q"
|
||||
#else
|
||||
#error OPA_SIZEOF_INT is not 4 or 8
|
||||
#endif
|
||||
|
||||
/* XXX DJG FIXME do we need to align these? */
|
||||
typedef struct { volatile int v; } OPA_int_t;
|
||||
typedef struct { void * volatile v; } OPA_ptr_t;
|
||||
|
||||
#define OPA_INT_T_INITIALIZER(val_) { (val_) }
|
||||
#define OPA_PTR_T_INITIALIZER(val_) { (val_) }
|
||||
|
||||
/* Aligned loads and stores are atomic on x86(-64). */
|
||||
static _opa_inline int OPA_load_int(_opa_const OPA_int_t *ptr)
|
||||
{
|
||||
return ptr->v;
|
||||
}
|
||||
|
||||
/* Aligned loads and stores are atomic on x86(-64). */
|
||||
static _opa_inline void OPA_store_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
ptr->v = val;
|
||||
}
|
||||
|
||||
/* Aligned loads and stores are atomic on x86(-64). */
|
||||
static _opa_inline void *OPA_load_ptr(_opa_const OPA_ptr_t *ptr)
|
||||
{
|
||||
return ptr->v;
|
||||
}
|
||||
|
||||
/* Aligned loads and stores are atomic on x86(-64). */
|
||||
static _opa_inline void OPA_store_ptr(OPA_ptr_t *ptr, void *val)
|
||||
{
|
||||
ptr->v = val;
|
||||
}
|
||||
|
||||
/* NOTE-X86-1 x86 and x86_64 processors execute instructions such that their
|
||||
* effects are visible in issue order, with one exception: earlier stores may
|
||||
* pass later loads. Also, non-temporal stores (with the "movnt*" instructions)
|
||||
* do not follow these ordering constraints. So all normal load/store
|
||||
* instructions on x86(_64) already have acquire/release semantics. We just
|
||||
* have to make sure that the compiler does not reorder the instructions. */
|
||||
|
||||
static _opa_inline int OPA_load_acquire_int(_opa_const OPA_int_t *ptr)
|
||||
{
|
||||
int tmp;
|
||||
tmp = ptr->v;
|
||||
OPA_compiler_barrier(); /* NOTE-X86-1 */
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_store_release_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
OPA_compiler_barrier(); /* NOTE-X86-1 */
|
||||
ptr->v = val;
|
||||
}
|
||||
|
||||
static _opa_inline void *OPA_load_acquire_ptr(_opa_const OPA_ptr_t *ptr)
|
||||
{
|
||||
void *tmp;
|
||||
tmp = ptr->v;
|
||||
OPA_compiler_barrier(); /* NOTE-X86-1 */
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_store_release_ptr(OPA_ptr_t *ptr, void *val)
|
||||
{
|
||||
OPA_compiler_barrier(); /* NOTE-X86-1 */
|
||||
ptr->v = val;
|
||||
}
|
||||
|
||||
|
||||
static _opa_inline void OPA_add_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
__asm__ __volatile__ ("lock ; add"OPA_SS" %1,%0"
|
||||
:"=m" (ptr->v)
|
||||
:"ir" (val), "m" (ptr->v));
|
||||
return;
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_incr_int(OPA_int_t *ptr)
|
||||
{
|
||||
__asm__ __volatile__ ("lock ; inc"OPA_SS" %0"
|
||||
:"=m" (ptr->v)
|
||||
:"m" (ptr->v));
|
||||
return;
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_decr_int(OPA_int_t *ptr)
|
||||
{
|
||||
__asm__ __volatile__ ("lock ; dec"OPA_SS" %0"
|
||||
:"=m" (ptr->v)
|
||||
:"m" (ptr->v));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static _opa_inline int OPA_decr_and_test_int(OPA_int_t *ptr)
|
||||
{
|
||||
char result;
|
||||
__asm__ __volatile__ ("lock ; dec"OPA_SS" %0; setz %1"
|
||||
:"=m" (ptr->v), "=q" (result)
|
||||
:"m" (ptr->v));
|
||||
return result;
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_fetch_and_add_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
__asm__ __volatile__ ("lock ; xadd %0,%1"
|
||||
: "=r" (val), "=m" (ptr->v)
|
||||
: "0" (val), "m" (ptr->v));
|
||||
return val;
|
||||
}
|
||||
|
||||
#define OPA_fetch_and_incr_int_by_faa OPA_fetch_and_incr_int
|
||||
#define OPA_fetch_and_decr_int_by_faa OPA_fetch_and_decr_int
|
||||
|
||||
|
||||
static _opa_inline void *OPA_cas_ptr(OPA_ptr_t *ptr, void *oldv, void *newv)
|
||||
{
|
||||
void *prev;
|
||||
__asm__ __volatile__ ("lock ; cmpxchg %3,%4"
|
||||
: "=a" (prev), "=m" (ptr->v)
|
||||
: "0" (oldv), "q" (newv), "m" (ptr->v));
|
||||
return prev;
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_cas_int(OPA_int_t *ptr, int oldv, int newv)
|
||||
{
|
||||
int prev;
|
||||
__asm__ __volatile__ ("lock ; cmpxchg %3,%4"
|
||||
: "=a" (prev), "=m" (ptr->v)
|
||||
: "0" (oldv), "q" (newv), "m" (ptr->v));
|
||||
return prev;
|
||||
}
|
||||
|
||||
static _opa_inline void *OPA_swap_ptr(OPA_ptr_t *ptr, void *val)
|
||||
{
|
||||
__asm__ __volatile__ ("xchg %0,%1"
|
||||
:"=r" (val), "=m" (ptr->v)
|
||||
: "0" (val), "m" (ptr->v));
|
||||
return val;
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_swap_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
__asm__ __volatile__ ("xchg %0,%1"
|
||||
:"=r" (val), "=m" (ptr->v)
|
||||
: "0" (val), "m" (ptr->v));
|
||||
return val;
|
||||
}
|
||||
|
||||
#undef OPA_SS
|
||||
|
||||
#endif /* OPA_GCC_INTEL_32_64_OPS_H_INCLUDED */
|
||||
@@ -1,15 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
|
||||
/*
|
||||
* (C) 2008 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef OPA_GCC_INTEL_32_64_P3_H_INCLUDED
|
||||
#define OPA_GCC_INTEL_32_64_P3_H_INCLUDED
|
||||
|
||||
#include "opa_gcc_intel_32_64_p3barrier.h"
|
||||
#include "opa_gcc_intel_32_64_ops.h"
|
||||
|
||||
#include "opa_emulated.h"
|
||||
|
||||
#endif /* OPA_GCC_INTEL_32_64_P3_H_INCLUDED */
|
||||
@@ -1,34 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
|
||||
/*
|
||||
* (C) 2008 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef OPA_GCC_INTEL_32_64_P3BARRIER_H_INCLUDED
|
||||
#define OPA_GCC_INTEL_32_64_P3BARRIER_H_INCLUDED
|
||||
|
||||
#define OPA_compiler_barrier() __asm__ __volatile__ ( "" ::: "memory" )
|
||||
|
||||
/* For all regular memory (write-back cacheable, not driver/graphics
|
||||
* memory), there is only one general ordering relaxation permitted by
|
||||
* x86/x86_64 processors: earlier stores may be retired after later
|
||||
* stores. The "clflush" and "movnt*" instructions also don't follow
|
||||
* general ordering constraints, although any code using these
|
||||
* instructions should be responsible for ensuring proper ordering
|
||||
* itself. So our read and write barriers may be implemented as simple
|
||||
* compiler barriers. */
|
||||
#define OPA_write_barrier() OPA_compiler_barrier()
|
||||
#define OPA_read_barrier() OPA_compiler_barrier()
|
||||
|
||||
/* Some Pentium III and earlier processors have store barriers
|
||||
(sfence), but no full barrier or load barriers. Some other very
|
||||
recent x86-like processors don't seem to have sfence either. A
|
||||
lock-prefixed atomic instruction (operating on any memory) behaves as
|
||||
a full memory barrier, so we use that here. */
|
||||
static inline void OPA_read_write_barrier(void)
|
||||
{
|
||||
int a = 0;
|
||||
__asm__ __volatile__ ("lock orl $0, %0" : "+m" (a) : /*no outputs*/ : "memory");
|
||||
}
|
||||
|
||||
#endif /* OPA_GCC_INTEL_32_64_P3BARRIER_H_INCLUDED */
|
||||
@@ -1,129 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
|
||||
/*
|
||||
* (C) 2008 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
|
||||
/* FIXME needs to be converted to new style functions with OPA_int_t/OPA_ptr_t-types */
|
||||
#ifndef OPA_GCC_INTRINSICS_H_INCLUDED
|
||||
#define OPA_GCC_INTRINSICS_H_INCLUDED
|
||||
|
||||
/* FIXME do we need to align these? */
|
||||
typedef struct { volatile int v; } OPA_int_t;
|
||||
typedef struct { void * volatile v; } OPA_ptr_t;
|
||||
|
||||
#define OPA_INT_T_INITIALIZER(val_) { (val_) }
|
||||
#define OPA_PTR_T_INITIALIZER(val_) { (val_) }
|
||||
|
||||
/* Assume that loads/stores are atomic on the current platform, even though this
|
||||
may not be true at all. */
|
||||
static _opa_inline int OPA_load_int(_opa_const OPA_int_t *ptr)
|
||||
{
|
||||
return ptr->v;
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_store_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
ptr->v = val;
|
||||
}
|
||||
|
||||
static _opa_inline void *OPA_load_ptr(_opa_const OPA_ptr_t *ptr)
|
||||
{
|
||||
return ptr->v;
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_store_ptr(OPA_ptr_t *ptr, void *val)
|
||||
{
|
||||
ptr->v = val;
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_load_acquire_int(_opa_const OPA_int_t *ptr)
|
||||
{
|
||||
volatile int i = 0;
|
||||
int tmp;
|
||||
tmp = ptr->v;
|
||||
__sync_lock_test_and_set(&i, 1); /* guarantees acquire semantics */
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_store_release_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
volatile int i = 1;
|
||||
__sync_lock_release(&i); /* guarantees release semantics */
|
||||
ptr->v = val;
|
||||
}
|
||||
|
||||
static _opa_inline void *OPA_load_acquire_ptr(_opa_const OPA_ptr_t *ptr)
|
||||
{
|
||||
volatile int i = 0;
|
||||
void *tmp;
|
||||
tmp = ptr->v;
|
||||
__sync_lock_test_and_set(&i, 1); /* guarantees acquire semantics */
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_store_release_ptr(OPA_ptr_t *ptr, void *val)
|
||||
{
|
||||
volatile int i = 1;
|
||||
__sync_lock_release(&i); /* guarantees release semantics */
|
||||
ptr->v = val;
|
||||
}
|
||||
|
||||
|
||||
/* gcc atomic intrinsics accept an optional list of variables to be
|
||||
protected by a memory barrier. These variables are labeled
|
||||
below by "protected variables :". */
|
||||
|
||||
static _opa_inline int OPA_fetch_and_add_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
return __sync_fetch_and_add(&ptr->v, val, /* protected variables: */ &ptr->v);
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_decr_and_test_int(OPA_int_t *ptr)
|
||||
{
|
||||
return __sync_sub_and_fetch(&ptr->v, 1, /* protected variables: */ &ptr->v) == 0;
|
||||
}
|
||||
|
||||
#define OPA_fetch_and_incr_int_by_faa OPA_fetch_and_incr_int
|
||||
#define OPA_fetch_and_decr_int_by_faa OPA_fetch_and_decr_int
|
||||
#define OPA_add_int_by_faa OPA_add_int
|
||||
#define OPA_incr_int_by_fai OPA_incr_int
|
||||
#define OPA_decr_int_by_fad OPA_decr_int
|
||||
|
||||
|
||||
static _opa_inline void *OPA_cas_ptr(OPA_ptr_t *ptr, void *oldv, void *newv)
|
||||
{
|
||||
return __sync_val_compare_and_swap(&ptr->v, oldv, newv, /* protected variables: */ &ptr->v);
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_cas_int(OPA_int_t *ptr, int oldv, int newv)
|
||||
{
|
||||
return __sync_val_compare_and_swap(&ptr->v, oldv, newv, /* protected variables: */ &ptr->v);
|
||||
}
|
||||
|
||||
#ifdef SYNC_LOCK_TEST_AND_SET_IS_SWAP
|
||||
static _opa_inline void *OPA_swap_ptr(OPA_ptr_t *ptr, void *val)
|
||||
{
|
||||
return __sync_lock_test_and_set(&ptr->v, val, /* protected variables: */ &ptr->v);
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_swap_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
return __sync_lock_test_and_set(&ptr->v, val, /* protected variables: */ &ptr->v);
|
||||
}
|
||||
|
||||
#else
|
||||
#define OPA_swap_ptr_by_cas OPA_swap_ptr
|
||||
#define OPA_swap_int_by_cas OPA_swap_int
|
||||
#endif
|
||||
|
||||
#define OPA_write_barrier() __sync_synchronize()
|
||||
#define OPA_read_barrier() __sync_synchronize()
|
||||
#define OPA_read_write_barrier() __sync_synchronize()
|
||||
#define OPA_compiler_barrier() __asm__ __volatile__ ( "" ::: "memory" )
|
||||
|
||||
|
||||
|
||||
#include"opa_emulated.h"
|
||||
|
||||
#endif /* OPA_GCC_INTRINSICS_H_INCLUDED */
|
||||
@@ -1,180 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
|
||||
/*
|
||||
* (C) 2008 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef OPA_GCC_PPC_H_INCLUDED
|
||||
#define OPA_GCC_PPC_H_INCLUDED
|
||||
|
||||
/* these need to be aligned on an 8-byte boundary to work on a BG/P */
|
||||
typedef struct { volatile int v OPA_ATTRIBUTE((aligned (8))); } OPA_int_t;
|
||||
typedef struct { void * volatile v OPA_ATTRIBUTE((aligned (8))); } OPA_ptr_t;
|
||||
|
||||
#define OPA_INT_T_INITIALIZER(val_) { (val_) }
|
||||
#define OPA_PTR_T_INITIALIZER(val_) { (val_) }
|
||||
|
||||
/* Aligned loads and stores are atomic. */
|
||||
static _opa_inline int OPA_load_int(_opa_const OPA_int_t *ptr)
|
||||
{
|
||||
return ptr->v;
|
||||
}
|
||||
|
||||
/* Aligned loads and stores are atomic. */
|
||||
static _opa_inline void OPA_store_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
ptr->v = val;
|
||||
}
|
||||
|
||||
/* Aligned loads and stores are atomic. */
|
||||
static _opa_inline void *OPA_load_ptr(_opa_const OPA_ptr_t *ptr)
|
||||
{
|
||||
return ptr->v;
|
||||
}
|
||||
|
||||
/* Aligned loads and stores are atomic. */
|
||||
static _opa_inline void OPA_store_ptr(OPA_ptr_t *ptr, void *val)
|
||||
{
|
||||
ptr->v = val;
|
||||
}
|
||||
|
||||
/* a useful link for PPC memory ordering issues:
|
||||
* http://www.rdrop.com/users/paulmck/scalability/paper/N2745r.2009.02.22a.html
|
||||
*
|
||||
* lwsync: orders L-L, S-S, L-S, but *not* S-L (i.e. gives x86-ish ordering)
|
||||
* eieio: orders S-S (but only for cacheable memory, not for MMIO)
|
||||
* sync: totally orders memops
|
||||
* isync: force all preceeding insns to appear complete before starting
|
||||
* subsequent insns, but w/o cumulativity (very confusing)
|
||||
*/
|
||||
/* helper macros */
|
||||
#define OPA_ppc_lwsync_() __asm__ __volatile__ ( "lwsync" ::: "memory" )
|
||||
#define OPA_ppc_hwsync_() __asm__ __volatile__ ( "sync" ::: "memory" )
|
||||
#define OPA_ppc_eieio_() __asm__ __volatile__ ( "eieio" ::: "memory" )
|
||||
|
||||
#define OPA_write_barrier() OPA_ppc_eieio_()
|
||||
#define OPA_read_barrier() OPA_ppc_lwsync_()
|
||||
#define OPA_read_write_barrier() OPA_ppc_hwsync_()
|
||||
#define OPA_compiler_barrier() __asm__ __volatile__ ( "" ::: "memory" )
|
||||
|
||||
/* NOTE-PPC-1 we use lwsync, although I think we might be able to use
|
||||
* conditional-branch+isync in some cases (load_acquire?) once we understand it
|
||||
* better */
|
||||
|
||||
static _opa_inline int OPA_load_acquire_int(_opa_const OPA_int_t *ptr)
|
||||
{
|
||||
int tmp;
|
||||
tmp = ptr->v;
|
||||
OPA_ppc_lwsync_(); /* NOTE-PPC-1 */
|
||||
return tmp;
|
||||
}
|
||||
static _opa_inline void OPA_store_release_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
OPA_ppc_lwsync_();
|
||||
ptr->v = val;
|
||||
}
|
||||
static _opa_inline void *OPA_load_acquire_ptr(_opa_const OPA_ptr_t *ptr)
|
||||
{
|
||||
void *tmp;
|
||||
tmp = ptr->v;
|
||||
OPA_ppc_lwsync_(); /* NOTE-PPC-1 */
|
||||
return tmp;
|
||||
}
|
||||
static _opa_inline void OPA_store_release_ptr(OPA_ptr_t *ptr, void *val)
|
||||
{
|
||||
OPA_ppc_lwsync_();
|
||||
ptr->v = val;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
load-link/store-conditional (LL/SC) primitives. We LL/SC implement
|
||||
these here, which are arch-specific, then use the generic
|
||||
implementations from opa_emulated.h */
|
||||
|
||||
static _opa_inline int OPA_LL_int(OPA_int_t *ptr)
|
||||
{
|
||||
int val;
|
||||
__asm__ __volatile__ ("lwarx %[val],0,%[ptr]"
|
||||
: [val] "=r" (val)
|
||||
: [ptr] "r" (&ptr->v)
|
||||
: "cc");
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/* Returns non-zero if the store was successful, zero otherwise. */
|
||||
static _opa_inline int OPA_SC_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
int ret = 1; /* init to non-zero, will be reset to 0 if SC was unsuccessful */
|
||||
__asm__ __volatile__ ("stwcx. %[val],0,%[ptr];\n"
|
||||
"beq 1f;\n"
|
||||
"li %[ret], 0;\n"
|
||||
"1: ;\n"
|
||||
: [ret] "=r" (ret)
|
||||
: [ptr] "r" (&ptr->v), [val] "r" (val), "0" (ret)
|
||||
: "cc", "memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Pointer versions of LL/SC. */
|
||||
|
||||
/* Set OPA_SS (Size Suffix) which is used to choose between lwarx/stwcx and
|
||||
* ldarx/stdcx when using 4 or 8 byte pointer operands */
|
||||
#if OPA_SIZEOF_VOID_P == 4
|
||||
#define OPA_SS "w"
|
||||
#elif OPA_SIZEOF_VOID_P == 8
|
||||
#define OPA_SS "d"
|
||||
#else
|
||||
#error OPA_SIZEOF_VOID_P is not 4 or 8
|
||||
#endif
|
||||
|
||||
|
||||
static _opa_inline void *OPA_LL_ptr(OPA_ptr_t *ptr)
|
||||
{
|
||||
void *val;
|
||||
__asm__ __volatile__ ("l"OPA_SS"arx %[val],0,%[ptr]"
|
||||
: [val] "=r" (val)
|
||||
: [ptr] "r" (&ptr->v)
|
||||
: "cc");
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/* Returns non-zero if the store was successful, zero otherwise. */
|
||||
static _opa_inline int OPA_SC_ptr(OPA_ptr_t *ptr, void *val)
|
||||
{
|
||||
int ret = 1; /* init to non-zero, will be reset to 0 if SC was unsuccessful */
|
||||
__asm__ __volatile__ ("st"OPA_SS"cx. %[val],0,%[ptr];\n"
|
||||
"beq 1f;\n"
|
||||
"li %[ret], 0;\n"
|
||||
"1: ;\n"
|
||||
: [ret] "=r" (ret)
|
||||
: [ptr] "r" (&ptr->v), [val] "r" (val), "0" (ret)
|
||||
: "cc", "memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
#undef OPA_SS
|
||||
|
||||
/* necessary to enable LL/SC emulation support */
|
||||
#define OPA_LL_SC_SUPPORTED 1
|
||||
|
||||
/* Implement all function using LL/SC */
|
||||
#define OPA_add_int_by_llsc OPA_add_int
|
||||
#define OPA_incr_int_by_llsc OPA_incr_int
|
||||
#define OPA_decr_int_by_llsc OPA_decr_int
|
||||
#define OPA_decr_and_test_int_by_llsc OPA_decr_and_test_int
|
||||
#define OPA_fetch_and_add_int_by_llsc OPA_fetch_and_add_int
|
||||
#define OPA_fetch_and_decr_int_by_llsc OPA_fetch_and_decr_int
|
||||
#define OPA_fetch_and_incr_int_by_llsc OPA_fetch_and_incr_int
|
||||
#define OPA_cas_ptr_by_llsc OPA_cas_ptr
|
||||
#define OPA_cas_int_by_llsc OPA_cas_int
|
||||
#define OPA_swap_ptr_by_llsc OPA_swap_ptr
|
||||
#define OPA_swap_int_by_llsc OPA_swap_int
|
||||
|
||||
|
||||
#include "opa_emulated.h"
|
||||
|
||||
#endif /* OPA_GCC_PPC_H_INCLUDED */
|
||||
@@ -1,443 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
|
||||
/*
|
||||
* (C) 2008 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
|
||||
/* Atomic primitives for SiCortex machines.
|
||||
* Originally contributed by Lawrence Stewart at SiCortex.
|
||||
*/
|
||||
|
||||
#ifndef OPA_GCC_SICORTEX_H
|
||||
#define OPA_GCC_SICORTEX_H
|
||||
|
||||
/* FIXME do these need alignment? */
|
||||
typedef struct { volatile int v; } OPA_int_t;
|
||||
typedef struct { int * volatile v; } OPA_ptr_t;
|
||||
|
||||
#define OPA_INT_T_INITIALIZER(val_) { (val_) }
|
||||
#define OPA_PTR_T_INITIALIZER(val_) { (val_) }
|
||||
|
||||
#define OPA_write_barrier() __asm__ __volatile__ ("sync" ::: "memory" )
|
||||
#define OPA_read_barrier() __asm__ __volatile__ ("sync" ::: "memory" )
|
||||
#define OPA_read_write_barrier() __asm__ __volatile__ ("sync" ::: "memory" )
|
||||
#define OPA_compiler_barrier() __asm__ __volatile__ ( "" ::: "memory" )
|
||||
|
||||
/* Aligned loads and stores are atomic. */
|
||||
static _opa_inline int OPA_load_int(_opa_const OPA_int_t *ptr)
|
||||
{
|
||||
return ptr->v;
|
||||
}
|
||||
|
||||
/* Aligned loads and stores are atomic. */
|
||||
static _opa_inline void OPA_store_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
ptr->v = val;
|
||||
}
|
||||
|
||||
/* Aligned loads and stores are atomic. */
|
||||
static _opa_inline void *OPA_load_ptr(_opa_const OPA_ptr_t *ptr)
|
||||
{
|
||||
return ptr->v;
|
||||
}
|
||||
|
||||
/* Aligned loads and stores are atomic. */
|
||||
static _opa_inline void OPA_store_ptr(OPA_ptr_t *ptr, void *val)
|
||||
{
|
||||
ptr->v = val;
|
||||
}
|
||||
|
||||
/* NOTE: these acquire/release operations have not been optimized, I just threw
|
||||
* down a full memory barrier. Spending much time working on the SiCortex platform
|
||||
* doesn't really make a lot of sense since there are so few machines in
|
||||
* existence and no more will ever be built. */
|
||||
static _opa_inline int OPA_load_acquire_int(_opa_const OPA_int_t *ptr)
|
||||
{
|
||||
int tmp;
|
||||
tmp = ptr->v;
|
||||
OPA_read_write_barrier();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_store_release_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
OPA_read_write_barrier();
|
||||
ptr->v = val;
|
||||
}
|
||||
|
||||
static _opa_inline void *OPA_load_acquire_ptr(_opa_const OPA_ptr_t *ptr)
|
||||
{
|
||||
void *tmp;
|
||||
tmp = ptr->v;
|
||||
OPA_read_write_barrier();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_store_release_ptr(OPA_ptr_t *ptr, void *val)
|
||||
{
|
||||
OPA_read_write_barrier();
|
||||
ptr->v = val;
|
||||
}
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* ICE9 rev A1 chips have a low-frequency bug that causes LL to
|
||||
fail. The workaround is to do the LL twice to make sure the data
|
||||
is in L1
|
||||
|
||||
very few systems are affected
|
||||
|
||||
FIXME We should either remove the workaround entirely or make it
|
||||
configurable/autodetected somehow. [goodell@ 2008/01/06]
|
||||
*/
|
||||
#define ICE9A_LLSC_WAR 0
|
||||
|
||||
/* For a description of the _opa_inline assembly constraints, see the MIPS section of:
|
||||
http://gcc.gnu.org/onlinedocs/gcc-4.3.2/gcc/Machine-Constraints.html#Machine-Constraints
|
||||
|
||||
relevant excerpt:
|
||||
I - A signed 16-bit constant (for arithmetic instructions).
|
||||
J - Integer zero.
|
||||
|
||||
Other _opa_inline asm knowledge worth remembering:
|
||||
r - a general register operand is allowed
|
||||
m - a memory address operand
|
||||
& - earlyclobber; operand is modified before instruction is finished using the input operands
|
||||
= - this operand is write-only
|
||||
|
||||
general format:
|
||||
asm volatile ("instructions" : [outputs] : [inputs] : [clobbered_regs]);
|
||||
"memory" should be included as a clobbered reg for most of these operations.
|
||||
*/
|
||||
|
||||
/* Atomic increment of a 32 bit value, returning the old value */
|
||||
static _opa_inline int OPA_shmemi_fetch_add_4(volatile int * v, int inc)
|
||||
{
|
||||
unsigned long result;
|
||||
if (ICE9A_LLSC_WAR) {
|
||||
unsigned long temp;
|
||||
|
||||
__asm__ __volatile__(
|
||||
" .set mips3 \n"
|
||||
" .set noreorder \n"
|
||||
"1: ll %0, %2 # fetch_add_4 \n"
|
||||
" ll %0, %2 # fetch_add_4 \n"
|
||||
" addu %1, %0, %3 \n"
|
||||
" sc %1, %2 \n"
|
||||
" beqz %1, 1b \n"
|
||||
" nop \n"
|
||||
" .set reorder \n"
|
||||
" .set mips0 \n"
|
||||
: "=&r" (result), "=&r" (temp), "=m" (*v)
|
||||
: "Ir" (inc)
|
||||
: "memory");
|
||||
} else {
|
||||
unsigned long temp;
|
||||
|
||||
__asm__ __volatile__(
|
||||
" .set mips3 \n"
|
||||
" .set noreorder \n"
|
||||
"1: ll %0, %2 # fetch_add_4 \n"
|
||||
" addu %1, %0, %3 \n"
|
||||
" sc %1, %2 \n"
|
||||
" beqz %1, 1b \n"
|
||||
" nop \n"
|
||||
" .set reorder \n"
|
||||
" .set mips0 \n"
|
||||
: "=&r" (result), "=&r" (temp), "=m" (*v)
|
||||
: "Ir" (inc)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Atomic increment of a 64 bit value, returning the old value */
|
||||
static _opa_inline long int OPA_shmemi_fetch_add_8(volatile long int * v, long int inc)
|
||||
{
|
||||
unsigned long result;
|
||||
if (ICE9A_LLSC_WAR) {
|
||||
unsigned long temp;
|
||||
|
||||
__asm__ __volatile__(
|
||||
" .set mips3 \n"
|
||||
" .set noreorder \n"
|
||||
"1: lld %0, %2 # fetch_add_8 \n"
|
||||
" lld %0, %2 # fetch_add_8 \n"
|
||||
" daddu %1, %0, %3 \n"
|
||||
" scd %1, %2 \n"
|
||||
" beqz %1, 1b \n"
|
||||
" nop \n"
|
||||
" .set reorder \n"
|
||||
" .set mips0 \n"
|
||||
: "=&r" (result), "=&r" (temp), "=m" (*v)
|
||||
: "Ir" (inc)
|
||||
: "memory");
|
||||
} else {
|
||||
unsigned long temp;
|
||||
|
||||
__asm__ __volatile__(
|
||||
" .set mips3 \n"
|
||||
" .set noreorder \n"
|
||||
"1: lld %0, %2 # fetch_add_8 \n"
|
||||
" daddu %1, %0, %3 \n"
|
||||
" scd %1, %2 \n"
|
||||
" beqz %1, 1b \n"
|
||||
" nop \n"
|
||||
" .set reorder \n"
|
||||
" .set mips0 \n"
|
||||
: "=&r" (result), "=&r" (temp), "=m" (*v)
|
||||
: "Ir" (inc)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Atomic swap of a 32 bit value, returning the old contents */
|
||||
static _opa_inline int OPA_shmemi_swap_4(volatile int * v, int val)
|
||||
{
|
||||
unsigned long result;
|
||||
if (ICE9A_LLSC_WAR) {
|
||||
unsigned long temp;
|
||||
|
||||
__asm__ __volatile__(
|
||||
" .set mips3 \n"
|
||||
" .set noreorder \n"
|
||||
"1: ll %0, %2 # swap_4 \n"
|
||||
" ll %0, %2 # swap_4 \n"
|
||||
" move %1, %3 \n"
|
||||
" sc %1, %2 \n"
|
||||
" beqz %1, 1b \n"
|
||||
" nop \n"
|
||||
" .set reorder \n"
|
||||
" .set mips0 \n"
|
||||
: "=&r" (result), "=&r" (temp), "=m" (*v)
|
||||
: "r" (val)
|
||||
: "memory");
|
||||
} else {
|
||||
unsigned long temp;
|
||||
|
||||
__asm__ __volatile__(
|
||||
" .set mips3 \n"
|
||||
" .set noreorder \n"
|
||||
"1: ll %0, %2 # swap_4 \n"
|
||||
" move %1, %3 \n"
|
||||
" sc %1, %2 \n"
|
||||
" beqz %1, 1b \n"
|
||||
" nop \n"
|
||||
" .set reorder \n"
|
||||
" .set mips0 \n"
|
||||
: "=&r" (result), "=&r" (temp), "=m" (*v)
|
||||
: "r" (val)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Atomic swap of a 64 bit value, returning the old contents */
|
||||
static _opa_inline long int OPA_shmemi_swap_8(volatile long int * v, long int val)
|
||||
{
|
||||
unsigned long result;
|
||||
if (ICE9A_LLSC_WAR) {
|
||||
unsigned long temp;
|
||||
|
||||
__asm__ __volatile__(
|
||||
" .set mips3 \n"
|
||||
" .set noreorder \n"
|
||||
"1: lld %0, %2 # swap_8 \n"
|
||||
" lld %0, %2 # swap_8 \n"
|
||||
" move %1, %3 \n"
|
||||
" scd %1, %2 \n"
|
||||
" beqz %1, 1b \n"
|
||||
" nop \n"
|
||||
" .set reorder \n"
|
||||
" .set mips0 \n"
|
||||
: "=&r" (result), "=&r" (temp), "=m" (*v)
|
||||
: "r" (val)
|
||||
: "memory");
|
||||
} else {
|
||||
unsigned long temp;
|
||||
|
||||
__asm__ __volatile__(
|
||||
" .set mips3 \n"
|
||||
" .set noreorder \n"
|
||||
"1: lld %0, %2 # swap_8 \n"
|
||||
" move %1, %3 \n"
|
||||
" scd %1, %2 \n"
|
||||
" beqz %1, 1b \n"
|
||||
" nop \n"
|
||||
" .set reorder \n"
|
||||
" .set mips0 \n"
|
||||
: "=&r" (result), "=&r" (temp), "=m" (*v)
|
||||
: "r" (val)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Atomic compare and swap of a 32 bit value, returns the old value
|
||||
* but only does the store of the val value if the old value == expect */
|
||||
static _opa_inline int OPA_shmemi_cswap_4(volatile int * v, int expect, int val)
|
||||
{
|
||||
unsigned long result;
|
||||
if (ICE9A_LLSC_WAR) {
|
||||
unsigned long temp;
|
||||
|
||||
__asm__ __volatile__(
|
||||
" .set mips3 \n"
|
||||
" .set noreorder \n"
|
||||
"1: ll %0, %2 # cswap_4 \n"
|
||||
" ll %0, %2 # cswap_4 \n"
|
||||
" bne %0, %4, 1f \n"
|
||||
" move %1, %3 \n"
|
||||
" sc %1, %2 \n"
|
||||
" beqz %1, 1b \n"
|
||||
" nop \n"
|
||||
" .set reorder \n"
|
||||
"1: \n"
|
||||
" .set mips0 \n"
|
||||
: "=&r" (result), "=&r" (temp), "=m" (*v)
|
||||
: "r" (val), "Jr" (expect)
|
||||
: "memory");
|
||||
} else {
|
||||
unsigned long temp;
|
||||
|
||||
__asm__ __volatile__(
|
||||
" .set mips3 \n"
|
||||
" .set noreorder \n"
|
||||
"1: ll %0, %2 # cswap_4 \n"
|
||||
" bne %0, %4, 1f \n"
|
||||
" move %1, %3 \n"
|
||||
" sc %1, %2 \n"
|
||||
" beqz %1, 1b \n"
|
||||
" nop \n"
|
||||
" .set reorder \n"
|
||||
"1: \n"
|
||||
" .set mips0 \n"
|
||||
: "=&r" (result), "=&r" (temp), "=m" (*v)
|
||||
: "r" (val), "Jr" (expect)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Atomic compare and swap of a 64 bit value, returns the old value
|
||||
* but only does the store of the val value if the old value == expect */
|
||||
static _opa_inline long int OPA_shmemi_cswap_8(volatile long int * v, long int expect, long int val)
|
||||
{
|
||||
unsigned long result;
|
||||
if (ICE9A_LLSC_WAR) {
|
||||
unsigned long temp;
|
||||
|
||||
__asm__ __volatile__(
|
||||
" .set mips3 \n"
|
||||
" .set noreorder \n"
|
||||
"1: lld %0, %2 # cswap_8 \n"
|
||||
" lld %0, %2 # cswap_8 \n"
|
||||
" bne %0, %4, 1f \n"
|
||||
" move %1, %3 \n"
|
||||
" scd %1, %2 \n"
|
||||
" beqz %1, 1b \n"
|
||||
" nop \n"
|
||||
" .set reorder \n"
|
||||
"1: \n"
|
||||
" .set mips0 \n"
|
||||
: "=&r" (result), "=&r" (temp), "=m" (*v)
|
||||
: "r" (val), "Jr" (expect)
|
||||
: "memory");
|
||||
} else {
|
||||
unsigned long temp;
|
||||
|
||||
__asm__ __volatile__(
|
||||
" .set mips3 \n"
|
||||
" .set noreorder \n"
|
||||
"1: lld %0, %2 # cswap_8 \n"
|
||||
" bne %0, %4, 1f \n"
|
||||
" move %1, %3 \n"
|
||||
" scd %1, %2 \n"
|
||||
" beqz %1, 1b \n"
|
||||
" nop \n"
|
||||
" .set reorder \n"
|
||||
"1: \n"
|
||||
" .set mips0 \n"
|
||||
: "=&r" (result), "=&r" (temp), "=m" (*v)
|
||||
: "r" (val), "Jr" (expect)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_add_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
OPA_shmemi_fetch_add_4(&ptr->v, val);
|
||||
}
|
||||
|
||||
static _opa_inline void *OPA_cas_ptr(OPA_ptr_t *ptr, void *oldv, void *newv)
|
||||
{
|
||||
#if (OPA_SIZEOF_VOID_P == 8)
|
||||
return((int *) OPA_shmemi_cswap_8((volatile long int *) &ptr->v, (uintptr_t) oldv, (uintptr_t) newv));
|
||||
#elif (OPA_SIZEOF_VOID_P == 4)
|
||||
return((int *) OPA_shmemi_cswap_4((volatile int *) &ptr->v, (uintptr_t) oldv, (uintptr_t) newv));
|
||||
#else
|
||||
#error "OPA_SIZEOF_VOID_P has an unexpected value :" OPA_QUOTE(OPA_SIZEOF_VOID_P);
|
||||
#endif
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_cas_int(OPA_int_t *ptr, int oldv, int newv)
|
||||
{
|
||||
return(OPA_shmemi_cswap_4(&ptr->v, oldv, newv));
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_decr_int(OPA_int_t *ptr)
|
||||
{
|
||||
OPA_shmemi_fetch_add_4(&ptr->v, -1);
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_decr_and_test_int(OPA_int_t *ptr)
|
||||
{
|
||||
int old = OPA_shmemi_fetch_add_4(&ptr->v, -1);
|
||||
return (old == 1);
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_fetch_and_add_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
return(OPA_shmemi_fetch_add_4(&ptr->v, val));
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_fetch_and_decr_int(OPA_int_t *ptr)
|
||||
{
|
||||
return(OPA_shmemi_fetch_add_4(&ptr->v, -1));
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_fetch_and_incr_int(OPA_int_t *ptr)
|
||||
{
|
||||
return(OPA_shmemi_fetch_add_4(&ptr->v, 1));
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_incr_int(OPA_int_t *ptr)
|
||||
{
|
||||
OPA_shmemi_fetch_add_4(&ptr->v, 1);
|
||||
}
|
||||
|
||||
static _opa_inline int *OPA_swap_ptr(OPA_ptr_t *ptr, int *val)
|
||||
{
|
||||
#if (OPA_SIZEOF_VOID_P == 8)
|
||||
return((int *) OPA_shmemi_swap_8((volatile long int *) &ptr->v, (uintptr_t) val));
|
||||
#elif (OPA_SIZEOF_VOID_P == 4)
|
||||
return((int *) OPA_shmemi_swap_4((volatile int *) &ptr->v, (uintptr_t) val));
|
||||
#else
|
||||
#error "OPA_SIZEOF_VOID_P has an unexpected value :" OPA_QUOTE(OPA_SIZEOF_VOID_P);
|
||||
#endif
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_swap_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
return(OPA_shmemi_swap_4(&ptr->v, val));
|
||||
}
|
||||
|
||||
#endif /* OPA_GCC_SICORTEX_H */
|
||||
@@ -1,154 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
|
||||
/*
|
||||
* (C) 2008 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef OPA_NT_INTRINSICS_H_INCLUDED
|
||||
#define OPA_NT_INTRINSICS_H_INCLUDED
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include<windows.h>
|
||||
#include<intrin.h>
|
||||
#include "mpi.h"
|
||||
|
||||
/* OPA_int_t uses a long because the compiler intrinsics operate on
|
||||
* longs instead of ints. */
|
||||
typedef struct { volatile long v; } OPA_int_t;
|
||||
typedef struct { void * volatile v; } OPA_ptr_t;
|
||||
|
||||
#define OPA_INT_T_INITIALIZER(val_) { (val_) }
|
||||
#define OPA_PTR_T_INITIALIZER(val_) { (val_) }
|
||||
|
||||
#define OPA_write_barrier() _WriteBarrier()
|
||||
#define OPA_read_barrier() _ReadBarrier()
|
||||
#define OPA_read_write_barrier() _ReadWriteBarrier()
|
||||
/* FIXME there mut be a more efficient way to implement this. Is "asm {};"
|
||||
* sufficient? */
|
||||
#define OPA_compiler_barrier() _ReadWriteBarrier()
|
||||
|
||||
static _opa_inline int OPA_load_int(_opa_const OPA_int_t *ptr)
|
||||
{
|
||||
return ((int)ptr->v);
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_store_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
ptr->v = (long)val;
|
||||
}
|
||||
|
||||
static _opa_inline void *OPA_load_ptr(_opa_const OPA_ptr_t *ptr)
|
||||
{
|
||||
return ((void *)ptr->v);
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_store_ptr(OPA_ptr_t *ptr, void *val)
|
||||
{
|
||||
ptr->v = val;
|
||||
}
|
||||
|
||||
/* NOTE: these acquire/release operations have not been optimized, I just threw
|
||||
* down a full memory barrier. Someone with more Windows expertise should feel
|
||||
* free to improve these (for Windows on x86/x86_64 these almost certainly only
|
||||
* need to be compiler barriers). */
|
||||
static _opa_inline int OPA_load_acquire_int(_opa_const OPA_int_t *ptr)
|
||||
{
|
||||
int tmp;
|
||||
tmp = ptr->v;
|
||||
OPA_read_write_barrier();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_store_release_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
OPA_read_write_barrier();
|
||||
ptr->v = val;
|
||||
}
|
||||
|
||||
static _opa_inline void *OPA_load_acquire_ptr(_opa_const OPA_ptr_t *ptr)
|
||||
{
|
||||
void *tmp;
|
||||
tmp = ptr->v;
|
||||
OPA_read_write_barrier();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_store_release_ptr(OPA_ptr_t *ptr, void *val)
|
||||
{
|
||||
OPA_read_write_barrier();
|
||||
ptr->v = val;
|
||||
}
|
||||
|
||||
|
||||
static _opa_inline void OPA_add_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
_InterlockedExchangeAdd(&(ptr->v), val);
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_incr_int(OPA_int_t *ptr)
|
||||
{
|
||||
_InterlockedIncrement(&(ptr->v));
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_decr_int(OPA_int_t *ptr)
|
||||
{
|
||||
_InterlockedDecrement(&(ptr->v));
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_decr_and_test_int(OPA_int_t *ptr)
|
||||
{
|
||||
return (_InterlockedDecrement(&(ptr->v)) == 0);
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_fetch_and_add_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
return ((int)_InterlockedExchangeAdd(&(ptr->v), (long)val));
|
||||
}
|
||||
|
||||
static _opa_inline void *OPA_cas_ptr(OPA_ptr_t *ptr, void *oldv, void *newv)
|
||||
{
|
||||
#if (OPA_SIZEOF_VOID_P == 4)
|
||||
return ((void *)(LONG_PTR) _InterlockedCompareExchange((LONG volatile *)&(ptr->v),
|
||||
(LONG)(LONG_PTR)newv,
|
||||
(LONG)(LONG_PTR)oldv)
|
||||
);
|
||||
#elif (OPA_SIZEOF_VOID_P == 8)
|
||||
return ((void *)(LONG_PTR)_InterlockedCompareExchange64((__int64 *)&(ptr->v),
|
||||
(INT64)(LONG_PTR)newv,
|
||||
(INT64)(LONG_PTR)oldv)
|
||||
);
|
||||
#else
|
||||
#error "OPA_SIZEOF_VOID_P not valid"
|
||||
#endif
|
||||
}
|
||||
|
||||
static _opa_inline void *OPA_swap_ptr(OPA_ptr_t *ptr, void *val)
|
||||
{
|
||||
#if (OPA_SIZEOF_VOID_P == 4)
|
||||
return (void *)(LONG_PTR )_InterlockedExchange((LONG volatile *)&(ptr->v),
|
||||
(LONG)(LONG_PTR)val);
|
||||
#elif (OPA_SIZEOF_VOID_P == 8)
|
||||
return (void *)(LONG_PTR)_InterlockedExchange64((LONG64 volatile *)&(ptr->v),
|
||||
(INT64)(LONG_PTR)val);
|
||||
#else
|
||||
#error "OPA_SIZEOF_VOID_P not valid"
|
||||
#endif
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_cas_int(OPA_int_t *ptr, int oldv, int newv)
|
||||
{
|
||||
return _InterlockedCompareExchange((long *)&(ptr->v), newv, oldv);
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_swap_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
return _InterlockedExchange(&(ptr->v), val);
|
||||
}
|
||||
|
||||
/* Implement fetch_and_incr/decr using fetch_and_add (*_faa) */
|
||||
#define OPA_fetch_and_incr_int_by_faa OPA_fetch_and_incr_int
|
||||
#define OPA_fetch_and_decr_int_by_faa OPA_fetch_and_decr_int
|
||||
|
||||
#include "opa_emulated.h"
|
||||
|
||||
#endif /* defined(OPA_NT_INTRINSICS_H_INCLUDED) */
|
||||
@@ -1,135 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
|
||||
/*
|
||||
* (C) 2008 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef OPA_SUN_ATOMIC_OPS_H_INCLUDED
|
||||
#define OPA_SUN_ATOMIC_OPS_H_INCLUDED
|
||||
|
||||
#include <atomic.h>
|
||||
|
||||
typedef struct { volatile uint_t v; } OPA_int_t;
|
||||
typedef struct { void * volatile v; } OPA_ptr_t;
|
||||
|
||||
#define OPA_INT_T_INITIALIZER(val_) { (val_) }
|
||||
#define OPA_PTR_T_INITIALIZER(val_) { (val_) }
|
||||
|
||||
static _opa_inline int OPA_load_int(_opa_const OPA_int_t *ptr)
|
||||
{
|
||||
return (int)ptr->v;
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_store_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
ptr->v = (uint)val;
|
||||
}
|
||||
|
||||
static _opa_inline void *OPA_load_ptr(_opa_const OPA_ptr_t *ptr)
|
||||
{
|
||||
return ptr->v;
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_store_ptr(OPA_ptr_t *ptr, void *val)
|
||||
{
|
||||
ptr->v = val;
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_load_acquire_int(_opa_const OPA_int_t *ptr)
|
||||
{
|
||||
int tmp;
|
||||
tmp = ptr->v;
|
||||
membar_enter();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_store_release_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
membar_exit();
|
||||
ptr->v = val;
|
||||
}
|
||||
|
||||
static _opa_inline void *OPA_load_acquire_ptr(_opa_const OPA_ptr_t *ptr)
|
||||
{
|
||||
void *tmp;
|
||||
tmp = ptr->v;
|
||||
membar_enter();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_store_release_ptr(OPA_ptr_t *ptr, void *val)
|
||||
{
|
||||
membar_exit();
|
||||
ptr->v = val;
|
||||
}
|
||||
|
||||
|
||||
static _opa_inline void OPA_add_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
atomic_add_int(&ptr->v, val);
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_incr_int(OPA_int_t *ptr)
|
||||
{
|
||||
atomic_inc_uint(&ptr->v);
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_decr_int(OPA_int_t *ptr)
|
||||
{
|
||||
atomic_dec_uint(&ptr->v);
|
||||
}
|
||||
|
||||
|
||||
static _opa_inline int OPA_decr_and_test_int(OPA_int_t *ptr)
|
||||
{
|
||||
return atomic_dec_uint_nv(&ptr->v) == 0;
|
||||
}
|
||||
|
||||
|
||||
static _opa_inline int OPA_fetch_and_add_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
return (int)atomic_add_int_nv(&ptr->v, val) - val;
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_fetch_and_decr_int(OPA_int_t *ptr)
|
||||
{
|
||||
return (int)atomic_dec_uint_nv(&ptr->v) + 1;
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_fetch_and_incr_int(OPA_int_t *ptr)
|
||||
{
|
||||
return (int)atomic_inc_uint_nv(&ptr->v) - 1;
|
||||
}
|
||||
|
||||
|
||||
static _opa_inline void *OPA_cas_ptr(OPA_ptr_t *ptr, void *oldv, void *newv)
|
||||
{
|
||||
return atomic_cas_ptr(ptr, oldv, newv);
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_cas_int(OPA_int_t *ptr, int oldv, int newv)
|
||||
{
|
||||
return (int)atomic_cas_uint(&ptr->v, (uint_t)oldv, (uint_t)newv);
|
||||
}
|
||||
|
||||
|
||||
static _opa_inline void *OPA_swap_ptr(OPA_ptr_t *ptr, void *val)
|
||||
{
|
||||
return atomic_swap_ptr(ptr, val);
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_swap_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
return (int)atomic_swap_uint(&ptr->v, (uint_t) val);
|
||||
}
|
||||
|
||||
|
||||
#define OPA_write_barrier() membar_producer()
|
||||
#define OPA_read_barrier() membar_consumer()
|
||||
#define OPA_read_write_barrier() do { membar_consumer(); membar_producer(); } while (0)
|
||||
|
||||
/* is this portable enough? */
|
||||
#define OPA_compiler_barrier() __asm__ __volatile__ ( "" ::: "memory" )
|
||||
|
||||
#endif /* OPA_SUN_ATOMIC_OPS_H_INCLUDED */
|
||||
@@ -1,152 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
|
||||
/*
|
||||
* (C) 2008 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef OPA_UNSAFE_H_INCLUDED
|
||||
#define OPA_UNSAFE_H_INCLUDED
|
||||
|
||||
/* NOTE: These types intentionally do not use volatile in order to provide even
|
||||
* better performance. If a good use case for having unsafe operations with
|
||||
* volatile types comes up, we can make two definitions that are conditional on
|
||||
* something sort of like NDEBUG. [goodell@ 2009-08-18] */
|
||||
typedef struct { int v; } OPA_int_t;
|
||||
typedef struct { int *v; } OPA_ptr_t;
|
||||
|
||||
#define OPA_INT_T_INITIALIZER(val_) { (val_) }
|
||||
#define OPA_PTR_T_INITIALIZER(val_) { (val_) }
|
||||
|
||||
/*
|
||||
Unsafe Primitives
|
||||
-----------------
|
||||
|
||||
These are versions of the atomic primitives that emulate the single-threaded
|
||||
behavior of the primitives but do not attempt to provide any safety against
|
||||
concurrent use. The primary use case for this implementation is to avoid
|
||||
overhead without code changes in client libraries and applications that have
|
||||
been compiled for single-threaded use only. They might also be useful for
|
||||
testing (and testing of tests) in some cases.
|
||||
|
||||
Thanks to Josh Haberman for inspiring this primitives implementation.
|
||||
*/
|
||||
|
||||
static _opa_inline int OPA_load_int(const OPA_int_t *ptr)
|
||||
{
|
||||
int retval;
|
||||
retval = ptr->v;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_store_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
ptr->v = val;
|
||||
}
|
||||
|
||||
static _opa_inline void *OPA_load_ptr(const OPA_ptr_t *ptr)
|
||||
{
|
||||
int *retval;
|
||||
retval = ptr->v;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_store_ptr(OPA_ptr_t *ptr, void *val)
|
||||
{
|
||||
ptr->v = val;
|
||||
}
|
||||
|
||||
/* no barrier needed, not even a compiler barrier */
|
||||
#define OPA_load_acquire_int(ptr_) OPA_load_int((ptr_))
|
||||
#define OPA_store_release_int(ptr_,val_) OPA_store_int((ptr_),(val_))
|
||||
#define OPA_load_acquire_ptr(ptr_) OPA_load_ptr((ptr_))
|
||||
#define OPA_store_release_ptr(ptr_,val_) OPA_store_ptr((ptr_),(val_))
|
||||
|
||||
static _opa_inline void OPA_add_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
ptr->v += val;
|
||||
}
|
||||
|
||||
static _opa_inline void *OPA_cas_ptr(OPA_ptr_t *ptr, int *oldv, int *newv)
|
||||
{
|
||||
int *prev;
|
||||
prev = ptr->v;
|
||||
if (prev == oldv) {
|
||||
ptr->v = newv;
|
||||
}
|
||||
return prev;
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_cas_int(OPA_int_t *ptr, int oldv, int newv)
|
||||
{
|
||||
int prev;
|
||||
prev = ptr->v;
|
||||
if (prev == oldv) {
|
||||
ptr->v = newv;
|
||||
}
|
||||
return prev;
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_decr_and_test_int(OPA_int_t *ptr)
|
||||
{
|
||||
int new_val;
|
||||
new_val = --(ptr->v);
|
||||
return (0 == new_val);
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_decr_int(OPA_int_t *ptr)
|
||||
{
|
||||
--(ptr->v);
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_fetch_and_add_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
int prev;
|
||||
prev = ptr->v;
|
||||
ptr->v += val;
|
||||
return prev;
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_fetch_and_decr_int(OPA_int_t *ptr)
|
||||
{
|
||||
int prev;
|
||||
prev = ptr->v;
|
||||
--(ptr->v);
|
||||
return prev;
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_fetch_and_incr_int(OPA_int_t *ptr)
|
||||
{
|
||||
int prev;
|
||||
prev = ptr->v;
|
||||
++(ptr->v);
|
||||
return prev;
|
||||
}
|
||||
|
||||
static _opa_inline void OPA_incr_int(OPA_int_t *ptr)
|
||||
{
|
||||
++(ptr->v);
|
||||
}
|
||||
|
||||
static _opa_inline void *OPA_swap_ptr(OPA_ptr_t *ptr, void *val)
|
||||
{
|
||||
int *prev;
|
||||
prev = ptr->v;
|
||||
ptr->v = val;
|
||||
return prev;
|
||||
}
|
||||
|
||||
static _opa_inline int OPA_swap_int(OPA_int_t *ptr, int val)
|
||||
{
|
||||
int prev;
|
||||
prev = ptr->v;
|
||||
ptr->v = val;
|
||||
return (int)prev;
|
||||
}
|
||||
|
||||
/* null barriers */
|
||||
#define OPA_write_barrier() do {} while (0)
|
||||
#define OPA_read_barrier() do {} while (0)
|
||||
#define OPA_read_write_barrier() do {} while (0)
|
||||
#define OPA_compiler_barrier() do {} while (0)
|
||||
|
||||
#endif /* !defined(OPA_UNSAFE_H_INCLUDED) */
|
||||
Reference in New Issue
Block a user