Proposed clarifications to the UPC lock specification (section 7.4)

Dan Bonachea <>

Kathy Yelick <>

Bill Carlson <>

***Item 1*** upc_lock_t is a shared datatype with incomplete type

7.4.1, section 2:

old text: "The type upc_lock_t is an opaque UPC type. Variables of type upc_lock_t are meant, therefore, to be manipulated through pointers only."

new text: "The type upc_lock_t is an opaque UPC type. upc_lock_t is a shared datatype with incomplete type (as defined in section 6.2.5 of [ISO/SEC00]). Objects of type upc_lock_t may therefore only be manipulated through pointers."

Implications:

  • (upc_lock_t *) is a "pointer-to-shared" and acts as such (they can be communicated across threads, etc)
  • (upc_lock_t *) can never be dereferenced by user code - enforces the rule that locks are manipulated only through pointers (see sample code below), which prevents all sorts of deviant and unsupportable behavior at compile-time
  • upc_lock_t's cannot be declared statically, only allocated dynamically
  • upc_lock_init() is now useless and obsolete

/* upc_lock_t declaration in upc.h is equivalent to this: */

struct s_upc_lock_t;

typedef shared struct s_upc_lock_t upc_lock_t;

/* sample code: */

#include <upc.h>

struct foo {

upc_lock_t L; // not permitted - compile error

};

struct foo2 {

upc_lock_t *L;

};

upc_lock_t l1; // not permitted - compile error

void main() {

upc_lock_t l2; // not permitted - compile error

upc_lock_t *f;

upc_lock_t *g;

f = upc_global_lock_alloc();

g = upc_all_lock_alloc();

upc_lock(g);

upc_unlock(g);

*g = *f; // not permitted - compile error

}

*** Item 2*** upc_lock_init() is obsolete and removed from spec

Delete section 7.4.2, and other references to upc_lock_init() in 7.4.3 and 7.4.4

Implications:

  • upc_lock_t's can no longer be statically allocated, so this function is obsolete
  • prohibit any possibility of re-initializing a upc_lock_t

*** Item 3*** Add a upc_lock_free() function

Add new section:

#include <upc.h>

void upc_lock_free(upc_lock_t *ptr);

1. upc_lock_free() frees all resources associated with the dynamically allocated upc_lock_t pointed to be ptr. If ptr is a null pointer, no action occurs. Otherwise, if the argument does not match a pointer earlier returned by the upc_global_lock_alloc() or upc_all_lock_alloc() functions, of if the lock as been deallocated by a previous call to upc_lock_free(), the behavior is undefined.

2. the call will succeed regardless of whether the referenced lock is currently unlocked or currently locked (by any thread)

3. any subsequent calls to locking functions from any threads using ptr have undefined effects

Implications:

  • lock intensive programs won't suffer resource leaks due to orphaned locks

** Item 4** a null strict reference is implied after upc_lock(), upc_lock_attempt() and before upc_unlock()

7.4.5, add section 3: A null strict reference is implied after a call to upc_lock()

7.4.6, add section 3: A null strict reference is implied after a successful call to upc_lock_attempt()

7.4.7, add section 3: A null strict reference is implied before upc_unlock()

Implications:

  • ensure proper synchronization for relaxed operations in a critical section (analogous to wait/notify spec)

***Item 5*** UPC locks do not support recursive locking

7.4.5, add section 4: If the calling thread is already holding the lock referenced by ptr (i.e. it has previously locked it using upc_lock() or upc_lock_attempt(), but not unlocked it), the result is undefined

7.4.6, add section 4: If the calling thread is already holding the lock referenced by ptr (i.e. it has previously locked it using upc_lock() or upc_lock_attempt(), but not unlocked it), the result is undefined

Implications:

  • provide highest possible performance for UPC locks
  • robust implementations can easily detect recursive locking bugs
  • avoid constraining a minimal implementation of UPC locks (i.e. a single bit of state per lock suffices)