task.c 7.27 KB
Newer Older
1
/*******************************************************************************
2
 * This file is part of SWIFT.
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
 * Coypright (c) 2012 Pedro Gonnet (pedro.gonnet@durham.ac.uk)
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 ******************************************************************************/

/* Config parameters. */
#include "../config.h"

/* Some standard headers. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <math.h>
#include <float.h>
#include <limits.h>
#include <omp.h>
#include <sched.h>

34
35
36
37
38
/* MPI headers. */
#ifdef WITH_MPI
    #include <mpi.h>
#endif

39
/* Local headers. */
40
#include "const.h"
41
#include "cycle.h"
Pedro Gonnet's avatar
Pedro Gonnet committed
42
#include "atomic.h"
43
#include "lock.h"
44
#include "space.h"
45
46
#include "part.h"
#include "multipole.h"
47
#include "cell.h"
48
#include "task.h"
49
#include "error.h"
50
51

/* Task type names. */
52
53
const char *taskID_names[task_type_count] = {   
    "none" , "sort" , "self" , "pair" , "sub" , "ghost" , 
54
55
    "kick1" , "kick2" , "send" , "recv" , "link" , "grav_pp" ,
    "grav_mm" , "grav_up" , "grav_down" };
56
57


58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
/**
 * @brief Unlock the cell held by this task.
 * 
 * @param t The #task.
 */
 
void task_unlock ( struct task *t ) {

    /* Act based on task type. */
    switch ( t->type ) {
        case task_type_self:
        case task_type_sort:
            cell_unlocktree( t->ci );
            break;
        case task_type_pair:
        case task_type_sub:
            cell_unlocktree( t->ci );
            if ( t->cj != NULL )
                cell_unlocktree( t->cj );
            break;
78
79
80
81
82
83
84
85
86
        case task_type_grav_pp:
        case task_type_grav_mm:
        case task_type_grav_down:
            cell_gunlocktree( t->ci );
            if ( t->cj != NULL )
                cell_gunlocktree( t->cj );
            break;
        default:
            break;
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
        }
        
    }


/**
 * @brief Try to lock the cells associated with this task.
 *
 * @param t the #task.
 */
 
int task_lock ( struct task *t ) {

    int type = t->type;
    struct cell *ci = t->ci, *cj = t->cj;

103
    /* Communication task? */
104
105
    if ( type == task_type_recv ||
         type == task_type_send ) {
106
107
108
109
110
111
112
113
114
    
        #ifdef WITH_MPI
            /* Check the status of the MPI request. */
            int res, err;
            MPI_Status stat;
            if ( ( err = MPI_Test( &t->req , &res , &stat ) ) != MPI_SUCCESS ) {
                char buff[ MPI_MAX_ERROR_STRING ];
                int len;
                MPI_Error_string( err , buff , &len );
Pedro Gonnet's avatar
Pedro Gonnet committed
115
                error( "Failed to test request on send/recv task (tag=%i, %s)." , t->flags , buff );
116
117
118
119
120
121
122
123
                }
            return res;
        #else
            error( "SWIFT was not compiled with MPI support." );
        #endif
    
        }

124
    /* Unary lock? */
125
    else if ( type == task_type_self || 
126
127
128
129
130
131
132
         type == task_type_sort || 
         (type == task_type_sub && cj == NULL) ) {
        if ( cell_locktree( ci ) != 0 )
            return 0;
        }
        
    /* Otherwise, binary lock. */
133
134
135
    else if ( type == task_type_pair || 
              ( type == task_type_sub && cj != NULL ) ) {
        if ( ci->hold || cj->hold )
136
137
138
139
140
            return 0;
        if ( cell_locktree( ci ) != 0 )
            return 0;
        if ( cell_locktree( cj ) != 0 ) {
            cell_unlocktree( ci );
141
142
143
144
145
146
147
148
149
150
151
152
153
154
            return 0;
            }
        }
        
    /* Gravity tasks? */
    else if ( type == task_type_grav_mm ||
              type == task_type_grav_pp ||
              type == task_type_grav_down ) {
        if ( ci->ghold || ( cj != NULL && cj->ghold ) )
            return 0;
        if ( cell_glocktree( ci ) != 0 )
            return 0;
        if ( cj != NULL && cell_glocktree( cj ) != 0 ) {
            cell_gunlocktree( ci );
155
156
157
158
159
160
161
162
163
164
            return 0;
            }
        }
        
    /* If we made it this far, we've got a lock. */
    return 1;
            
    }


