#include "libgomp.h"
#include <stdlib.h>
#include <string.h>
struct gomp_work_share *
gomp_new_work_share (bool ordered, unsigned nthreads)
{
struct gomp_work_share *ws;
size_t size;
size = sizeof (*ws);
if (ordered)
size += nthreads * sizeof (ws->ordered_team_ids[0]);
ws = gomp_malloc_cleared (size);
gomp_mutex_init (&ws->lock);
ws->ordered_owner = -1;
return ws;
}
static void
free_work_share (struct gomp_work_share *ws)
{
gomp_mutex_destroy (&ws->lock);
free (ws);
}
bool
gomp_work_share_start (bool ordered)
{
struct gomp_thread *thr = gomp_thread ();
struct gomp_team *team = thr->ts.team;
struct gomp_work_share *ws;
unsigned ws_index, ws_gen;
if (team == NULL)
{
ws = gomp_new_work_share (ordered, 1);
thr->ts.work_share = ws;
thr->ts.static_trip = 0;
gomp_mutex_lock (&ws->lock);
return true;
}
gomp_mutex_lock (&team->work_share_lock);
ws_gen = ++thr->ts.work_share_generation;
if (ws_gen - team->oldest_live_gen < team->num_live_gen)
{
ws_index = ws_gen & team->generation_mask;
ws = team->work_shares[ws_index];
thr->ts.work_share = ws;
thr->ts.static_trip = 0;
gomp_mutex_lock (&ws->lock);
gomp_mutex_unlock (&team->work_share_lock);
return false;
}
if (team->num_live_gen++ == team->generation_mask)
{
team->work_shares = gomp_realloc (team->work_shares,
2 * team->num_live_gen
* sizeof (*team->work_shares));
if (team->oldest_live_gen > 0)
memcpy (team->work_shares + team->num_live_gen,
team->work_shares,
(team->oldest_live_gen & team->generation_mask)
* sizeof (*team->work_shares));
team->generation_mask = team->generation_mask * 2 + 1;
}
ws_index = ws_gen & team->generation_mask;
ws = gomp_new_work_share (ordered, team->nthreads);
thr->ts.work_share = ws;
thr->ts.static_trip = 0;
team->work_shares[ws_index] = ws;
gomp_mutex_lock (&ws->lock);
gomp_mutex_unlock (&team->work_share_lock);
return true;
}
void
gomp_work_share_end (void)
{
struct gomp_thread *thr = gomp_thread ();
struct gomp_team *team = thr->ts.team;
struct gomp_work_share *ws = thr->ts.work_share;
bool last;
thr->ts.work_share = NULL;
if (team == NULL)
{
free_work_share (ws);
return;
}
last = gomp_barrier_wait_start (&team->barrier);
if (last)
{
unsigned ws_index;
ws_index = thr->ts.work_share_generation & team->generation_mask;
team->work_shares[ws_index] = NULL;
team->oldest_live_gen++;
team->num_live_gen = 0;
free_work_share (ws);
}
gomp_barrier_wait_end (&team->barrier, last);
}
void
gomp_work_share_end_nowait (void)
{
struct gomp_thread *thr = gomp_thread ();
struct gomp_team *team = thr->ts.team;
struct gomp_work_share *ws = thr->ts.work_share;
unsigned completed;
thr->ts.work_share = NULL;
if (team == NULL)
{
free_work_share (ws);
return;
}
#ifdef HAVE_SYNC_BUILTINS
completed = __sync_add_and_fetch (&ws->threads_completed, 1);
#else
gomp_mutex_lock (&ws->lock);
completed = ++ws->threads_completed;
gomp_mutex_unlock (&ws->lock);
#endif
if (completed == team->nthreads)
{
unsigned ws_index;
gomp_mutex_lock (&team->work_share_lock);
ws_index = thr->ts.work_share_generation & team->generation_mask;
team->work_shares[ws_index] = NULL;
team->oldest_live_gen++;
team->num_live_gen--;
gomp_mutex_unlock (&team->work_share_lock);
free_work_share (ws);
}
}