00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "libgomp.h"
00029 #include <stddef.h>
00030 #include <stdlib.h>
00031 #include <string.h>
00032
00033
00034
00035
00036
00037 static struct gomp_work_share *
00038 alloc_work_share (struct gomp_team *team)
00039 {
00040 struct gomp_work_share *ws;
00041 unsigned int i;
00042
00043
00044 if (team->work_share_list_alloc != NULL)
00045 {
00046 ws = team->work_share_list_alloc;
00047 team->work_share_list_alloc = ws->next_free;
00048 return ws;
00049 }
00050
00051 #ifdef HAVE_SYNC_BUILTINS
00052 ws = team->work_share_list_free;
00053
00054
00055 __asm ("" : "+r" (ws));
00056
00057 if (ws && ws->next_free)
00058 {
00059 struct gomp_work_share *next = ws->next_free;
00060 ws->next_free = NULL;
00061 team->work_share_list_alloc = next->next_free;
00062 return next;
00063 }
00064 #else
00065 gomp_mutex_lock (&team->work_share_list_free_lock);
00066 ws = team->work_share_list_free;
00067 if (ws)
00068 {
00069 team->work_share_list_alloc = ws->next_free;
00070 team->work_share_list_free = NULL;
00071 gomp_mutex_unlock (&team->work_share_list_free_lock);
00072 return ws;
00073 }
00074 gomp_mutex_unlock (&team->work_share_list_free_lock);
00075 #endif
00076
00077 team->work_share_chunk *= 2;
00078 ws = gomp_malloc (team->work_share_chunk * sizeof (struct gomp_work_share));
00079 ws->next_alloc = team->work_shares[0].next_alloc;
00080 team->work_shares[0].next_alloc = ws;
00081 team->work_share_list_alloc = &ws[1];
00082 for (i = 1; i < team->work_share_chunk - 1; i++)
00083 ws[i].next_free = &ws[i + 1];
00084 ws[i].next_free = NULL;
00085 return ws;
00086 }
00087
00088
00089
00090
00091 void
00092 gomp_init_work_share (struct gomp_work_share *ws, bool ordered,
00093 unsigned nthreads)
00094 {
00095 gomp_mutex_init (&ws->lock);
00096 if (__builtin_expect (ordered, 0))
00097 {
00098 #define INLINE_ORDERED_TEAM_IDS_CNT \
00099 ((sizeof (struct gomp_work_share) \
00100 - offsetof (struct gomp_work_share, inline_ordered_team_ids)) \
00101 / sizeof (((struct gomp_work_share *) 0)->inline_ordered_team_ids[0]))
00102
00103 if (nthreads > INLINE_ORDERED_TEAM_IDS_CNT)
00104 ws->ordered_team_ids
00105 = gomp_malloc (nthreads * sizeof (*ws->ordered_team_ids));
00106 else
00107 ws->ordered_team_ids = ws->inline_ordered_team_ids;
00108 memset (ws->ordered_team_ids, '\0',
00109 nthreads * sizeof (*ws->ordered_team_ids));
00110 ws->ordered_num_used = 0;
00111 ws->ordered_owner = -1;
00112 ws->ordered_cur = 0;
00113 }
00114 else
00115 ws->ordered_team_ids = NULL;
00116 gomp_ptrlock_init (&ws->next_ws, NULL);
00117 ws->threads_completed = 0;
00118 }
00119
00120
00121
00122
00123 void
00124 gomp_fini_work_share (struct gomp_work_share *ws)
00125 {
00126 gomp_mutex_destroy (&ws->lock);
00127 if (ws->ordered_team_ids != ws->inline_ordered_team_ids)
00128 free (ws->ordered_team_ids);
00129 gomp_ptrlock_destroy (&ws->next_ws);
00130 }
00131
00132
00133
00134
00135 static inline void
00136 free_work_share (struct gomp_team *team, struct gomp_work_share *ws)
00137 {
00138 gomp_fini_work_share (ws);
00139 if (__builtin_expect (team == NULL, 0))
00140 free (ws);
00141 else
00142 {
00143 struct gomp_work_share *next_ws;
00144 #ifdef HAVE_SYNC_BUILTINS
00145 do
00146 {
00147 next_ws = team->work_share_list_free;
00148 ws->next_free = next_ws;
00149 }
00150 while (!__sync_bool_compare_and_swap (&team->work_share_list_free,
00151 next_ws, ws));
00152 #else
00153 gomp_mutex_lock (&team->work_share_list_free_lock);
00154 next_ws = team->work_share_list_free;
00155 ws->next_free = next_ws;
00156 team->work_share_list_free = ws;
00157 gomp_mutex_unlock (&team->work_share_list_free_lock);
00158 #endif
00159 }
00160 }
00161
00162
00163
00164
00165
00166
00167 bool
00168 gomp_work_share_start (bool ordered)
00169 {
00170 struct gomp_thread *thr = gomp_thread ();
00171 struct gomp_team *team = thr->ts.team;
00172 struct gomp_work_share *ws;
00173
00174
00175 if (team == NULL)
00176 {
00177 ws = gomp_malloc (sizeof (*ws));
00178 gomp_init_work_share (ws, ordered, 1);
00179 thr->ts.work_share = ws;
00180 return ws;
00181 }
00182
00183 ws = thr->ts.work_share;
00184 thr->ts.last_work_share = ws;
00185 ws = gomp_ptrlock_get (&ws->next_ws);
00186 if (ws == NULL)
00187 {
00188
00189 struct gomp_work_share *ws = alloc_work_share (team);
00190 gomp_init_work_share (ws, ordered, team->nthreads);
00191 thr->ts.work_share = ws;
00192 return true;
00193 }
00194 else
00195 {
00196 thr->ts.work_share = ws;
00197 return false;
00198 }
00199 }
00200
00201
00202
00203
00204 void
00205 gomp_work_share_end (void)
00206 {
00207 struct gomp_thread *thr = gomp_thread ();
00208 struct gomp_team *team = thr->ts.team;
00209 gomp_barrier_state_t bstate;
00210
00211
00212 if (team == NULL)
00213 {
00214 free_work_share (NULL, thr->ts.work_share);
00215 thr->ts.work_share = NULL;
00216 return;
00217 }
00218
00219 bstate = gomp_barrier_wait_start (&team->barrier);
00220
00221 if (gomp_barrier_last_thread (bstate))
00222 {
00223 if (__builtin_expect (thr->ts.last_work_share != NULL, 1))
00224 free_work_share (team, thr->ts.last_work_share);
00225 }
00226
00227 gomp_team_barrier_wait_end (&team->barrier, bstate);
00228 thr->ts.last_work_share = NULL;
00229 }
00230
00231
00232
00233
00234 void
00235 gomp_work_share_end_nowait (void)
00236 {
00237 struct gomp_thread *thr = gomp_thread ();
00238 struct gomp_team *team = thr->ts.team;
00239 struct gomp_work_share *ws = thr->ts.work_share;
00240 unsigned completed;
00241
00242
00243 if (team == NULL)
00244 {
00245 free_work_share (NULL, ws);
00246 thr->ts.work_share = NULL;
00247 return;
00248 }
00249
00250 if (__builtin_expect (thr->ts.last_work_share == NULL, 0))
00251 return;
00252
00253 #ifdef HAVE_SYNC_BUILTINS
00254 completed = __sync_add_and_fetch (&ws->threads_completed, 1);
00255 #else
00256 gomp_mutex_lock (&ws->lock);
00257 completed = ++ws->threads_completed;
00258 gomp_mutex_unlock (&ws->lock);
00259 #endif
00260
00261 if (completed == team->nthreads)
00262 free_work_share (team, thr->ts.last_work_share);
00263 thr->ts.last_work_share = NULL;
00264 }