5
/* begin_generated_IBM_copyright_prolog */
7
/* ---------------------------------------------------------------- */
8
/* (C)Copyright IBM Corp. 2007, 2008 */
10
/* ---------------------------------------------------------------- */
12
/* end_generated_IBM_copyright_prolog */
14
* \file armci/src/armcix/dcmf/armcix_lock.c
15
* \brief DCMF ARMCI Extension for lock operations.
18
#include "armcix_impl.h"
20
typedef struct ARMCIX_DCMF_Lockwaiter_t
27
ARMCIX_DCMF_Lockwaiter_t;
29
typedef struct ARMCIX_DCMF_Lockwaitq_t
31
ARMCIX_DCMF_Lockwaiter_t * queue;
36
ARMCIX_DCMF_Lockwaitq_t;
40
ARMCIX_DCMF_Lock_Request,
42
ARMCIX_DCMF_Lock_Release
44
ARMCIX_DCMF_Lockinfo_operation_t;
46
typedef struct ARMCIX_DCMF_Lockinfo_t
48
ARMCIX_DCMF_Lockinfo_operation_t op;
64
ARMCIX_DCMF_Lockinfo_t __attribute__ ((__aligned__ (16)));
66
/** Lock operation DCMF protocol global object. */
67
DCMF_Protocol_t __lock_req_protocol;
68
DCMF_Protocol_t __lock_ack_protocol;
71
* \brief Origin node active lock slots.
74
#error MAX_SLOTS must be less than or equal to 256
76
unsigned char * __lock_slot;
78
/** Target node pending lock queue. */
79
ARMCIX_DCMF_Lockwaitq_t __lock_pending;
82
* \brief Acquire a lock on a memory address range.
84
* Inspects the memory lock table and, if there is an open slot and the
85
* requested memory address range does not conflict with an existing lock,
86
* updates the memory locak table with the lock information and returns
87
* the slot of the acquired lock.
89
* \todo Can this be moved up to a more platform-neutral place?
91
* \param[in] local_memlock_table The memory lock table
92
* \param[in] pstart The start of the memory address range
93
* \param[in] pend The end of the memory address range
95
* \return The memory lock table slot of the successfully acquired lock,
98
* \see ARMCIX_release_lock
100
int ARMCIX_aquire_lock (memlock_t * local_memlock_table, void * pstart, void * pend)
102
int acquired_lock = -1;
104
/* inspect the table */
105
unsigned conflict = 0;
107
for(; slot < MAX_SLOTS; slot++)
109
/* nonzero starting address means the slot is occupied */
110
if(local_memlock_table[slot].start == NULL)
112
/* remember a free slot to store address range */
113
acquired_lock = slot;
117
/* check for conflict: overlap between stored and current range */
118
if ( (pstart >= local_memlock_table[slot].start &&
119
pstart <= local_memlock_table[slot].end) ||
120
(pend >= local_memlock_table[slot].start &&
121
pend <= local_memlock_table[slot].end) )
129
if (acquired_lock != -1 && !conflict)
131
/* acquired the memory lock: enter address into the table */
132
local_memlock_table[acquired_lock].start = pstart;
133
local_memlock_table[acquired_lock].end = pend;
140
return acquired_lock;
144
* \brief Release a lock of the memory address range in the specified lock slot.
146
* Clears the memory address range in specified lock slot of the memory lock
149
* \todo Can this be moved up to a more platform-neutral place?
151
* \param[in] local_memlock_table The memory lock table
152
* \param[in] slot The memory lock slot to release
154
* \see ARMCIX_aquire_lock
156
void ARMCIX_release_lock (memlock_t * local_memlock_table, unsigned slot)
158
local_memlock_table[slot].start = NULL;
159
local_memlock_table[slot].end = NULL;
163
* \brief Receive a lock control message.
165
* The lock message type is either a lock \e request, \e acknowledgement,
168
* For a lock request message the local memlock table is inspected for an
169
* available lock slot. If a slot is found a lock acknowledgement message
170
* is immediately sent to the peer node. Otherwise, the lock request
171
* information is saved in a pending queue.
173
* The lock acknowledgment message is sent from the target node when the
174
* origin node has acquired a lock of a resource on the target node. The
175
* update variable is unset which will end the polling advance operation
176
* inside the blocking ARMCIX_Lockmem() function.
178
* The lock release message frees the specified slot and attempts to acquire
179
* a lock for the first lock waiter in the pending queue. If the lock is
180
* aqcuired then a lock acknowledgement is sent to the waiter.
182
* \param[in] clientdata Registered clientdata, the armci connection array
183
* \param[in] info Lock control information
184
* \param[in] peer Rank of the node that sent this control message
186
* \see DCMF_RecvControl
188
void ARMCIX_DCMF_RecvLockMessage (void * clientdata,
189
const DCMF_Control_t * info,
192
/* Get the lock information sent with this lock message */
193
ARMCIX_DCMF_Lockinfo_t * lockinfo = (ARMCIX_DCMF_Lockinfo_t *) info;
195
switch (lockinfo->op)
197
case ARMCIX_DCMF_Lock_Request:
199
unsigned queue_request = 1;
200
if (__lock_pending.head == __lock_pending.tail)
202
/* There are no pending lock requests. Attempt to acquire the */
204
int lock = ARMCIX_aquire_lock ((memlock_t *) clientdata, lockinfo->request.start, lockinfo->request.end);
207
/* The lock was acquired. Send a lock acknowledgement message to */
208
/* the origin node with the slot of the aquired lock and the */
209
/* address of the update variable on the origin node. */
210
ARMCIX_DCMF_Lockinfo_t ack;
211
ack.op = ARMCIX_DCMF_Lock_Ack;
212
ack.update = lockinfo->update;
216
DCMF_Control (&__lock_ack_protocol,
217
DCMF_SEQUENTIAL_CONSISTENCY,
219
(DCMF_Control_t *) &ack);
227
/* There were pending lock requests, or the acquire lock attempt */
228
/* failed. Queue the lock request until another node releases a */
230
ARMCIX_DCMF_Lockwaiter_t * tail = &__lock_pending.queue[__lock_pending.tail];
232
tail->start = lockinfo->request.start;
233
tail->end = lockinfo->request.end;
234
tail->update = lockinfo->update;
236
/* Advance the tail index */
237
__lock_pending.tail = (__lock_pending.tail+1)%__lock_pending.size;
242
case ARMCIX_DCMF_Lock_Ack:
244
/* Save the lock slot until the lock is released. */
245
__lock_slot[peer] = lockinfo->key.slot;
247
/* Set the update variable to zero. This will break the polling loop */
248
/* in ARMCIX_Lockmem() and allow that function to return. */
249
*(lockinfo->update) = 0;
252
case ARMCIX_DCMF_Lock_Release:
254
/* Release the lock in this slot. */
255
ARMCIX_release_lock ((memlock_t *) clientdata, lockinfo->key.slot);
257
if (__lock_pending.head != __lock_pending.tail)
259
/* There is a pending lock request. Attempt to acquire the lock as */
260
/* specified in the pending queue now that the previous lock has */
262
ARMCIX_DCMF_Lockwaiter_t * head = &__lock_pending.queue[__lock_pending.head];
263
int lock = ARMCIX_aquire_lock ((memlock_t *) clientdata, head->start, head->end);
266
/* The aquire lock attempt was successful. Send a lock */
267
/* acknowledgement message to the origin node of the pending */
268
/* lock request with the slot of the aquired lock and the */
269
/* address of the update variable on the origin node. */
270
ARMCIX_DCMF_Lockinfo_t ack;
271
ack.op = ARMCIX_DCMF_Lock_Ack;
272
ack.update = head->update;
276
DCMF_Control (&__lock_ack_protocol,
277
DCMF_SEQUENTIAL_CONSISTENCY,
279
(DCMF_Control_t *) &ack);
281
/* Advance the head index (dequeue the pending lock request) */
282
__lock_pending.head = (__lock_pending.head+1)%__lock_pending.size;
296
* \brief DCMF ARMCI Extention receive short lock request callback
298
* \see ARMCIX_DCMF_RecvLockAck
299
* \see DCMF_RecvSendShort
301
void ARMCIX_DCMF_RecvLockRequest (void * clientdata,
302
const DCQuad * msginfo,
308
ARMCIX_DCMF_RecvLockMessage (clientdata, (const DCMF_Control_t *) msginfo, peer);
313
* \brief Initialize the ARMCI Extention lock resources.
315
* Register the DCMF Control protocol used to pass lock messages between nodes.
316
* Allocate a lock pending queue for use when a lock request is received by
317
* the receive callback function ARMCIX_DCMF_RecvLockMessage() and the resource
318
* is currently allocated to another node.
320
* \param[in] local_memlock_table memlock table
322
* \see ARMCIX_DCMF_Lockwaitq_t
323
* \see ARMCIX_DCMF_Lockwaiter_t
324
* \see ARMCIX_DCMF_RecvLockMessage
325
* \see DCMF_Control_register
327
void ARMCIX_init_memlock (memlock_t * local_memlock_table)
329
DCMF_CriticalSection_enter (0);
331
DCMF_Send_Configuration_t send_configuration = {
332
DCMF_DEFAULT_SEND_PROTOCOL,
334
ARMCIX_DCMF_RecvLockRequest,
339
DCMF_Send_register (&__lock_req_protocol, &send_configuration);
341
DCMF_Control_Configuration_t ctrl_configuration = {
342
DCMF_DEFAULT_CONTROL_PROTOCOL,
344
ARMCIX_DCMF_RecvLockMessage,
347
DCMF_Control_register (&__lock_ack_protocol, &ctrl_configuration);
349
unsigned msize = DCMF_Messager_size ();
350
unsigned qsize = sizeof(ARMCIX_DCMF_Lockwaiter_t) * msize+1;
351
__lock_pending.size = msize;
352
__lock_pending.queue = (ARMCIX_DCMF_Lockwaiter_t *) malloc (qsize);
353
__lock_pending.head = 0;
354
__lock_pending.tail = 0;
356
__lock_slot = (unsigned char *) malloc (sizeof(unsigned char) * msize);
357
memset(__lock_slot, 0x00, sizeof(unsigned char) * msize);
359
DCMF_CriticalSection_exit (0);
363
* \brief ARMCI Extension blocking memory lock operation.
365
* Send a lock request to the remote node and block until the lock has been
366
* acquired on the remote node.
368
* \param[in] pstart The start virtual address of the range of memory to lock.
369
* \param[in] pend The end virtual address of the range of memory to lock.
370
* \param[in] proc Remote process(or) ID
372
* \see ARMCIX_DCMF_Lockinfo_t
373
* \see ARMCIX_DCMF_RecvLockMessage
376
void ARMCIX_Lockmem (void * pstart, void * pend, int proc)
378
DCMF_CriticalSection_enter (0);
380
volatile unsigned active = 1;
382
ARMCIX_DCMF_Lockinfo_t info;
383
info.op = ARMCIX_DCMF_Lock_Request;
384
info.update = (unsigned *)&active;
385
info.request.start = pstart;
386
info.request.end = pend;
388
DCMF_Request_t request;
389
DCMF_Send ( &__lock_req_protocol,
391
(DCMF_Callback_t) { NULL, NULL },
392
DCMF_SEQUENTIAL_CONSISTENCY,
397
sizeof(ARMCIX_DCMF_Lockinfo_t)/sizeof(DCQuad));
399
while (active) DCMF_Messager_advance ();
401
DCMF_CriticalSection_exit (0);
406
* \brief ARMCI Extension release memory lock operation.
408
* Send a lock release message to the remote node. This is a \e fire-and-forget
409
* operation because the node does not block for an acknowledgement that the
410
* lock release was successful.
412
* \param[in] proc Remote process(or) ID
414
* \see ARMCIX_DCMF_Lockinfo_t
415
* \see ARMCIX_DCMF_RecvLockMessage
418
void ARMCIX_Unlockmem (int proc)
420
DCMF_CriticalSection_enter (0);
422
ARMCIX_DCMF_Lockinfo_t info;
423
info.op = ARMCIX_DCMF_Lock_Release;
424
info.key.slot = (unsigned) __lock_slot[proc];
427
DCMF_Request_t request;
428
volatile unsigned active = 1;
429
DCMF_Send ( &__lock_req_protocol,
431
(DCMF_Callback_t) { ARMCIX_DCMF_cb_decrement, (void *)&active },
432
DCMF_SEQUENTIAL_CONSISTENCY,
437
sizeof(ARMCIX_DCMF_Lockinfo_t)/sizeof(DCQuad));
439
while (active) DCMF_Messager_advance ();
441
DCMF_CriticalSection_exit (0);