Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
a972a55c44eb96e3f6f70f569a5026bb727b1ec9
[simgrid.git] / teshsuite / smpi / mpich3-test / rma / mcs-mutex.c
1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
2 /*
3  *  (C) 2013 by Argonne National Laboratory.
4  *      See COPYRIGHT in top-level directory.
5  */
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <assert.h>
10 #include <strings.h>
11
12 #include <mpi.h>
13 #include "mcs-mutex.h"
14
15 /* TODO: Make these mutex operations no-ops for sequential runs */
16
17 /** Create an MCS mutex.  Collective on comm.
18   *
19   * @param[out] comm communicator containing all processes that will use the
20   *                  mutex
21   * @param[out] tail_rank rank of the process in comm that holds the tail
22   *                  pointer
23   * @param[out] hdl  handle to the mutex
24   * @return          MPI status
25   */
26 int MCS_Mutex_create(int tail_rank, MPI_Comm comm, MCS_Mutex * hdl_out)
27 {
28     int rank, nproc;
29     MCS_Mutex hdl;
30
31     hdl = malloc(sizeof(struct mcs_mutex_s));
32     assert(hdl != NULL);
33
34     MPI_Comm_dup(comm, &hdl->comm);
35
36     MPI_Comm_rank(hdl->comm, &rank);
37     MPI_Comm_size(hdl->comm, &nproc);
38
39     hdl->tail_rank = tail_rank;
40
41 #ifdef USE_WIN_SHARED
42     MPI_Win_allocate_shared(2 * sizeof(int), sizeof(int), MPI_INFO_NULL,
43                             hdl->comm, &hdl->base, &hdl->window);
44 #else
45 #ifdef USE_WIN_ALLOC_SHM
46     MPI_Info_create(&hdl->win_info);
47     MPI_Info_set(hdl->win_info, "alloc_shm", "true");
48 #else
49     MPI_Info_create(&hdl->win_info);
50     MPI_Info_set(hdl->win_info, "alloc_shm", "false");
51 #endif
52     MPI_Win_allocate(2 * sizeof(int), sizeof(int), hdl->win_info, hdl->comm,
53                      &hdl->base, &hdl->window);
54 #endif
55
56     MPI_Win_lock_all(0, hdl->window);
57
58     hdl->base[0] = MPI_PROC_NULL;
59     hdl->base[1] = MPI_PROC_NULL;
60
61     MPI_Win_sync(hdl->window);
62     MPI_Barrier(hdl->comm);
63
64     *hdl_out = hdl;
65     return MPI_SUCCESS;
66 }
67
68
69 /** Free an MCS mutex.  Collective on ranks in the communicator used at the
70   * time of creation.
71   *
72   * @param[in] hdl handle to the group that will be freed
73   * @return        MPI status
74   */
75 int MCS_Mutex_free(MCS_Mutex * hdl_ptr)
76 {
77     MCS_Mutex hdl = *hdl_ptr;
78
79     MPI_Win_unlock_all(hdl->window);
80
81     MPI_Win_free(&hdl->window);
82     MPI_Comm_free(&hdl->comm);
83 #ifndef USE_WIN_SHARED
84     MPI_Info_free(&hdl->win_info);
85 #endif
86
87     free(hdl);
88     hdl_ptr = NULL;
89
90     return MPI_SUCCESS;
91 }
92
93
94 /** Lock a mutex.
95   *
96   * @param[in] hdl   Handle to the mutex
97   * @return          MPI status
98   */
99 int MCS_Mutex_lock(MCS_Mutex hdl)
100 {
101     int rank, nproc;
102     int prev;
103
104     MPI_Comm_rank(hdl->comm, &rank);
105     MPI_Comm_size(hdl->comm, &nproc);
106
107     /* This store is safe, since it cannot happen concurrently with a remote
108      * write */
109     hdl->base[MCS_MTX_ELEM_DISP] = MPI_PROC_NULL;
110     MPI_Win_sync(hdl->window);
111
112     MPI_Fetch_and_op(&rank, &prev, MPI_INT, hdl->tail_rank, MCS_MTX_TAIL_DISP,
113                      MPI_REPLACE, hdl->window);
114     MPI_Win_flush(hdl->tail_rank, hdl->window);
115
116     /* If there was a previous tail, update their next pointer and wait for
117      * notification.  Otherwise, the mutex was successfully acquired. */
118     if (prev != MPI_PROC_NULL) {
119         /* Wait for notification */
120         MPI_Status status;
121
122         MPI_Accumulate(&rank, 1, MPI_INT, prev, MCS_MTX_ELEM_DISP, 1, MPI_INT, MPI_REPLACE,
123                        hdl->window);
124         MPI_Win_flush(prev, hdl->window);
125
126         debug_print("%2d: LOCK   - waiting for notification from %d\n", rank, prev);
127         MPI_Recv(NULL, 0, MPI_BYTE, prev, MCS_MUTEX_TAG, hdl->comm, &status);
128     }
129
130     debug_print("%2d: LOCK   - lock acquired\n", rank);
131
132     return MPI_SUCCESS;
133 }
134
135
136 /** Attempt to acquire a mutex.
137   *
138   * @param[in] hdl   Handle to the mutex
139   * @param[out] success Indicates whether the mutex was acquired
140   * @return          MPI status
141   */
142 int MCS_Mutex_trylock(MCS_Mutex hdl, int *success)
143 {
144     int rank, nproc;
145     int tail, nil = MPI_PROC_NULL;
146
147     MPI_Comm_rank(hdl->comm, &rank);
148     MPI_Comm_size(hdl->comm, &nproc);
149
150     /* This store is safe, since it cannot happen concurrently with a remote
151      * write */
152     hdl->base[MCS_MTX_ELEM_DISP] = MPI_PROC_NULL;
153     MPI_Win_sync(hdl->window);
154
155     /* Check if the lock is available and claim it if it is. */
156     MPI_Compare_and_swap(&rank, &nil, &tail, MPI_INT, hdl->tail_rank,
157                          MCS_MTX_TAIL_DISP, hdl->window);
158     MPI_Win_flush(hdl->tail_rank, hdl->window);
159
160     /* If the old tail was MPI_PROC_NULL, we have claimed the mutex */
161     *success = (tail == nil);
162
163     debug_print("%2d: TRYLOCK - %s\n", rank, (*success) ? "Success" : "Non-success");
164
165     return MPI_SUCCESS;
166 }
167
168
169 /** Unlock a mutex.
170   *
171   * @param[in] hdl   Handle to the mutex
172   * @return          MPI status
173   */
174 int MCS_Mutex_unlock(MCS_Mutex hdl)
175 {
176     int rank, nproc, next;
177
178     MPI_Comm_rank(hdl->comm, &rank);
179     MPI_Comm_size(hdl->comm, &nproc);
180
181     MPI_Win_sync(hdl->window);
182
183     /* Read my next pointer.  FOP is used since another process may write to
184      * this location concurrent with this read. */
185     MPI_Fetch_and_op(NULL, &next, MPI_INT, rank, MCS_MTX_ELEM_DISP, MPI_NO_OP, hdl->window);
186     MPI_Win_flush(rank, hdl->window);
187
188     if (next == MPI_PROC_NULL) {
189         int tail;
190         int nil = MPI_PROC_NULL;
191
192         /* Check if we are the at the tail of the lock queue.  If so, we're
193          * done.  If not, we need to send notification. */
194         MPI_Compare_and_swap(&nil, &rank, &tail, MPI_INT, hdl->tail_rank,
195                              MCS_MTX_TAIL_DISP, hdl->window);
196         MPI_Win_flush(hdl->tail_rank, hdl->window);
197
198         if (tail != rank) {
199             debug_print("%2d: UNLOCK - waiting for next pointer (tail = %d)\n", rank, tail);
200             assert(tail >= 0 && tail < nproc);
201
202             for (;;) {
203                 int flag;
204
205                 MPI_Fetch_and_op(NULL, &next, MPI_INT, rank, MCS_MTX_ELEM_DISP,
206                                  MPI_NO_OP, hdl->window);
207
208                 MPI_Win_flush(rank, hdl->window);
209                 if (next != MPI_PROC_NULL)
210                     break;
211
212                 MPI_Iprobe(MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &flag, MPI_STATUS_IGNORE);
213             }
214         }
215     }
216
217     /* Notify the next waiting process */
218     if (next != MPI_PROC_NULL) {
219         debug_print("%2d: UNLOCK - notifying %d\n", rank, next);
220         MPI_Send(NULL, 0, MPI_BYTE, next, MCS_MUTEX_TAG, hdl->comm);
221     }
222
223     debug_print("%2d: UNLOCK - lock released\n", rank);
224
225     return MPI_SUCCESS;
226 }