// // 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 #include //#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); }