Initial commit

This commit is contained in:
Bassem Girgis
2018-12-20 17:34:07 -06:00
parent 7a2d899662
commit 81b4b9e273
34743 changed files with 5940233 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,535 @@
/* -*- Mode: C; c-basic-offset:4 ; -*- */
/*
*
* Copyright (C) 1997 University of Chicago.
* See COPYRIGHT notice in top-level directory.
*/
/* user include file for MPI-IO programs */
#ifndef MPIO_INCLUDE
#define MPIO_INCLUDE
#include "mpi.h"
#if defined(__cplusplus)
extern "C" {
#endif
#define ROMIO_VERSION 126 /* version 1.2.6 */
/* define MPI-IO datatypes and constants */
#ifndef MPI_FILE_DEFINED
typedef struct ADIOI_FileD *MPI_File;
#endif
#define HAVE_MPI_GREQUEST 1
#ifndef HAVE_MPI_GREQUEST
typedef struct ADIOI_RequestD *MPIO_Request;
#else
#define MPIO_Request MPI_Request
#define MPIO_USES_MPI_REQUEST
/* Also rename the MPIO routines to get the MPI versions */
#define MPIO_Wait MPI_Wait
#define MPIO_Test MPI_Test
#define PMPIO_Wait PMPI_Wait
#define PMPIO_Test PMPI_Test
#endif
#define MPIO_REQUEST_DEFINED
#ifndef HAVE_MPI_OFFSET
typedef long long MPI_Offset;
/* If we needed to define MPI_Offset, then we also need to make
this definition. */
#ifndef HAVE_MPI_DATAREP_FUNCTIONS
#define HAVE_MPI_DATAREP_FUNCTIONS
typedef int (MPI_Datarep_conversion_function)(void *, MPI_Datatype, int,
void *, MPI_Offset, void *);
typedef int (MPI_Datarep_extent_function)(MPI_Datatype datatype, MPI_Aint *,
void *);
#endif
#endif
#ifndef NEEDS_MPI_FINT
#endif
#ifdef NEEDS_MPI_FINT
typedef int MPI_Fint;
#endif
#ifndef HAVE_MPI_INFO
#define HAVE_MPI_INFO
#endif
#ifndef HAVE_MPI_INFO
typedef struct MPIR_Info *MPI_Info;
# define MPI_INFO_NULL ((MPI_Info) 0)
# define MPI_MAX_INFO_KEY 255
# define MPI_MAX_INFO_VAL 1024
#endif
#define MPI_MODE_RDONLY 2 /* ADIO_RDONLY */
#define MPI_MODE_RDWR 8 /* ADIO_RDWR */
#define MPI_MODE_WRONLY 4 /* ADIO_WRONLY */
#define MPI_MODE_CREATE 1 /* ADIO_CREATE */
#define MPI_MODE_EXCL 64 /* ADIO_EXCL */
#define MPI_MODE_DELETE_ON_CLOSE 16 /* ADIO_DELETE_ON_CLOSE */
#define MPI_MODE_UNIQUE_OPEN 32 /* ADIO_UNIQUE_OPEN */
#define MPI_MODE_APPEND 128 /* ADIO_APPEND */
#define MPI_MODE_SEQUENTIAL 256 /* ADIO_SEQUENTIAL */
#define MPI_DISPLACEMENT_CURRENT -54278278
#ifndef MPICH
/* FIXME: Make sure that we get a consistent definition of MPI_FILE_NULL
in MPICH */
/* MPICH defines null object handles differently */
#define MPI_FILE_NULL ((MPI_File) 0)
#endif
#define MPIO_REQUEST_NULL ((MPIO_Request) 0)
#define MPI_SEEK_SET 600
#define MPI_SEEK_CUR 602
#define MPI_SEEK_END 604
/* Open MPI: don't define MPI_MAX_DATAREP_STRING here; it's defined in
OMPI's mpi.h. */
#ifndef OPEN_MPI
#define MPI_MAX_DATAREP_STRING 128
#endif
#ifndef HAVE_MPI_DARRAY_SUBARRAY
#define HAVE_MPI_DARRAY_SUBARRAY
#endif
#ifndef HAVE_MPI_DARRAY_SUBARRAY
# define MPI_ORDER_C 56
# define MPI_ORDER_FORTRAN 57
# define MPI_DISTRIBUTE_BLOCK 121
# define MPI_DISTRIBUTE_CYCLIC 122
# define MPI_DISTRIBUTE_NONE 123
# define MPI_DISTRIBUTE_DFLT_DARG -49767
#endif
/* MPI-IO function prototypes */
/* The compiler must support ANSI C style prototypes, otherwise
long long constants (e.g. 0) may get passed as ints. */
#ifndef HAVE_PRAGMA_HP_SEC_DEF
/* 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);
/* 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);
int MPI_File_get_view(MPI_File fh, MPI_Offset *disp, MPI_Datatype *etype, MPI_Datatype *filetype,
char *datarep);
/* 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);
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);
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);
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);
/* 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);
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);
/* 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);
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);
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);
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);
/* 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);
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);
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);
/* 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);
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);
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);
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);
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);
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);
/* 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);
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);
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);
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);
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);
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);
/* Section 9.5.1 */
int MPI_File_get_type_extent(MPI_File fh, MPI_Datatype datatype, MPI_Aint *extent);
/* 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);
/* 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);
/* 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);
#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);
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);
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);
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);
/* 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);
/* 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);
#endif
/* 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
should only happen if MPICH_RENAMING_MPI_FUNCS is not defined. */
/* Section 4.12.4 */
#if !defined(MPICH_RENAMING_MPI_FUNCS)
#ifdef MPI_File_f2c
#undef MPI_File_f2c
#endif
#ifdef MPI_File_c2f
#undef MPI_File_c2f
#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);
#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_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[]);
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);
int MPIO_Waitsome(int incount, MPIO_Request array_of_requests[], int *outcount,
int array_of_indices[], MPI_Status array_of_statuses[]);
int MPIO_Testsome(int incount, MPIO_Request array_of_requests[], int *outcount,
int array_of_indices[], MPI_Status array_of_statuses[]);
MPI_Fint MPIO_Request_c2f(MPIO_Request request);
MPIO_Request MPIO_Request_f2c(MPI_Fint request);
#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);
/* 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
should only happen if MPICH_RENAMING_MPI_FUNCS is not defined. */
#if !defined(MPICH_RENAMING_MPI_FUNCS)
#ifdef MPI_Info_f2c
#undef MPI_Info_f2c
#endif
#ifdef MPI_Info_c2f
#undef MPI_Info_c2f
#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);
#endif
#endif /* HAVE_PRAGMA_HP_SEC_DEF */
/**************** BINDINGS FOR THE PROFILING INTERFACE ***************/
/* 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 *);
/* Section 9.3 */
int PMPI_File_set_view(MPI_File, MPI_Offset,
MPI_Datatype, MPI_Datatype, const char *, MPI_Info);
int PMPI_File_get_view(MPI_File, MPI_Offset *,
MPI_Datatype *, MPI_Datatype *, char *);
/* 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);
int PMPI_File_read_at_all(MPI_File, MPI_Offset, void *,
int, MPI_Datatype, MPI_Status *)
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5);
int PMPI_File_write_at(MPI_File, MPI_Offset, const void *,
int, MPI_Datatype, MPI_Status *)
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5);
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);
/* 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_at(MPI_File, MPI_Offset, void *,
int, MPI_Datatype, MPIO_Request *)
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5);
int PMPI_File_iwrite_at(MPI_File, MPI_Offset, const void *,
int, MPI_Datatype, MPIO_Request *)
MPICH_ATTR_POINTER_WITH_TYPE_TAG(3,5);
/* Section 9.4.3 */
int PMPI_File_read(MPI_File, void *, int, MPI_Datatype, MPI_Status *)
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
int PMPI_File_read_all(MPI_File, void *, int, MPI_Datatype, MPI_Status *)
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
int PMPI_File_write(MPI_File, const void *, int, MPI_Datatype, MPI_Status *)
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
int PMPI_File_write_all(MPI_File, const void *, int, MPI_Datatype, MPI_Status *)
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
/* 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);
int PMPI_File_iwrite(MPI_File, const void *, int, MPI_Datatype, MPIO_Request *)
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
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 *);
/* 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);
int PMPI_File_write_shared(MPI_File, const void *, int, MPI_Datatype, MPI_Status *)
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
int PMPI_File_iread_shared(MPI_File, void *, int,
MPI_Datatype, MPIO_Request *)
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
int PMPI_File_iwrite_shared(MPI_File, const void *, int,
MPI_Datatype, MPIO_Request *)
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
int PMPI_File_read_ordered(MPI_File, void *, int, MPI_Datatype, MPI_Status *)
MPICH_ATTR_POINTER_WITH_TYPE_TAG(2,4);
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 *);
/* 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 *);
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 *);
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 *);
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 *);
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 *);
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 *);
/* Section 9.5.1 */
int PMPI_File_get_type_extent(MPI_File, MPI_Datatype, MPI_Aint *);
/* Section 9.5.3 */
int PMPI_Register_datarep(const char *,
MPI_Datarep_conversion_function *,
MPI_Datarep_conversion_function *,
MPI_Datarep_extent_function *,
void *);
/* 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);
/* 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 * );
#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);
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);
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);
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);
#ifndef HAVE_MPI_DARRAY_SUBARRAY
/* Section 4.14.4 */
int PMPI_Type_create_subarray(int, int *, int *, int *, int,
MPI_Datatype, MPI_Datatype *);
/* Section 4.14.5 */
int PMPI_Type_create_darray(int, int, int, int *, int *,
int *, int *, int, MPI_Datatype, MPI_Datatype *);
#endif
/* Section 4.12.4 */
MPI_File PMPI_File_f2c(MPI_Fint);
MPI_Fint PMPI_File_c2f(MPI_File);
#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);
#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 *);
MPI_Fint PMPI_Info_c2f(MPI_Info);
MPI_Info PMPI_Info_f2c(MPI_Fint);
#endif
#if defined(__cplusplus)
}
#endif
#endif

