525 строки
13 KiB
C
525 строки
13 KiB
C
/**
|
|
* $HEADER$
|
|
*/
|
|
|
|
#include "attribute/attribute.h"
|
|
#include "communicator/communicator.h"
|
|
|
|
/**
|
|
* Macros - Lots of them!
|
|
*/
|
|
|
|
#define ATTR_TABLE_SIZE 10
|
|
|
|
/* This is done so that I can have a consistent interface to my macros
|
|
here */
|
|
|
|
#define MPI_DATATYPE_NULL_COPY_FN MPI_TYPE_NULL_COPY_FN
|
|
|
|
#define CREATE_KEY() lam_bitmap_find_and_set_first_unset_bit(key_bitmap)
|
|
|
|
#define FREE_KEY(key) lam_bitmap_clear_bit(key_bitmap, (key))
|
|
|
|
|
|
/* Not checking for NULL_DELETE_FN here, since according to the
|
|
MPI-standard it should be a valid function that returns
|
|
MPI_SUCCESS */
|
|
|
|
#define DELETE_ATTR_OBJECT(type, attribute) \
|
|
if ((err = (*((key_item->delete_attr_fn).attr_##type##_delete_fn)) \
|
|
((lam_##type##_t *)object, \
|
|
key, attribute, \
|
|
key_item->extra_state)) != MPI_SUCCESS) {\
|
|
return err;\
|
|
}
|
|
|
|
#define COPY_ATTR_OBJECT(type, old_object, hash_value) \
|
|
if ((err = (*((hash_value->copy_attr_fn).attr_##type##_copy_fn)) \
|
|
((lam_##type##_t *)old_object, key, hash_value->extra_state, \
|
|
old_attr, &new_attr, &flag)) != MPI_SUCCESS) { \
|
|
return err; \
|
|
}
|
|
|
|
|
|
/*
|
|
* Static
|
|
*/
|
|
static void lam_attribute_construct(lam_attrkey_t *attribute);
|
|
static void lam_attribute_destruct(lam_attrkey_t *attribute);
|
|
static void lam_attrkey_item_construct(lam_attrkey_item_t *item);
|
|
static void lam_attrkey_item_destruct(lam_attrkey_item_t *item);
|
|
|
|
|
|
/*
|
|
* lam_attrkey_t classes
|
|
*/
|
|
|
|
OBJ_CLASS_INSTANCE(lam_attrkey_t,
|
|
lam_list_t,
|
|
lam_attribute_construct,
|
|
lam_attribute_destruct);
|
|
/*
|
|
* lam_attribute_entry_t classes
|
|
*/
|
|
|
|
OBJ_CLASS_INSTANCE(lam_attrkey_item_t,
|
|
lam_object_t,
|
|
lam_attrkey_item_construct,
|
|
lam_attrkey_item_destruct);
|
|
|
|
|
|
/*
|
|
* Static variables
|
|
*/
|
|
|
|
static lam_attrkey_t *attr_hash;
|
|
static lam_bitmap_t *key_bitmap;
|
|
|
|
|
|
/*
|
|
* lam_attrkey_t interface functions
|
|
*/
|
|
|
|
static void
|
|
lam_attribute_construct(lam_attrkey_t *attribute)
|
|
{
|
|
attribute->a_fhandle = -1;
|
|
OBJ_CONSTRUCT(&(attribute->super), lam_hash_table_t);
|
|
}
|
|
|
|
|
|
static void
|
|
lam_attribute_destruct(lam_attrkey_t *attribute)
|
|
{
|
|
OBJ_DESTRUCT(&(attribute->super));
|
|
}
|
|
|
|
/*
|
|
* lam_attrkey_item_t interface functions
|
|
*/
|
|
|
|
static void
|
|
lam_attrkey_item_construct(lam_attrkey_item_t *item)
|
|
{
|
|
memset(&(item->attr_type), 0,
|
|
sizeof(lam_attrkey_item_t) - sizeof(lam_object_t));
|
|
}
|
|
|
|
|
|
static void
|
|
lam_attrkey_item_destruct(lam_attrkey_item_t *item)
|
|
{
|
|
/* Remove the key entry from the hash and free the key */
|
|
|
|
lam_hash_table_remove_value_uint32(&(attr_hash->super), item->key);
|
|
FREE_KEY(item->key);
|
|
}
|
|
|
|
|
|
/*
|
|
* This will initialize the main list to store key- attribute
|
|
* items. This will be called one time, mostly during MPI_INIT()
|
|
*/
|
|
|
|
int
|
|
lam_attr_init()
|
|
{
|
|
attr_hash = OBJ_NEW(lam_attrkey_t);
|
|
if (NULL == attr_hash) {
|
|
fprintf(stderr, "Error while creating the main attribute list\n");
|
|
return MPI_ERR_SYSRESOURCE;
|
|
}
|
|
key_bitmap = OBJ_NEW(lam_bitmap_t);
|
|
if (0 != lam_bitmap_init(key_bitmap, 10)) {
|
|
return MPI_ERR_SYSRESOURCE;
|
|
}
|
|
if (lam_hash_table_init(&attr_hash->super,
|
|
ATTR_TABLE_SIZE) != LAM_SUCCESS)
|
|
return MPI_ERR_SYSRESOURCE;
|
|
|
|
return MPI_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
* This will destroy the list, mostly during MPI_Finalize()
|
|
*/
|
|
|
|
void
|
|
lam_attr_destroy()
|
|
{
|
|
OBJ_RELEASE(attr_hash);
|
|
OBJ_RELEASE(key_bitmap);
|
|
}
|
|
|
|
|
|
int
|
|
lam_attr_create_keyval(lam_attribute_type_t type,
|
|
lam_attribute_fn_ptr_union_t copy_attr_fn,
|
|
lam_attribute_fn_ptr_union_t delete_attr_fn,
|
|
int *key, void *extra_state, int predefined)
|
|
{
|
|
lam_attrkey_item_t *attr;
|
|
int ret;
|
|
|
|
/* Protect against the user calling lam_attr_destroy and then
|
|
calling any of the functions which use it */
|
|
if (NULL == attr_hash)
|
|
return MPI_ERR_INTERN;
|
|
|
|
/* Allocate space for the list item */
|
|
|
|
attr = OBJ_NEW(lam_attrkey_item_t);
|
|
if (NULL == attr) {
|
|
fprintf(stderr, "Error during new object creation for attribute \n");
|
|
return MPI_ERR_SYSRESOURCE;
|
|
}
|
|
|
|
/* Create a new unique key and fill the hash */
|
|
|
|
*key = CREATE_KEY();
|
|
ret = lam_hash_table_set_value_uint32(&attr_hash->super, *key, attr);
|
|
if (ret != LAM_SUCCESS)
|
|
return ret;
|
|
|
|
/* Fill in the list item */
|
|
|
|
attr->copy_attr_fn = copy_attr_fn;
|
|
attr->delete_attr_fn = delete_attr_fn;
|
|
attr->extra_state = extra_state;
|
|
attr->attr_type = type;
|
|
attr->key = *key;
|
|
attr->attr_flag = (1 == predefined) ? LAM_PREDEFINED : 0;
|
|
|
|
/* Bump up the reference count, since we want the object to be
|
|
destroyed only when free_keyval is called and not when all
|
|
attributes associated with it have been deleted */
|
|
|
|
OBJ_RETAIN(attr);
|
|
|
|
/* Other fields will be filled in by the create_attr function */
|
|
|
|
return MPI_SUCCESS;
|
|
}
|
|
|
|
|
|
int
|
|
lam_attr_free_keyval(lam_attribute_type_t type, int *key, int predefined)
|
|
{
|
|
lam_attrkey_item_t *key_item;
|
|
|
|
/* Protect against the user calling lam_attr_destroy and then
|
|
calling any of the functions which use it */
|
|
if (NULL == attr_hash)
|
|
return MPI_ERR_INTERN;
|
|
|
|
/* Find the key-value pair */
|
|
|
|
key_item = (lam_attrkey_item_t*)
|
|
lam_hash_table_get_value_uint32(&attr_hash->super, *key);
|
|
|
|
if ((NULL == key_item) || (key_item->attr_type != type) ||
|
|
((!predefined) && (key_item->attr_flag & LAM_PREDEFINED)))
|
|
return MPI_INVALID_ATTR_KEYVAL;
|
|
|
|
/* Not releasing the object here, it will be done in MPI_*_attr_delete */
|
|
|
|
*key = MPI_KEYVAL_INVALID;
|
|
|
|
/* This will delete the key only when no attributes are associated
|
|
with it, else it will just decrement the reference count, so that when
|
|
the last attribute is deleted, this object gets deleted too */
|
|
|
|
OBJ_RELEASE(key_item);
|
|
|
|
return MPI_SUCCESS;
|
|
}
|
|
|
|
|
|
int
|
|
lam_attr_delete(lam_attribute_type_t type, void *object,
|
|
lam_hash_table_t *keyhash, int key,
|
|
int predefined)
|
|
{
|
|
lam_attrkey_item_t *key_item;
|
|
int ret, err;
|
|
void *attr;
|
|
|
|
/* Protect against the user calling lam_attr_destroy and then
|
|
calling any of the functions which use it */
|
|
if (NULL == attr_hash)
|
|
return MPI_ERR_INTERN;
|
|
|
|
/* Check if the key is valid in the key-attribute hash */
|
|
|
|
key_item = (lam_attrkey_item_t*)
|
|
lam_hash_table_get_value_uint32(&attr_hash->super, key);
|
|
|
|
if ((NULL == key_item) || (key_item->attr_type!= type) ||
|
|
((!predefined) && (key_item->attr_flag & LAM_PREDEFINED)))
|
|
return MPI_INVALID_ATTR_KEYVAL;
|
|
|
|
/* Check if the key is valid for the communicator/window/dtype. If
|
|
yes, then delete the attribute and key entry from the CWD hash */
|
|
|
|
attr = lam_hash_table_get_value_uint32(keyhash, key);
|
|
|
|
switch(type) {
|
|
|
|
case COMM_ATTR:
|
|
|
|
DELETE_ATTR_OBJECT(communicator, attr);
|
|
break;
|
|
|
|
case WIN_ATTR:
|
|
DELETE_ATTR_OBJECT(win, attr);
|
|
break;
|
|
|
|
case TYPE_ATTR:
|
|
DELETE_ATTR_OBJECT(datatype, attr);
|
|
break;
|
|
|
|
default:
|
|
fprintf(stderr, "lam_attribute: lam_attr_seet: Invalid type -- "
|
|
" Should be one of COMM/WIN/TYPE \n");
|
|
assert(0);
|
|
}
|
|
|
|
ret = lam_hash_table_remove_value_uint32(keyhash, key);
|
|
if (ret != LAM_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
/* Decrement the ref count for the key, and if ref count is 0,
|
|
remove the key (the destructor deletes the key implicitly for
|
|
this object */
|
|
|
|
OBJ_RELEASE(key_item);
|
|
return MPI_SUCCESS;
|
|
}
|
|
|
|
|
|
int
|
|
lam_attr_set(lam_attribute_type_t type, void *object,
|
|
lam_hash_table_t *keyhash, int key, void *attribute,
|
|
int predefined)
|
|
{
|
|
lam_attrkey_item_t *key_item;
|
|
int ret, err;
|
|
void *oldattr;
|
|
int had_old = 0;
|
|
|
|
/* Protect against the user calling lam_attr_destroy and then
|
|
calling any of the functions which use it */
|
|
if (NULL == attr_hash)
|
|
return MPI_ERR_INTERN;
|
|
|
|
key_item = (lam_attrkey_item_t *)
|
|
lam_hash_table_get_value_uint32(&(attr_hash->super), key);
|
|
|
|
/* If key not found */
|
|
|
|
if ((NULL == key_item) || (key_item->attr_type != type) ||
|
|
((!predefined) && (key_item->attr_flag & LAM_PREDEFINED))) {
|
|
fprintf(stderr, "lam_attribute: lam_attr_set: key not found \n");
|
|
return MPI_INVALID_ATTR_KEYVAL;
|
|
}
|
|
|
|
/* Now see if the key is present in the CWD object. If so, delete
|
|
the old attribute in the key */
|
|
oldattr = lam_hash_table_get_value_uint32(keyhash, key);
|
|
|
|
if (oldattr != NULL) {
|
|
|
|
switch(type) {
|
|
|
|
case COMM_ATTR:
|
|
DELETE_ATTR_OBJECT(communicator, oldattr);
|
|
break;
|
|
|
|
case WIN_ATTR:
|
|
DELETE_ATTR_OBJECT(win, oldattr);
|
|
break;
|
|
|
|
case TYPE_ATTR:
|
|
DELETE_ATTR_OBJECT(datatype, oldattr);
|
|
break;
|
|
|
|
default:
|
|
fprintf(stderr, "lam_attribute: lam_attr_set: Invalid type -- "
|
|
" Should be one of COMM/WIN/TYPE \n");
|
|
assert(0);
|
|
}
|
|
had_old = 1;
|
|
}
|
|
|
|
ret = lam_hash_table_set_value_uint32(keyhash, key, attribute);
|
|
if (ret != LAM_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
/* Increase the reference count of the object, only if there was no
|
|
old atribute/no old entry in the CWD */
|
|
|
|
if (!had_old) {
|
|
OBJ_RETAIN(key_item);
|
|
}
|
|
return MPI_SUCCESS;
|
|
}
|
|
|
|
|
|
int
|
|
lam_attr_get(lam_hash_table_t *keyhash, int key, void *attribute,
|
|
int *flag)
|
|
{
|
|
void *attr;
|
|
lam_attrkey_item_t *key_item;
|
|
|
|
/* According to MPI specs, the call is invalid if key is not
|
|
present in the main hash at all. If no attribute is associated
|
|
with the key, then the call is valid and returns FALSE in the
|
|
flag argument */
|
|
|
|
key_item = (lam_attrkey_item_t *)
|
|
lam_hash_table_get_value_uint32(&(attr_hash->super), key);
|
|
|
|
if (NULL == key_item) {
|
|
return MPI_KEYVAL_INVALID;
|
|
}
|
|
|
|
attr = lam_hash_table_get_value_uint32(keyhash, key);
|
|
|
|
if (NULL == attr) {
|
|
*flag = 0;
|
|
} else {
|
|
|
|
/* VPS: Put Fortran stuff here too */
|
|
|
|
*((void **) attribute) = attr;
|
|
*flag = 1;
|
|
}
|
|
return MPI_SUCCESS;
|
|
}
|
|
|
|
|
|
/* There is too much of code copy/paste in here, see if some other
|
|
logic could work here */
|
|
int
|
|
lam_attr_copy_all(lam_attribute_type_t type, void *old_object,
|
|
void *new_object, lam_hash_table_t *oldkeyhash,
|
|
lam_hash_table_t *newkeyhash)
|
|
{
|
|
int ret;
|
|
int err;
|
|
uint32_t key;
|
|
int flag;
|
|
void *node, *in_node, *old_attr, *new_attr;
|
|
lam_attrkey_item_t *hash_value;
|
|
|
|
/* Protect against the user calling lam_attr_destroy and then
|
|
calling any of the functions which use it */
|
|
if (NULL == attr_hash)
|
|
return MPI_ERR_INTERN;
|
|
|
|
/* Get the first key-attr in the CWD hash */
|
|
ret = lam_hash_table_get_first_key_uint32(oldkeyhash, &key, &old_attr,
|
|
&node);
|
|
|
|
/* While we still have some key-attr pair in the CWD hash */
|
|
while (ret != LAM_ERROR) {
|
|
in_node = node;
|
|
|
|
/* Get the attr_item in the main hash - so that we know
|
|
what the copy_attr_fn is */
|
|
|
|
hash_value = (lam_attrkey_item_t *)
|
|
lam_hash_table_get_value_uint32(&(attr_hash->super), key);
|
|
|
|
assert (hash_value != NULL);
|
|
|
|
|
|
switch (type) {
|
|
|
|
case COMM_ATTR:
|
|
/* Now call the copy_attr_fn */
|
|
COPY_ATTR_OBJECT(communicator, old_object, hash_value);
|
|
|
|
break;
|
|
|
|
case TYPE_ATTR:
|
|
|
|
/* Now call the copy_attr_fn */
|
|
COPY_ATTR_OBJECT(datatype, old_object, hash_value);
|
|
|
|
break;
|
|
|
|
case WIN_ATTR:
|
|
|
|
/* Now call the copy_attr_fn */
|
|
COPY_ATTR_OBJECT(win, old_object, hash_value);
|
|
|
|
break;
|
|
}
|
|
|
|
/* Hang this off the new CWD object */
|
|
|
|
/* VPS: predefined is set to 1, so that no comparison is
|
|
done for prdefined at all and it just falls off the
|
|
error checking loop in attr_set */
|
|
|
|
/* VPS: we pass the address of new_attr in here, I am
|
|
assuming that new_attr should have actually been a
|
|
double pointer in the copy fn, but since its a pointer
|
|
in that MPI specs, we need to pass *new_attr here */
|
|
lam_attr_set(type, new_object, newkeyhash, key,
|
|
new_attr, 1);
|
|
|
|
|
|
ret = lam_hash_table_get_next_key_uint32(oldkeyhash, &key,
|
|
&old_attr, in_node,
|
|
&node);
|
|
}
|
|
return MPI_SUCCESS;
|
|
}
|
|
|
|
|
|
int
|
|
lam_attr_delete_all(lam_attribute_type_t type, void *object,
|
|
lam_hash_table_t *keyhash)
|
|
{
|
|
int ret;
|
|
uint32_t key, oldkey;
|
|
void *node, *in_node, *old_attr;
|
|
lam_attrkey_item_t *hash_value;
|
|
|
|
/* Protect against the user calling lam_attr_destroy and then
|
|
calling any of the functions which use it */
|
|
if (NULL == attr_hash)
|
|
return MPI_ERR_INTERN;
|
|
|
|
/* Get the first key in local CWD hash */
|
|
ret = lam_hash_table_get_first_key_uint32(keyhash,
|
|
&key, &old_attr,
|
|
&node);
|
|
while (ret != LAM_ERROR) {
|
|
|
|
/* Save this node info for deletion, before we move onto the
|
|
next node */
|
|
|
|
in_node = node;
|
|
oldkey = key;
|
|
|
|
/* Move to the next node */
|
|
|
|
ret = lam_hash_table_get_next_key_uint32(keyhash,
|
|
&key, &old_attr,
|
|
in_node, &node);
|
|
/* Now delete this attribute */
|
|
|
|
lam_attr_delete(type, object, keyhash, oldkey, 1);
|
|
|
|
}
|
|
|
|
return MPI_SUCCESS;
|
|
}
|