task.c 5.61 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
34
35
 * 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>

/* Local headers. */
#include "cycle.h"
Pedro Gonnet's avatar
Pedro Gonnet committed
36
#include "atomic.h"
37
#include "lock.h"
38
#include "cell.h"
39
#include "task.h"
40
#include "error.h"
41
42

/* Task type names. */
43
const char *taskID_names[task_type_count] = { "none" , "sort" , "self" , "pair" , "sub" , "ghost" , "kick1" , "kick2" };
44
45


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/**
 * @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;
        }
        
    }


/**
 * @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;

    /* Unary lock? */
    if ( type == task_type_self || 
         type == task_type_sort || 
         (type == task_type_sub && cj == NULL) ) {
        if ( cell_locktree( ci ) != 0 )
            return 0;
        }
        
    /* Otherwise, binary lock. */
    else if ( type == task_type_pair || (type == task_type_sub && cj != NULL) ) {
        if ( ci->hold || cj->hold || ci->wait || cj->wait )
            return 0;
        if ( cell_locktree( ci ) != 0 )
            return 0;
        if ( cell_locktree( cj ) != 0 ) {
            cell_unlocktree( ci );
            return 0;
            }
        }
        
    /* If we made it this far, we've got a lock. */
    return 1;
            
    }


108
/**
109
 * @brief Remove all unlocks to tasks that are of the given type.
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
 *
 * @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 );
    
    }


132
133
134
135
136
137
138
/**
 * @brief Remove an unlock_task from the given task.
 *
 * @param ta The unlocking #task.
 * @param tb The #task that will be unlocked.
 */
 
139
void task_rmunlock ( struct task *ta , struct task *tb ) {
140
141
142

    int k;
    
143
144
    lock_lock( &ta->lock );
    
145
146
147
148
    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 ];
149
            lock_unlock_blind( &ta->lock );
150
151
152
153
154
155
156
            return;
            }
    error( "Task not found." );

    }
    

Pedro Gonnet's avatar
Pedro Gonnet committed
157
158
159
160
161
162
163
164
165
166
/**
 * @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.
 */
 
167
void task_rmunlock_blind ( struct task *ta , struct task *tb ) {
Pedro Gonnet's avatar
Pedro Gonnet committed
168
169
170

    int k;
    
171
172
    lock_lock( &ta->lock );
    
Pedro Gonnet's avatar
Pedro Gonnet committed
173
174
175
176
    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 ];
177
            break;
Pedro Gonnet's avatar
Pedro Gonnet committed
178
            }
179
180
            
    lock_unlock_blind( &ta->lock );
Pedro Gonnet's avatar
Pedro Gonnet committed
181
182
183
184

    }
    

185
186
187
188
189
190
191
/**
 * @brief Add an unlock_task to the given task.
 *
 * @param ta The unlocking #task.
 * @param tb The #task that will be unlocked.
 */
 
192
void task_addunlock ( struct task *ta , struct task *tb ) {
193
194

    /* Add the lock atomically. */
Pedro Gonnet's avatar
Pedro Gonnet committed
195
    ta->unlock_tasks[ atomic_inc( &ta->nr_unlock_tasks ) ] = tb;
196
197
198
199
200
201
202
203

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

204
void task_addunlock_old ( struct task *ta , struct task *tb ) {
205
206
207

    int k;
    
208
209
    lock_lock( &ta->lock );
    
210
211
    /* Check if ta already unlocks tb. */
    for ( k = 0 ; k < ta->nr_unlock_tasks ; k++ )
212
        if ( ta->unlock_tasks[k] == tb ) {
213
            error( "Duplicate unlock." );
214
            lock_unlock_blind( &ta->lock );
215
            return;
216
            }
217
218
219
220
221
222
223

    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;

224
225
    lock_unlock_blind( &ta->lock );
    
226
227
228
    }