#include "dsynth.h"
typedef struct job {
pthread_t td;
pthread_cond_t cond;
bulk_t *active;
int terminate : 1;
} job_t;
static int BulkScanJob;
static int BulkCurJobs;
static int BulkMaxJobs;
static job_t JobsAry[MAXBULK];
static void (*BulkFunc)(bulk_t *bulk);
static bulk_t *BulkSubmit;
static bulk_t **BulkSubmitTail = &BulkSubmit;
static bulk_t *BulkResponse;
static bulk_t **BulkResponseTail = &BulkResponse;
static pthread_cond_t BulkResponseCond;
static pthread_mutex_t BulkMutex;
static void bulkstart(void);
#if 0
static int readall(int fd, void *buf, size_t bytes);
static int writeall(int fd, const void *buf, size_t bytes);
#endif
static void *bulkthread(void *arg);
void
initbulk(void (*func)(bulk_t *bulk), int jobs)
{
int i;
if (jobs > MAXBULK)
jobs = MAXBULK;
ddassert(BulkSubmit == NULL);
BulkCurJobs = 0;
BulkMaxJobs = jobs;
BulkFunc = func;
BulkScanJob = 0;
addbuildenv("__MAKE_CONF", "/dev/null",
BENV_ENVIRONMENT | BENV_PKGLIST);
if (UseCCache) {
addbuildenv("WITH_CCACHE_BUILD", "yes", BENV_MAKECONF);
addbuildenv("CCACHE_DIR", CCachePath, BENV_MAKECONF);
}
pthread_mutex_init(&BulkMutex, NULL);
pthread_cond_init(&BulkResponseCond, NULL);
pthread_mutex_lock(&BulkMutex);
for (i = 0; i < jobs; ++i) {
pthread_cond_init(&JobsAry[i].cond, NULL);
pthread_create(&JobsAry[i].td, NULL, bulkthread, &JobsAry[i]);
}
pthread_mutex_unlock(&BulkMutex);
}
void
donebulk(void)
{
bulk_t *bulk;
int i;
pthread_mutex_lock(&BulkMutex);
while ((bulk = BulkSubmit) != NULL) {
BulkSubmit = bulk->next;
freebulk(bulk);
}
BulkSubmitTail = &BulkSubmit;
for (i = 0; i < BulkMaxJobs; ++i) {
JobsAry[i].terminate = 1;
pthread_cond_signal(&JobsAry[i].cond);
}
pthread_mutex_unlock(&BulkMutex);
for (i = 0; i < BulkMaxJobs; ++i) {
pthread_join(JobsAry[i].td, NULL);
pthread_cond_destroy(&JobsAry[i].cond);
if (JobsAry[i].active) {
freebulk(JobsAry[i].active);
JobsAry[i].active = NULL;
pthread_mutex_lock(&BulkMutex);
--BulkCurJobs;
pthread_mutex_unlock(&BulkMutex);
}
JobsAry[i].terminate = 0;
}
ddassert(BulkCurJobs == 0);
while ((bulk = BulkResponse) != NULL) {
BulkResponse = bulk->next;
freebulk(bulk);
}
BulkResponseTail = &BulkResponse;
BulkFunc = NULL;
bzero(JobsAry, sizeof(JobsAry));
if (UseCCache) {
delbuildenv("WITH_CCACHE_BUILD");
delbuildenv("CCACHE_DIR");
}
delbuildenv("__MAKE_CONF");
}
void
queuebulk(const char *s1, const char *s2, const char *s3, const char *s4)
{
bulk_t *bulk;
bulk = calloc(1, sizeof(*bulk));
if (s1)
bulk->s1 = strdup(s1);
if (s2)
bulk->s2 = strdup(s2);
if (s3)
bulk->s3 = strdup(s3);
if (s4)
bulk->s4 = strdup(s4);
bulk->state = ONSUBMIT;
pthread_mutex_lock(&BulkMutex);
*BulkSubmitTail = bulk;
BulkSubmitTail = &bulk->next;
if (BulkCurJobs < BulkMaxJobs) {
pthread_mutex_unlock(&BulkMutex);
bulkstart();
} else {
pthread_mutex_unlock(&BulkMutex);
}
}
static
void
bulkstart(void)
{
bulk_t *bulk;
int i;
pthread_mutex_lock(&BulkMutex);
while ((bulk = BulkSubmit) != NULL && BulkCurJobs < BulkMaxJobs) {
i = BulkScanJob + 1;
for (;;) {
i = i % BulkMaxJobs;
if (JobsAry[i].active == NULL)
break;
++i;
}
BulkScanJob = i;
BulkSubmit = bulk->next;
if (BulkSubmit == NULL)
BulkSubmitTail = &BulkSubmit;
bulk->state = ONRUN;
JobsAry[i].active = bulk;
pthread_cond_signal(&JobsAry[i].cond);
++BulkCurJobs;
}
pthread_mutex_unlock(&BulkMutex);
}
bulk_t *
getbulk(void)
{
bulk_t *bulk;
pthread_mutex_lock(&BulkMutex);
while (BulkCurJobs && BulkResponse == NULL) {
pthread_cond_wait(&BulkResponseCond, &BulkMutex);
}
if (BulkResponse) {
bulk = BulkResponse;
ddassert(bulk->state == ONRESPONSE);
BulkResponse = bulk->next;
if (BulkResponse == NULL)
BulkResponseTail = &BulkResponse;
bulk->state = UNLISTED;
} else {
bulk = NULL;
}
pthread_mutex_unlock(&BulkMutex);
bulkstart();
return bulk;
}
void
freebulk(bulk_t *bulk)
{
ddassert(bulk->state == UNLISTED);
if (bulk->s1) {
free(bulk->s1);
bulk->s1 = NULL;
}
if (bulk->s2) {
free(bulk->s2);
bulk->s2 = NULL;
}
if (bulk->s3) {
free(bulk->s3);
bulk->s3 = NULL;
}
if (bulk->s4) {
free(bulk->s4);
bulk->s4 = NULL;
}
if (bulk->r1) {
free(bulk->r1);
bulk->r1 = NULL;
}
if (bulk->r2) {
free(bulk->r2);
bulk->r2 = NULL;
}
if (bulk->r3) {
free(bulk->r3);
bulk->r3 = NULL;
}
if (bulk->r4) {
free(bulk->r4);
bulk->r4 = NULL;
}
free(bulk);
}
#if 0
static
int
readall(int fd, void *buf, size_t bytes)
{
ssize_t r;
for (;;) {
r = read(fd, buf, bytes);
if (r == (ssize_t)bytes)
break;
if (r > 0) {
buf = (char *)buf + r;
bytes -= r;
continue;
}
if (r < 0 && errno == EINTR)
continue;
return 1;
}
return 0;
}
static
int
writeall(int fd, const void *buf, size_t bytes)
{
ssize_t r;
for (;;) {
r = write(fd, buf, bytes);
if (r == (ssize_t)bytes)
break;
if (r > 0) {
buf = (const char *)buf + r;
bytes -= r;
continue;
}
if (r < 0 && errno == EINTR)
continue;
return 1;
}
return 0;
}
#endif
static void *
bulkthread(void *arg)
{
job_t *job = arg;
bulk_t *bulk;
pthread_mutex_lock(&BulkMutex);
for (;;) {
if (job->terminate)
break;
if (job->active == NULL)
pthread_cond_wait(&job->cond, &BulkMutex);
bulk = job->active;
if (bulk) {
bulk->state = ISRUNNING;
pthread_mutex_unlock(&BulkMutex);
BulkFunc(bulk);
pthread_mutex_lock(&BulkMutex);
bulk->state = ONRESPONSE;
bulk->next = NULL;
*BulkResponseTail = bulk;
BulkResponseTail = &bulk->next;
--BulkCurJobs;
pthread_cond_signal(&BulkResponseCond);
}
if ((bulk = BulkSubmit) != NULL && job->terminate == 0) {
BulkSubmit = bulk->next;
if (BulkSubmit == NULL)
BulkSubmitTail = &BulkSubmit;
bulk->state = ONRUN;
job->active = bulk;
++BulkCurJobs;
} else {
job->active = NULL;
}
}
pthread_mutex_unlock(&BulkMutex);
return NULL;
}