165
/**
166
 * @brief Remove all unlocks to tasks that are of the given type.
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
 *
 * @param t The #task.
 * @param type The task type ID to remove.
 */
 
void task_cleanunlock ( struct task *t , int type ) {

    int k;
    
    lock_lock( &t->lock );
    
    for ( k = 0 ; k < t->nr_unlock_tasks ; k++ )
        if ( t->unlock_tasks[k]->type == type ) {
            t->nr_unlock_tasks -= 1;
            t->unlock_tasks[k] = t->unlock_tasks[ t->nr_unlock_tasks ];
            }
    
    lock_unlock_blind( &t->lock );
    
    }


189
190
191
192
193
194
195
/**
 * @brief Remove an unlock_task from the given task.
 *
 * @param ta The unlocking #task.
 * @param tb The #task that will be unlocked.
 */
 
196
void task_rmunlock ( struct task *ta , struct task *tb ) {
197
198
199

    int k;
    
200
201
    lock_lock( &ta->lock );
    
202
203
204
205
    for ( k = 0 ; k < ta->nr_unlock_tasks ; k++ )
        if ( ta->unlock_tasks[k] == tb ) {
            ta->nr_unlock_tasks -= 1;
            ta->unlock_tasks[k] = ta->unlock_tasks[ ta->nr_unlock_tasks ];
206
            lock_unlock_blind( &ta->lock );
207
208
209
210
211
212
213
            return;
            }
    error( "Task not found." );

    }
    

Pedro Gonnet's avatar
Pedro Gonnet committed
214
215
216
217
218
219
220
221
222
223
/**
 * @brief Remove an unlock_task from the given task.
 *
 * @param ta The unlocking #task.
 * @param tb The #task that will be unlocked.
 *
 * Differs from #task_rmunlock in that it will not fail if
 * the task @c tb is not in the unlocks of @c ta.
 */
 
224
void task_rmunlock_blind ( struct task *ta , struct task *tb ) {
Pedro Gonnet's avatar
Pedro Gonnet committed
225
226
227

    int k;
    
228
229
    lock_lock( &ta->lock );
    
Pedro Gonnet's avatar
Pedro Gonnet committed
230
231
232
233
    for ( k = 0 ; k < ta->nr_unlock_tasks ; k++ )
        if ( ta->unlock_tasks[k] == tb ) {
            ta->nr_unlock_tasks -= 1;
            ta->unlock_tasks[k] = ta->unlock_tasks[ ta->nr_unlock_tasks ];
234
            break;
Pedro Gonnet's avatar
Pedro Gonnet committed
235
            }
236
237
            
    lock_unlock_blind( &ta->lock );
Pedro Gonnet's avatar
Pedro Gonnet committed
238
239
240
241

    }
    

242
243
244
245
246
247
248
/**
 * @brief Add an unlock_task to the given task.
 *
 * @param ta The unlocking #task.
 * @param tb The #task that will be unlocked.
 */
 
249
void task_addunlock ( struct task *ta , struct task *tb ) {
250

251
252
    error( "Use sched_addunlock instead." );

253
    /* Add the lock atomically. */
Pedro Gonnet's avatar
Pedro Gonnet committed
254
    ta->unlock_tasks[ atomic_inc( &ta->nr_unlock_tasks ) ] = tb;
255
256
257
258
259
260
261
262

    /* Check a posteriori if we did not overshoot. */
    if ( ta->nr_unlock_tasks > task_maxunlock )
        error( "Too many unlock_tasks in task." );
        
    }
    

263
void task_addunlock_old ( struct task *ta , struct task *tb ) {
264
265
266

    int k;
    
267
268
    lock_lock( &ta->lock );
    
269
270
    /* Check if ta already unlocks tb. */
    for ( k = 0 ; k < ta->nr_unlock_tasks ; k++ )
271
        if ( ta->unlock_tasks[k] == tb ) {
272
            error( "Duplicate unlock." );
273
            lock_unlock_blind( &ta->lock );
274
            return;
275
            }
276
277
278
279
280
281
282

    if ( ta->nr_unlock_tasks == task_maxunlock )
        error( "Too many unlock_tasks in task." );
        
    ta->unlock_tasks[ ta->nr_unlock_tasks] = tb;
    ta->nr_unlock_tasks += 1;

283
284
    lock_unlock_blind( &ta->lock );
    
285
286
287
    }