View File

@@ -0,0 +1,46 @@
!
! Copyright (C) 1997 University of Chicago.
! See COPYRIGHT notice in top-level directory.
!
!
! user include file for Fortran MPI-IO programs
!
INTEGER MPI_MODE_RDONLY, MPI_MODE_RDWR, MPI_MODE_WRONLY
INTEGER MPI_MODE_DELETE_ON_CLOSE, MPI_MODE_UNIQUE_OPEN
INTEGER MPI_MODE_CREATE, MPI_MODE_EXCL
INTEGER MPI_MODE_APPEND, MPI_MODE_SEQUENTIAL
PARAMETER (MPI_MODE_RDONLY=2, MPI_MODE_RDWR=8, MPI_MODE_WRONLY=4)
PARAMETER (MPI_MODE_CREATE=1, MPI_MODE_DELETE_ON_CLOSE=16)
PARAMETER (MPI_MODE_UNIQUE_OPEN=32, MPI_MODE_EXCL=64)
PARAMETER (MPI_MODE_APPEND=128, MPI_MODE_SEQUENTIAL=256)
!
INTEGER MPI_FILE_NULL
PARAMETER (MPI_FILE_NULL=0)
!
INTEGER MPI_MAX_DATAREP_STRING
PARAMETER (MPI_MAX_DATAREP_STRING=128)
!
INTEGER MPI_SEEK_SET, MPI_SEEK_CUR, MPI_SEEK_END
PARAMETER (MPI_SEEK_SET=600, MPI_SEEK_CUR=602, MPI_SEEK_END=604)
!
INTEGER MPIO_REQUEST_NULL
PARAMETER (MPIO_REQUEST_NULL=0)
!
integer*8 MPI_DISPLACEMENT_CURRENT
PARAMETER (MPI_DISPLACEMENT_CURRENT=-54278278)
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!

