//
// Copyright (c) 2009-2011, ERICSSON AB
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the ERICSSON AB nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include "ivar.h"
#include <stdlib.h>
#include <string.h>
//#define LOG
#include "log.h"
int feldspar_ivar_hook(void)
{
return 0;
}
void *worker( void *p );
void ivar_init( struct ivar *iv )
{
struct ivar_internals *ivi;
int err;
log_1("ivar_init %p - enter\n", iv);
ivi = iv->internals = (struct ivar_internals*)malloc( sizeof(struct ivar_internals) );
err = pthread_mutex_init( &(ivi->mutex), NULL );
if (err) exit(err);
err = pthread_cond_init( &(ivi->cond), NULL );
if (err) exit(err);
ivi->full = 0;
iv->self = iv;
log_1("ivar_init %p - leave\n", iv);
}
void ivar_destroy( struct ivar *iv ) // TODO: Think about ivars escaping from their scope...
{
log_1("ivar_destroy %p - enter\n", iv);
// if( iv->self == iv ) // This is true iff this iVar is not a copy.
// {
// struct ivar_internals *ivi = iv->internals;
// pthread_mutex_destroy( &(ivi->mutex) );
// pthread_cond_destroy( &(ivi->cond) );
// if( ivi->full )
// free( ivi->data );
// free( ivi );
// }
log_1("ivar_destroy %p - leave\n", iv);
}
void ivar_put_with_size( struct ivar iv, void *d, int size )
{
struct ivar_internals *ivi = iv.internals;
log_3("ivar_put_with_size %p %p %d - enter\n", &iv, d, size);
pthread_mutex_lock( &(ivi->mutex) );
ivi->data = (void*)malloc( size );
memcpy( ivi->data, d, size );
ivi->full = 1;
pthread_cond_broadcast( &(ivi->cond) );
pthread_mutex_unlock( &(ivi->mutex) );
log_3("ivar_put_with_size %p %p %d - leave\n", &iv, d, size);
}
void ivar_put_array( struct ivar iv, struct array *d )
{
struct ivar_internals *ivi = iv.internals;
log_2("ivar_put_array %p %p - enter\n", &iv, d);
pthread_mutex_lock( &(ivi->mutex) );
ivi->data = (void*)malloc( sizeof(struct array) );
initArray( ivi->data, d->elemSize, d->length );
copyArray( ivi->data, d );
ivi->full = 1;
pthread_cond_broadcast( &(ivi->cond) );
pthread_mutex_unlock( &(ivi->mutex) );
log_2("ivar_put_array %p %p - leave\n", &iv, d);
}
void ivar_get_helper( struct ivar_internals *iv )
{
log_1("ivar_get_helper %p - enter\n", iv);
pthread_mutex_lock( &(iv->mutex) );
if( !iv->full )
{
log_1("ivar_get_helper %p - ivar is empty\n", iv);
int create = 0;
pthread_mutex_lock( &(feldspar_taskpool.mutex) );
if( !feldspar_taskpool.shutdown && (feldspar_taskpool.num_threads <= feldspar_taskpool.min_threads) )
{
create = 1;
++feldspar_taskpool.num_threads;
log_3("ivar_get_helper %p - will create a new thread; "
"active: %d, all: %d\n"
, iv, feldspar_taskpool.act_threads, feldspar_taskpool.num_threads);
}
else
{
--feldspar_taskpool.act_threads;
log_3("ivar_get_helper %p - will NOT create a new thread; "
"active: %d, all: %d\n"
, iv, feldspar_taskpool.act_threads, feldspar_taskpool.num_threads);
}
pthread_mutex_unlock( &(feldspar_taskpool.mutex) );
if( create )
{
pthread_t th;
pthread_create( &th, NULL, &worker, (void*)&feldspar_taskpool );
}
log_1("ivar_get_helper %p - blocking while waiting for data\n", iv);
pthread_cond_wait( &(iv->cond), &(iv->mutex) );
pthread_mutex_lock( &(feldspar_taskpool.mutex) );
++feldspar_taskpool.act_threads;
log_3("ivar_get_helper %p - data arrived; active: %d, all: %d\n"
, iv, feldspar_taskpool.act_threads, feldspar_taskpool.num_threads);
pthread_mutex_unlock( &(feldspar_taskpool.mutex) );
}
pthread_mutex_unlock( &(iv->mutex) );
log_1("ivar_get_helper %p - leave\n", iv);
}
void ivar_get_with_size( void *var, struct ivar iv, int size )
{
log_3("ivar_get_with_size %p %p %d - enter\n", var, &iv, size);
ivar_get_helper(iv.internals);
memcpy( var, iv.internals->data, size );
log_3("ivar_get_with_size %p %p %d - leave\n", var, &iv, size);
}
void ivar_get_array( struct array *var, struct ivar iv )
{
struct array *ptr;
log_2("ivar_get_array %p %p - enter\n", var, &iv);
ivar_get_helper(iv.internals);
ptr = (struct array*)iv.internals->data;
assert(ptr);
initArray( var, ptr->elemSize, ptr->length );
copyArray( var, ptr );
log_2("ivar_get_array %p %p - leave\n", var, &iv);
}
void ivar_get_nontask_with_size( void *var, struct ivar iv, int size )
{
struct ivar_internals *ivi = iv.internals;
log_3("ivar_get_nontask_with_size %p %p %d - enter\n", var, &iv, size);
pthread_mutex_lock( &(ivi->mutex) );
if ( !ivi->full )
log_3("ivar_get_nontask_with_size %p %p %d -> waiting for data\n"
, var, &iv, size);
while( !ivi->full )
{
int err = pthread_cond_wait( &(ivi->cond), &(ivi->mutex) );
if (err) { exit(err); }
}
pthread_mutex_unlock( &(ivi->mutex) );
assert(ivi->data);
memcpy( var, ivi->data, size );
log_3("ivar_get_nontask_with_size %p %p %d - leave\n", var, &iv, size);
}
void ivar_get_array_nontask( struct array *var, struct ivar iv )
{
struct ivar_internals *ivi = iv.internals;
struct array *ptr;
log_2("ivar_get_array_nontask %p %p - enter\n", var, &iv);
pthread_mutex_lock( &(ivi->mutex) );
if ( !ivi->full )
log_2("ivar_get_array_nontask %p %p - waiting for data\n", var, &iv);
while(!ivi->full)
{
int err = pthread_cond_wait( &(ivi->cond), &(ivi->mutex) );
if (err) { exit(err); }
}
assert(ivi->full);
pthread_mutex_unlock( &(ivi->mutex) );
if (NULL == ivi->data)
{
log_2("ivar_get_array_nontask %p %p - data uninitialized\n", var, &iv);
}
else
{
ptr = (struct array*)ivi->data;
initArray( var, ptr->elemSize, ptr->length );
copyArray( var, ptr );
}
log_2("ivar_get_array_nontask %p %p - leave\n", var, &iv);
}