//
// 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.
//
#ifndef TASKPOOL_H
#define TASKPOOL_H
#include <pthread.h>
int feldspar_taskpool_hook(void);
struct taskpool
{
int capacity;
int num_threads, act_threads, min_threads, max_threads;
int head, tail;
void **closures;
int shutdown;
pthread_mutex_t mutex;
};
void taskpool_init( int c, int num, int min );
void taskpool_shutdown();
void spawn( void *closure );
/* Helper macro: */
/* TODO: Replace runtime check with a compile time one! */
#define check_array( t, temp ) \
if( !strcmp(#t,"struct array *") ) \
{ \
void *m = malloc( sizeof(struct array) ); \
memcpy( m, *(void**)(&(temp)), sizeof(struct array) ); \
memcpy( (void*)&(temp), (void*)&m, sizeof(void*) ); \
} \
/* Wrappers for spawn with different number of arguments: */
#define spawn0( task ) \
{ \
void *buffer = malloc( sizeof(void(*)()) ); \
char *p = buffer; \
void *t0 = &task; \
memcpy( p, &t0, sizeof(void(*)()) ); \
spawn( buffer ); \
} \
#define spawn1( task, t1, p1 ) \
{ \
void *buffer = malloc( sizeof(void(*)()) + sizeof(t1) ); \
char *p = buffer; \
void *t0 = &task; \
t1 temp1 = (p1); \
memcpy( p, &t0, sizeof(void(*)()) ); \
p += sizeof(void(*)()); \
check_array( t1, temp1 ); \
memcpy( p, &temp1, sizeof(t1) ); \
spawn( buffer ); \
} \
#define spawn2( task, t1, p1, t2, p2 ) \
{ \
void *buffer = malloc( sizeof(void(*)()) + sizeof(t1) + sizeof(t2) ); \
char *p = buffer; \
void *t0 = &task; \
t1 temp1 = (p1); \
t2 temp2 = (p2); \
memcpy( p, &t0, sizeof(void(*)()) ); \
p += sizeof(void(*)()); \
check_array( t1, temp1 ); \
memcpy( p, &temp1, sizeof(t1) ); \
p += sizeof(t1); \
check_array( t2, temp2 ); \
memcpy( p, &temp2, sizeof(t2) ); \
spawn( buffer ); \
} \
#define spawn3( task, t1, p1, t2, p2, t3, p3 ) \
{ \
void *buffer = malloc( sizeof(void(*)()) + sizeof(t1) + sizeof(t2) + sizeof(t3) ); \
char *p = buffer; \
void *t0 = &task; \
t1 temp1 = (p1); \
t2 temp2 = (p2); \
t3 temp3 = (p3); \
memcpy( p, &t0, sizeof(void(*)()) ); \
p += sizeof(void(*)()); \
check_array( t1, temp1 ); \
memcpy( p, &temp1, sizeof(t1) ); \
p += sizeof(t1); \
check_array( t2, temp2 ); \
memcpy( p, &temp2, sizeof(t2) ); \
p += sizeof(t2); \
check_array( t3, temp3 ); \
memcpy( p, &temp3, sizeof(t3) ); \
spawn( buffer ); \
} \
#define spawn4( task, t1, p1, t2, p2, t3, p3, t4, p4 ) \
{ \
void *buffer = malloc( sizeof(void(*)()) + sizeof(t1) + sizeof(t2) + sizeof(t3) + sizeof(t4) ); \
char *p = buffer; \
void *t0 = &task; \
t1 temp1 = (p1); \
t2 temp2 = (p2); \
t3 temp3 = (p3); \
t4 temp4 = (p4); \
memcpy( p, &t0, sizeof(void(*)()) ); \
p += sizeof(void(*)()); \
check_array( t1, temp1 ); \
memcpy( p, &temp1, sizeof(t1) ); \
p += sizeof(t1); \
check_array( t2, temp2 ); \
memcpy( p, &temp2, sizeof(t2) ); \
p += sizeof(t2); \
check_array( t3, temp3 ); \
memcpy( p, &temp3, sizeof(t3) ); \
p += sizeof(t3); \
check_array( t4, temp4 ); \
memcpy( p, &temp4, sizeof(t4) ); \
spawn( buffer ); \
} \
#define spawn5( task, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5 ) \
{ \
void *buffer = malloc( sizeof(void(*)()) + sizeof(t1) + sizeof(t2) + sizeof(t3) + sizeof(t4) + sizeof(t5) ); \
char *p = buffer; \
void *t0 = &task; \
t1 temp1 = (p1); \
t2 temp2 = (p2); \
t3 temp3 = (p3); \
t4 temp4 = (p4); \
t5 temp5 = (p5); \
memcpy( p, &t0, sizeof(void(*)()) ); \
p += sizeof(void(*)()); \
check_array( t1, temp1 ); \
memcpy( p, &temp1, sizeof(t1) ); \
p += sizeof(t1); \
check_array( t2, temp2 ); \
memcpy( p, &temp2, sizeof(t2) ); \
p += sizeof(t2); \
check_array( t3, temp3 ); \
memcpy( p, &temp3, sizeof(t3) ); \
p += sizeof(t3); \
check_array( t4, temp4 ); \
memcpy( p, &temp4, sizeof(t4) ); \
p += sizeof(t4); \
check_array( t5, temp5 ); \
memcpy( p, &temp5, sizeof(t5) ); \
spawn( buffer ); \
} \
#define spawn6( task, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6 ) \
{ \
void *buffer = malloc( sizeof(void(*)()) + sizeof(t1) + sizeof(t2) + sizeof(t3) + sizeof(t4) + sizeof(t5) + sizeof(t6) ); \
char *p = buffer; \
void *t0 = &task; \
t1 temp1 = (p1); \
t2 temp2 = (p2); \
t3 temp3 = (p3); \
t4 temp4 = (p4); \
t5 temp5 = (p5); \
t6 temp6 = (p6); \
memcpy( p, &t0, sizeof(void(*)()) ); \
p += sizeof(void(*)()); \
check_array( t1, temp1 ); \
memcpy( p, &temp1, sizeof(t1) ); \
p += sizeof(t1); \
check_array( t2, temp2 ); \
memcpy( p, &temp2, sizeof(t2) ); \
p += sizeof(t2); \
check_array( t3, temp3 ); \
memcpy( p, &temp3, sizeof(t3) ); \
p += sizeof(t3); \
check_array( t4, temp4 ); \
memcpy( p, &temp4, sizeof(t4) ); \
p += sizeof(t4); \
check_array( t5, temp5 ); \
memcpy( p, &temp5, sizeof(t5) ); \
p += sizeof(t5); \
check_array( t6, temp6 ); \
memcpy( p, &temp6, sizeof(t6) ); \
spawn( buffer ); \
} \
#define spawn7( task, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6 , t7, p7 ) \
{ \
void *buffer = malloc( sizeof(void(*)()) + sizeof(t1) + sizeof(t2) + sizeof(t3) + sizeof(t4) + sizeof(t5) + sizeof(t6) + sizeof(t7) ); \
char *p = buffer; \
void *t0 = &task; \
t1 temp1 = (p1); \
t2 temp2 = (p2); \
t3 temp3 = (p3); \
t4 temp4 = (p4); \
t5 temp5 = (p5); \
t6 temp6 = (p6); \
t7 temp7 = (p7); \
memcpy( p, &t0, sizeof(void(*)()) ); \
p += sizeof(void(*)()); \
check_array( t1, temp1 ); \
memcpy( p, &temp1, sizeof(t1) ); \
p += sizeof(t1); \
check_array( t2, temp2 ); \
memcpy( p, &temp2, sizeof(t2) ); \
p += sizeof(t2); \
check_array( t3, temp3 ); \
memcpy( p, &temp3, sizeof(t3) ); \
p += sizeof(t3); \
check_array( t4, temp4 ); \
memcpy( p, &temp4, sizeof(t4) ); \
p += sizeof(t4); \
check_array( t5, temp5 ); \
memcpy( p, &temp5, sizeof(t5) ); \
p += sizeof(t5); \
check_array( t6, temp6 ); \
memcpy( p, &temp6, sizeof(t6) ); \
p += sizeof(t6); \
check_array( t7, temp7 ); \
memcpy( p, &temp7, sizeof(t7) ); \
spawn( buffer ); \
} \
/* Wrappers for task cores with different number of arguments: */
#define run0( task_core ) \
{ \
(task_core)(); \
} \
#define run1( task_core, t1 ) \
{ \
t1 p1; \
char *p = params; \
memcpy( &p1, p, sizeof(t1) ); \
(task_core)(p1); \
} \
#define run2( task_core, t1, t2 ) \
{ \
t1 p1; \
t2 p2; \
char *p = params; \
memcpy( &p1, p, sizeof(t1) ); \
p += sizeof(t1); \
memcpy( &p2, p, sizeof(t2) ); \
(task_core)(p1,p2); \
} \
#define run3( task_core, t1, t2, t3 ) \
{ \
t1 p1; \
t2 p2; \
t3 p3; \
char *p = params; \
memcpy( &p1, p, sizeof(t1) ); \
p += sizeof(t1); \
memcpy( &p2, p, sizeof(t2) ); \
p += sizeof(t2); \
memcpy( &p3, p, sizeof(t3) ); \
(task_core)(p1,p2,p3); \
} \
#define run4( task_core, t1, t2, t3, t4 ) \
{ \
t1 p1; \
t2 p2; \
t3 p3; \
t4 p4; \
char *p = params; \
memcpy( &p1, p, sizeof(t1) ); \
p += sizeof(t1); \
memcpy( &p2, p, sizeof(t2) ); \
p += sizeof(t2); \
memcpy( &p3, p, sizeof(t3) ); \
p += sizeof(t3); \
memcpy( &p4, p, sizeof(t4) ); \
(task_core)(p1,p2,p3,p4); \
} \
#define run5( task_core, t1, t2, t3, t4, t5 ) \
{ \
t1 p1; \
t2 p2; \
t3 p3; \
t4 p4; \
t5 p5; \
char *p = params; \
memcpy( &p1, p, sizeof(t1) ); \
p += sizeof(t1); \
memcpy( &p2, p, sizeof(t2) ); \
p += sizeof(t2); \
memcpy( &p3, p, sizeof(t3) ); \
p += sizeof(t3); \
memcpy( &p4, p, sizeof(t4) ); \
p += sizeof(t4); \
memcpy( &p5, p, sizeof(t5) ); \
(task_core)(p1,p2,p3,p4,p5); \
} \
#define run6( task_core, t1, t2, t3, t4, t5, t6 ) \
{ \
t1 p1; \
t2 p2; \
t3 p3; \
t4 p4; \
t5 p5; \
t6 p6; \
char *p = params; \
memcpy( &p1, p, sizeof(t1) ); \
p += sizeof(t1); \
memcpy( &p2, p, sizeof(t2) ); \
p += sizeof(t2); \
memcpy( &p3, p, sizeof(t3) ); \
p += sizeof(t3); \
memcpy( &p4, p, sizeof(t4) ); \
p += sizeof(t4); \
memcpy( &p5, p, sizeof(t5) ); \
p += sizeof(t5); \
memcpy( &p6, p, sizeof(t6) ); \
(task_core)(p1,p2,p3,p4,p5,p6); \
} \
#define run7( task_core, t1, t2, t3, t4, t5, t6, t7 ) \
{ \
t1 p1; \
t2 p2; \
t3 p3; \
t4 p4; \
t5 p5; \
t6 p6; \
t7 p7; \
char *p = params; \
memcpy( &p1, p, sizeof(t1) ); \
p += sizeof(t1); \
memcpy( &p2, p, sizeof(t2) ); \
p += sizeof(t2); \
memcpy( &p3, p, sizeof(t3) ); \
p += sizeof(t3); \
memcpy( &p4, p, sizeof(t4) ); \
p += sizeof(t4); \
memcpy( &p5, p, sizeof(t5) ); \
p += sizeof(t5); \
memcpy( &p6, p, sizeof(t6) ); \
p += sizeof(t6); \
memcpy( &p7, p, sizeof(t7) ); \
(task_core)(p1,p2,p3,p4,p5,p6,p7); \
} \
#endif /* TASKPOOL_H */