View File

@@ -0,0 +1,241 @@
#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

View File

@@ -0,0 +1,160 @@
/* -*- 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) */

View File

@@ -0,0 +1,286 @@
/* -*- 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 */

View File

@@ -0,0 +1,27 @@
/* -*- 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 */

View File

@@ -0,0 +1,205 @@
/* -*- 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) */

View File

@@ -0,0 +1,192 @@
/* -*- 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 */

View File

@@ -0,0 +1,216 @@
/* -*- 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 */

View File

@@ -0,0 +1,15 @@
/* -*- 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 */

View File

@@ -0,0 +1,25 @@
/* -*- 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 */

View File

@@ -0,0 +1,173 @@
/* -*- 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 */

View File

@@ -0,0 +1,15 @@
/* -*- 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 */

View File

@@ -0,0 +1,34 @@
/* -*- 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 */

View File

@@ -0,0 +1,129 @@
/* -*- 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 */

View File

@@ -0,0 +1,180 @@
/* -*- 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 */

View File

@@ -0,0 +1,443 @@
/* -*- 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 */

View File

@@ -0,0 +1,154 @@
/* -*- 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) */

View File

@@ -0,0 +1,135 @@
/* -*- 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 */

View File

@@ -0,0 +1,152 @@
/* -*- 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) */