4
/* begin_generated_IBM_copyright_prolog */
6
/* ---------------------------------------------------------------- */
7
/* (C)Copyright IBM Corp. 2007, 2008 */
9
/* ---------------------------------------------------------------- */
11
/* end_generated_IBM_copyright_prolog */
13
* \file armci/src/armcix/dcmf/armcix_lock.c
14
* \brief DCMF ARMCI Extension for lock operations.
17
#include "armcix_impl.h"
19
typedef struct ARMCIX_DCMF_Lockwaiter_t
26
ARMCIX_DCMF_Lockwaiter_t;
28
typedef struct ARMCIX_DCMF_Lockwaitq_t
30
ARMCIX_DCMF_Lockwaiter_t * queue;
35
ARMCIX_DCMF_Lockwaitq_t;
39
ARMCIX_DCMF_Lock_Request,
41
ARMCIX_DCMF_Lock_Release
43
ARMCIX_DCMF_Lockinfo_operation_t;
45
typedef struct ARMCIX_DCMF_Lockinfo_t
47
ARMCIX_DCMF_Lockinfo_operation_t op;
63
ARMCIX_DCMF_Lockinfo_t __attribute__ ((__aligned__ (16)));
65
/** Lock operation DCMF protocol global object. */
66
DCMF_Protocol_t __lock_req_protocol;
67
DCMF_Protocol_t __lock_ack_protocol;
70
* \brief Origin node active lock slots.
73
#error MAX_SLOTS must be less than or equal to 256
75
unsigned char * __lock_slot;
77
/** Target node pending lock queue. */
78
ARMCIX_DCMF_Lockwaitq_t __lock_pending;
81
* \brief Acquire a lock on a memory address range.
83
* Inspects the memory lock table and, if there is an open slot and the
84
* requested memory address range does not conflict with an existing lock,
85
* updates the memory locak table with the lock information and returns
86
* the slot of the acquired lock.
88
* \todo Can this be moved up to a more platform-neutral place?
90
* \param[in] local_memlock_table The memory lock table
91
* \param[in] pstart The start of the memory address range
92
* \param[in] pend The end of the memory address range
94
* \return The memory lock table slot of the successfully acquired lock,
97
* \see ARMCIX_release_lock
99
int ARMCIX_aquire_lock (memlock_t * local_memlock_table, void * pstart, void * pend)
101
int acquired_lock = -1;
103
/* inspect the table */
104
unsigned conflict = 0;
106
for(; slot < MAX_SLOTS; slot++)
108
/* nonzero starting address means the slot is occupied */
109
if(local_memlock_table[slot].start == NULL)
111
/* remember a free slot to store address range */
112
acquired_lock = slot;
116
/* check for conflict: overlap between stored and current range */
117
if ( (pstart >= local_memlock_table[slot].start &&
118
pstart <= local_memlock_table[slot].end) ||
119
(pend >= local_memlock_table[slot].start &&
120
pend <= local_memlock_table[slot].end) )
128
if (acquired_lock != -1 && !conflict)
130
/* acquired the memory lock: enter address into the table */
131
local_memlock_table[acquired_lock].start = pstart;
132
local_memlock_table[acquired_lock].end = pend;
139
return acquired_lock;
143
* \brief Release a lock of the memory address range in the specified lock slot.
145
* Clears the memory address range in specified lock slot of the memory lock
148
* \todo Can this be moved up to a more platform-neutral place?
150
* \param[in] local_memlock_table The memory lock table
151
* \param[in] slot The memory lock slot to release
153
* \see ARMCIX_aquire_lock
155
void ARMCIX_release_lock (memlock_t * local_memlock_table, unsigned slot)
157
local_memlock_table[slot].start = NULL;
158
local_memlock_table[slot].end = NULL;
162
* \brief Receive a lock control message.
164
* The lock message type is either a lock \e request, \e acknowledgement,
167
* For a lock request message the local memlock table is inspected for an
168
* available lock slot. If a slot is found a lock acknowledgement message
169
* is immediately sent to the peer node. Otherwise, the lock request
170
* information is saved in a pending queue.
172
* The lock acknowledgment message is sent from the target node when the
173
* origin node has acquired a lock of a resource on the target node. The
174
* update variable is unset which will end the polling advance operation
175
* inside the blocking ARMCIX_Lockmem() function.
177
* The lock release message frees the specified slot and attempts to acquire
178
* a lock for the first lock waiter in the pending queue. If the lock is
179
* aqcuired then a lock acknowledgement is sent to the waiter.
181
* \param[in] clientdata Registered clientdata, the armci connection array
182
* \param[in] info Lock control information
183
* \param[in] peer Rank of the node that sent this control message
185
* \see DCMF_RecvControl
187
void ARMCIX_DCMF_RecvLockMessage (void * clientdata,
188
const DCMF_Control_t * info,
191
/* Get the lock information sent with this lock message */
192
ARMCIX_DCMF_Lockinfo_t * lockinfo = (ARMCIX_DCMF_Lockinfo_t *) info;
194
switch (lockinfo->op)
196
case ARMCIX_DCMF_Lock_Request:
198
unsigned queue_request = 1;
199
if (__lock_pending.head == __lock_pending.tail)
201
/* There are no pending lock requests. Attempt to acquire the */
203
int lock = ARMCIX_aquire_lock ((memlock_t *) clientdata, lockinfo->request.start, lockinfo->request.end);
206
/* The lock was acquired. Send a lock acknowledgement message to */
207
/* the origin node with the slot of the aquired lock and the */
208
/* address of the update variable on the origin node. */
209
ARMCIX_DCMF_Lockinfo_t ack;
210
ack.op = ARMCIX_DCMF_Lock_Ack;
211
ack.update = lockinfo->update;
215
DCMF_Control (&__lock_ack_protocol,
216
DCMF_SEQUENTIAL_CONSISTENCY,
218
(DCMF_Control_t *) &ack);
226
/* There were pending lock requests, or the acquire lock attempt */
227
/* failed. Queue the lock request until another node releases a */
229
ARMCIX_DCMF_Lockwaiter_t * tail = &__lock_pending.queue[__lock_pending.tail];
231
tail->start = lockinfo->request.start;
232
tail->end = lockinfo->request.end;
233
tail->update = lockinfo->update;
235
/* Advance the tail index */
236
__lock_pending.tail = (__lock_pending.tail+1)%__lock_pending.size;
241
case ARMCIX_DCMF_Lock_Ack:
243
/* Save the lock slot until the lock is released. */
244
__lock_slot[peer] = lockinfo->key.slot;
246
/* Set the update variable to zero. This will break the polling loop */
247
/* in ARMCIX_Lockmem() and allow that function to return. */
248
*(lockinfo->update) = 0;
251
case ARMCIX_DCMF_Lock_Release:
253
/* Release the lock in this slot. */
254
ARMCIX_release_lock ((memlock_t *) clientdata, lockinfo->key.slot);
256
if (__lock_pending.head != __lock_pending.tail)
258
/* There is a pending lock request. Attempt to acquire the lock as */
259
/* specified in the pending queue now that the previous lock has */
261
ARMCIX_DCMF_Lockwaiter_t * head = &__lock_pending.queue[__lock_pending.head];
262
int lock = ARMCIX_aquire_lock ((memlock_t *) clientdata, head->start, head->end);
265
/* The aquire lock attempt was successful. Send a lock */
266
/* acknowledgement message to the origin node of the pending */
267
/* lock request with the slot of the aquired lock and the */
268
/* address of the update variable on the origin node. */
269
ARMCIX_DCMF_Lockinfo_t ack;
270
ack.op = ARMCIX_DCMF_Lock_Ack;
271
ack.update = head->update;
275
DCMF_Control (&__lock_ack_protocol,
276
DCMF_SEQUENTIAL_CONSISTENCY,
278
(DCMF_Control_t *) &ack);
280
/* Advance the head index (dequeue the pending lock request) */
281
__lock_pending.head = (__lock_pending.head+1)%__lock_pending.size;
295
* \brief DCMF ARMCI Extention receive short lock request callback
297
* \see ARMCIX_DCMF_RecvLockAck
298
* \see DCMF_RecvSendShort
300
void ARMCIX_DCMF_RecvLockRequest (void * clientdata,
301
const DCQuad * msginfo,
307
ARMCIX_DCMF_RecvLockMessage (clientdata, (const DCMF_Control_t *) msginfo, peer);
312
* \brief Initialize the ARMCI Extention lock resources.
314
* Register the DCMF Control protocol used to pass lock messages between nodes.
315
* Allocate a lock pending queue for use when a lock request is received by
316
* the receive callback function ARMCIX_DCMF_RecvLockMessage() and the resource
317
* is currently allocated to another node.
319
* \param[in] local_memlock_table memlock table
321
* \see ARMCIX_DCMF_Lockwaitq_t
322
* \see ARMCIX_DCMF_Lockwaiter_t
323
* \see ARMCIX_DCMF_RecvLockMessage
324
* \see DCMF_Control_register
326
void ARMCIX_init_memlock (memlock_t * local_memlock_table)
328
DCMF_CriticalSection_enter (0);
330
DCMF_Send_Configuration_t send_configuration = {
331
DCMF_DEFAULT_SEND_PROTOCOL,
332
DCMF_DEFAULT_NETWORK,
333
ARMCIX_DCMF_RecvLockRequest,
338
DCMF_Send_register (&__lock_req_protocol, &send_configuration);
340
DCMF_Control_Configuration_t ctrl_configuration = {
341
DCMF_DEFAULT_CONTROL_PROTOCOL,
342
DCMF_DEFAULT_NETWORK,
343
ARMCIX_DCMF_RecvLockMessage,
346
DCMF_Control_register (&__lock_ack_protocol, &ctrl_configuration);
348
unsigned msize = DCMF_Messager_size ();
349
unsigned qsize = sizeof(ARMCIX_DCMF_Lockwaiter_t) * msize+1;
350
__lock_pending.size = msize;
351
__lock_pending.queue = (ARMCIX_DCMF_Lockwaiter_t *) malloc (qsize);
352
__lock_pending.head = 0;
353
__lock_pending.tail = 0;
355
__lock_slot = (unsigned char *) malloc (sizeof(unsigned char) * msize);
356
memset(__lock_slot, 0x00, sizeof(unsigned char) * msize);
358
DCMF_CriticalSection_exit (0);
362
* \brief ARMCI Extension blocking memory lock operation.
364
* Send a lock request to the remote node and block until the lock has been
365
* acquired on the remote node.
367
* \param[in] pstart The start virtual address of the range of memory to lock.
368
* \param[in] pend The end virtual address of the range of memory to lock.
369
* \param[in] proc Remote process(or) ID
371
* \see ARMCIX_DCMF_Lockinfo_t
372
* \see ARMCIX_DCMF_RecvLockMessage
375
void ARMCIX_Lockmem (void * pstart, void * pend, int proc)
377
DCMF_CriticalSection_enter (0);
379
volatile unsigned active = 1;
381
ARMCIX_DCMF_Lockinfo_t info;
382
info.op = ARMCIX_DCMF_Lock_Request;
383
info.update = (unsigned *)&active;
384
info.request.start = pstart;
385
info.request.end = pend;
387
DCMF_Request_t request;
388
DCMF_Send ( &__lock_req_protocol,
390
(DCMF_Callback_t) { NULL, NULL },
391
DCMF_SEQUENTIAL_CONSISTENCY,
396
sizeof(ARMCIX_DCMF_Lockinfo_t)/sizeof(DCQuad));
398
while (active) DCMF_Messager_advance ();
400
DCMF_CriticalSection_exit (0);
405
* \brief ARMCI Extension release memory lock operation.
407
* Send a lock release message to the remote node. This is a \e fire-and-forget
408
* operation because the node does not block for an acknowledgement that the
409
* lock release was successful.
411
* \param[in] proc Remote process(or) ID
413
* \see ARMCIX_DCMF_Lockinfo_t
414
* \see ARMCIX_DCMF_RecvLockMessage
417
void ARMCIX_Unlockmem (int proc)
419
DCMF_CriticalSection_enter (0);
421
ARMCIX_DCMF_Lockinfo_t info;
422
info.op = ARMCIX_DCMF_Lock_Release;
423
info.key.slot = (unsigned) __lock_slot[proc];
426
DCMF_Request_t request;
427
volatile unsigned active = 1;
428
DCMF_Send ( &__lock_req_protocol,
430
(DCMF_Callback_t) { ARMCIX_DCMF_cb_decrement, (void *)&active },
431
DCMF_SEQUENTIAL_CONSISTENCY,
436
sizeof(ARMCIX_DCMF_Lockinfo_t)/sizeof(DCQuad));
438
while (active) DCMF_Messager_advance ();
440
DCMF_CriticalSection_exit (0);