18e25f19bSMatthew Dillon /* 28e25f19bSMatthew Dillon * Copyright (c) 2019 The DragonFly Project. All rights reserved. 38e25f19bSMatthew Dillon * 48e25f19bSMatthew Dillon * This code is derived from software contributed to The DragonFly Project 58e25f19bSMatthew Dillon * by Matthew Dillon <dillon@backplane.com> 68e25f19bSMatthew Dillon * 78e25f19bSMatthew Dillon * This code uses concepts and configuration based on 'synth', by 88e25f19bSMatthew Dillon * John R. Marino <draco@marino.st>, which was written in ada. 98e25f19bSMatthew Dillon * 108e25f19bSMatthew Dillon * Redistribution and use in source and binary forms, with or without 118e25f19bSMatthew Dillon * modification, are permitted provided that the following conditions 128e25f19bSMatthew Dillon * are met: 138e25f19bSMatthew Dillon * 148e25f19bSMatthew Dillon * 1. Redistributions of source code must retain the above copyright 158e25f19bSMatthew Dillon * notice, this list of conditions and the following disclaimer. 168e25f19bSMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright 178e25f19bSMatthew Dillon * notice, this list of conditions and the following disclaimer in 188e25f19bSMatthew Dillon * the documentation and/or other materials provided with the 198e25f19bSMatthew Dillon * distribution. 208e25f19bSMatthew Dillon * 3. Neither the name of The DragonFly Project nor the names of its 218e25f19bSMatthew Dillon * contributors may be used to endorse or promote products derived 228e25f19bSMatthew Dillon * from this software without specific, prior written permission. 238e25f19bSMatthew Dillon * 248e25f19bSMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 258e25f19bSMatthew Dillon * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 268e25f19bSMatthew Dillon * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 278e25f19bSMatthew Dillon * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 288e25f19bSMatthew Dillon * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 298e25f19bSMatthew Dillon * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 308e25f19bSMatthew Dillon * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 318e25f19bSMatthew Dillon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 328e25f19bSMatthew Dillon * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 338e25f19bSMatthew Dillon * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 348e25f19bSMatthew Dillon * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 358e25f19bSMatthew Dillon * SUCH DAMAGE. 368e25f19bSMatthew Dillon */ 378e25f19bSMatthew Dillon #include "dsynth.h" 388e25f19bSMatthew Dillon 398e25f19bSMatthew Dillon typedef struct job { 408e25f19bSMatthew Dillon pthread_t td; 418e25f19bSMatthew Dillon pthread_cond_t cond; 428e25f19bSMatthew Dillon bulk_t *active; 438e25f19bSMatthew Dillon int terminate : 1; 448e25f19bSMatthew Dillon } job_t; 458e25f19bSMatthew Dillon 468e25f19bSMatthew Dillon /* 478e25f19bSMatthew Dillon * Most of these globals are locked with BulkMutex 488e25f19bSMatthew Dillon */ 498e25f19bSMatthew Dillon static int BulkScanJob; 508e25f19bSMatthew Dillon static int BulkCurJobs; 518e25f19bSMatthew Dillon static int BulkMaxJobs; 528e25f19bSMatthew Dillon static job_t JobsAry[MAXBULK]; 538e25f19bSMatthew Dillon static void (*BulkFunc)(bulk_t *bulk); 548e25f19bSMatthew Dillon static bulk_t *BulkSubmit; 558e25f19bSMatthew Dillon static bulk_t **BulkSubmitTail = &BulkSubmit; 568e25f19bSMatthew Dillon static bulk_t *BulkResponse; 578e25f19bSMatthew Dillon static bulk_t **BulkResponseTail = &BulkResponse; 588e25f19bSMatthew Dillon static pthread_cond_t BulkResponseCond; 598e25f19bSMatthew Dillon static pthread_mutex_t BulkMutex; 608e25f19bSMatthew Dillon 618e25f19bSMatthew Dillon static void bulkstart(void); 628e25f19bSMatthew Dillon #if 0 638e25f19bSMatthew Dillon static int readall(int fd, void *buf, size_t bytes); 648e25f19bSMatthew Dillon static int writeall(int fd, const void *buf, size_t bytes); 658e25f19bSMatthew Dillon #endif 668e25f19bSMatthew Dillon static void *bulkthread(void *arg); 678e25f19bSMatthew Dillon 68a67bf8dbSMatthew Dillon /* 69a67bf8dbSMatthew Dillon * Initialize for bulk scan operations. Always paired with donebulk() 70a67bf8dbSMatthew Dillon */ 718e25f19bSMatthew Dillon void 728e25f19bSMatthew Dillon initbulk(void (*func)(bulk_t *bulk), int jobs) 738e25f19bSMatthew Dillon { 748e25f19bSMatthew Dillon int i; 758e25f19bSMatthew Dillon 768e25f19bSMatthew Dillon if (jobs > MAXBULK) 778e25f19bSMatthew Dillon jobs = MAXBULK; 788e25f19bSMatthew Dillon 798e25f19bSMatthew Dillon ddassert(BulkSubmit == NULL); 808e25f19bSMatthew Dillon BulkCurJobs = 0; 818e25f19bSMatthew Dillon BulkMaxJobs = jobs; 828e25f19bSMatthew Dillon BulkFunc = func; 838e25f19bSMatthew Dillon BulkScanJob = 0; 848e25f19bSMatthew Dillon 85*967a4bb3SMatthew Dillon addbuildenv("__MAKE_CONF", "/dev/null", 86*967a4bb3SMatthew Dillon BENV_ENVIRONMENT | BENV_PKGLIST); 87a67bf8dbSMatthew Dillon 888e25f19bSMatthew Dillon pthread_mutex_init(&BulkMutex, NULL); 898e25f19bSMatthew Dillon pthread_cond_init(&BulkResponseCond, NULL); 908e25f19bSMatthew Dillon 918e25f19bSMatthew Dillon pthread_mutex_lock(&BulkMutex); 928e25f19bSMatthew Dillon for (i = 0; i < jobs; ++i) { 938e25f19bSMatthew Dillon pthread_cond_init(&JobsAry[i].cond, NULL); 948e25f19bSMatthew Dillon pthread_create(&JobsAry[i].td, NULL, bulkthread, &JobsAry[i]); 958e25f19bSMatthew Dillon } 968e25f19bSMatthew Dillon pthread_mutex_unlock(&BulkMutex); 978e25f19bSMatthew Dillon } 988e25f19bSMatthew Dillon 998e25f19bSMatthew Dillon void 1008e25f19bSMatthew Dillon donebulk(void) 1018e25f19bSMatthew Dillon { 1028e25f19bSMatthew Dillon bulk_t *bulk; 1038e25f19bSMatthew Dillon int i; 1048e25f19bSMatthew Dillon 1058e25f19bSMatthew Dillon pthread_mutex_lock(&BulkMutex); 1068e25f19bSMatthew Dillon while ((bulk = BulkSubmit) != NULL) { 1078e25f19bSMatthew Dillon BulkSubmit = bulk->next; 1088e25f19bSMatthew Dillon freebulk(bulk); 1098e25f19bSMatthew Dillon } 1108e25f19bSMatthew Dillon BulkSubmitTail = &BulkSubmit; 1118e25f19bSMatthew Dillon 1128e25f19bSMatthew Dillon for (i = 0; i < BulkMaxJobs; ++i) { 1138e25f19bSMatthew Dillon JobsAry[i].terminate = 1; 1148e25f19bSMatthew Dillon pthread_cond_signal(&JobsAry[i].cond); 1158e25f19bSMatthew Dillon } 1168e25f19bSMatthew Dillon pthread_mutex_unlock(&BulkMutex); 1178e25f19bSMatthew Dillon for (i = 0; i < BulkMaxJobs; ++i) { 1188e25f19bSMatthew Dillon pthread_join(JobsAry[i].td, NULL); 1198e25f19bSMatthew Dillon pthread_cond_destroy(&JobsAry[i].cond); 1208e25f19bSMatthew Dillon if (JobsAry[i].active) { 1218e25f19bSMatthew Dillon freebulk(JobsAry[i].active); 1228e25f19bSMatthew Dillon JobsAry[i].active = NULL; 1233699ee09SMatthew Dillon pthread_mutex_lock(&BulkMutex); 1248e25f19bSMatthew Dillon --BulkCurJobs; 1253699ee09SMatthew Dillon pthread_mutex_unlock(&BulkMutex); 1268e25f19bSMatthew Dillon } 1278e25f19bSMatthew Dillon JobsAry[i].terminate = 0; 1288e25f19bSMatthew Dillon } 1298e25f19bSMatthew Dillon ddassert(BulkCurJobs == 0); 1308e25f19bSMatthew Dillon 1318e25f19bSMatthew Dillon while ((bulk = BulkResponse) != NULL) { 1328e25f19bSMatthew Dillon BulkResponse = bulk->next; 1338e25f19bSMatthew Dillon freebulk(bulk); 1348e25f19bSMatthew Dillon } 1358e25f19bSMatthew Dillon BulkResponseTail = &BulkResponse; 1368e25f19bSMatthew Dillon 1378e25f19bSMatthew Dillon BulkFunc = NULL; 1388e25f19bSMatthew Dillon 1398e25f19bSMatthew Dillon bzero(JobsAry, sizeof(JobsAry)); 140a67bf8dbSMatthew Dillon 141a67bf8dbSMatthew Dillon delbuildenv("__MAKE_CONF"); 1428e25f19bSMatthew Dillon } 1438e25f19bSMatthew Dillon 1447f0eca56SMatthew Dillon void 1458e25f19bSMatthew Dillon queuebulk(const char *s1, const char *s2, const char *s3, const char *s4) 1468e25f19bSMatthew Dillon { 1478e25f19bSMatthew Dillon bulk_t *bulk; 1488e25f19bSMatthew Dillon 1498e25f19bSMatthew Dillon bulk = calloc(1, sizeof(*bulk)); 1508e25f19bSMatthew Dillon if (s1) 1518e25f19bSMatthew Dillon bulk->s1 = strdup(s1); 1528e25f19bSMatthew Dillon if (s2) 1538e25f19bSMatthew Dillon bulk->s2 = strdup(s2); 1548e25f19bSMatthew Dillon if (s3) 1558e25f19bSMatthew Dillon bulk->s3 = strdup(s3); 1568e25f19bSMatthew Dillon if (s4) 1578e25f19bSMatthew Dillon bulk->s4 = strdup(s4); 1588e25f19bSMatthew Dillon bulk->state = ONSUBMIT; 1598e25f19bSMatthew Dillon 1608e25f19bSMatthew Dillon pthread_mutex_lock(&BulkMutex); 1618e25f19bSMatthew Dillon *BulkSubmitTail = bulk; 1628e25f19bSMatthew Dillon BulkSubmitTail = &bulk->next; 1637f0eca56SMatthew Dillon if (BulkCurJobs < BulkMaxJobs) { 1648e25f19bSMatthew Dillon pthread_mutex_unlock(&BulkMutex); 1658e25f19bSMatthew Dillon bulkstart(); 1667f0eca56SMatthew Dillon } else { 1677f0eca56SMatthew Dillon pthread_mutex_unlock(&BulkMutex); 1687f0eca56SMatthew Dillon } 1698e25f19bSMatthew Dillon } 1708e25f19bSMatthew Dillon 1718e25f19bSMatthew Dillon /* 1728e25f19bSMatthew Dillon * Fill any idle job slots with new jobs as available. 1738e25f19bSMatthew Dillon */ 1748e25f19bSMatthew Dillon static 1758e25f19bSMatthew Dillon void 1768e25f19bSMatthew Dillon bulkstart(void) 1778e25f19bSMatthew Dillon { 1788e25f19bSMatthew Dillon bulk_t *bulk; 1798e25f19bSMatthew Dillon int i; 1808e25f19bSMatthew Dillon 1818e25f19bSMatthew Dillon pthread_mutex_lock(&BulkMutex); 1828e25f19bSMatthew Dillon while ((bulk = BulkSubmit) != NULL && BulkCurJobs < BulkMaxJobs) { 1838e25f19bSMatthew Dillon i = BulkScanJob + 1; 1848e25f19bSMatthew Dillon for (;;) { 1858e25f19bSMatthew Dillon i = i % BulkMaxJobs; 1868e25f19bSMatthew Dillon if (JobsAry[i].active == NULL) 1878e25f19bSMatthew Dillon break; 1888e25f19bSMatthew Dillon ++i; 1898e25f19bSMatthew Dillon } 1908e25f19bSMatthew Dillon BulkScanJob = i; 1918e25f19bSMatthew Dillon BulkSubmit = bulk->next; 1928e25f19bSMatthew Dillon if (BulkSubmit == NULL) 1938e25f19bSMatthew Dillon BulkSubmitTail = &BulkSubmit; 1948e25f19bSMatthew Dillon 1958e25f19bSMatthew Dillon bulk->state = ONRUN; 1968e25f19bSMatthew Dillon JobsAry[i].active = bulk; 1978e25f19bSMatthew Dillon pthread_cond_signal(&JobsAry[i].cond); 1988e25f19bSMatthew Dillon ++BulkCurJobs; 1998e25f19bSMatthew Dillon } 2008e25f19bSMatthew Dillon pthread_mutex_unlock(&BulkMutex); 2018e25f19bSMatthew Dillon } 2028e25f19bSMatthew Dillon 2038e25f19bSMatthew Dillon /* 2048e25f19bSMatthew Dillon * Retrieve completed job or job with activity 2058e25f19bSMatthew Dillon */ 2068e25f19bSMatthew Dillon bulk_t * 2078e25f19bSMatthew Dillon getbulk(void) 2088e25f19bSMatthew Dillon { 2098e25f19bSMatthew Dillon bulk_t *bulk; 2108e25f19bSMatthew Dillon 2118e25f19bSMatthew Dillon pthread_mutex_lock(&BulkMutex); 2128e25f19bSMatthew Dillon while (BulkCurJobs && BulkResponse == NULL) { 2138e25f19bSMatthew Dillon pthread_cond_wait(&BulkResponseCond, &BulkMutex); 2148e25f19bSMatthew Dillon } 2158e25f19bSMatthew Dillon if (BulkResponse) { 2168e25f19bSMatthew Dillon bulk = BulkResponse; 2178e25f19bSMatthew Dillon ddassert(bulk->state == ONRESPONSE); 2188e25f19bSMatthew Dillon BulkResponse = bulk->next; 2198e25f19bSMatthew Dillon if (BulkResponse == NULL) 2208e25f19bSMatthew Dillon BulkResponseTail = &BulkResponse; 2218e25f19bSMatthew Dillon bulk->state = UNLISTED; 2228e25f19bSMatthew Dillon } else { 2238e25f19bSMatthew Dillon bulk = NULL; 2248e25f19bSMatthew Dillon } 2258e25f19bSMatthew Dillon pthread_mutex_unlock(&BulkMutex); 2268e25f19bSMatthew Dillon bulkstart(); 2278e25f19bSMatthew Dillon 2288e25f19bSMatthew Dillon return bulk; 2298e25f19bSMatthew Dillon } 2308e25f19bSMatthew Dillon 2318e25f19bSMatthew Dillon void 2328e25f19bSMatthew Dillon freebulk(bulk_t *bulk) 2338e25f19bSMatthew Dillon { 2348e25f19bSMatthew Dillon ddassert(bulk->state == UNLISTED); 2358e25f19bSMatthew Dillon 2368e25f19bSMatthew Dillon if (bulk->s1) { 2378e25f19bSMatthew Dillon free(bulk->s1); 2388e25f19bSMatthew Dillon bulk->s1 = NULL; 2398e25f19bSMatthew Dillon } 2408e25f19bSMatthew Dillon if (bulk->s2) { 2418e25f19bSMatthew Dillon free(bulk->s2); 2428e25f19bSMatthew Dillon bulk->s2 = NULL; 2438e25f19bSMatthew Dillon } 2448e25f19bSMatthew Dillon if (bulk->s3) { 2458e25f19bSMatthew Dillon free(bulk->s3); 2468e25f19bSMatthew Dillon bulk->s3 = NULL; 2478e25f19bSMatthew Dillon } 2488e25f19bSMatthew Dillon if (bulk->s4) { 2498e25f19bSMatthew Dillon free(bulk->s4); 2508e25f19bSMatthew Dillon bulk->s4 = NULL; 2518e25f19bSMatthew Dillon } 2528e25f19bSMatthew Dillon if (bulk->r1) { 2538e25f19bSMatthew Dillon free(bulk->r1); 2548e25f19bSMatthew Dillon bulk->r1 = NULL; 2558e25f19bSMatthew Dillon } 2568e25f19bSMatthew Dillon if (bulk->r2) { 2578e25f19bSMatthew Dillon free(bulk->r2); 2588e25f19bSMatthew Dillon bulk->r2 = NULL; 2598e25f19bSMatthew Dillon } 2608e25f19bSMatthew Dillon if (bulk->r3) { 2618e25f19bSMatthew Dillon free(bulk->r3); 2628e25f19bSMatthew Dillon bulk->r3 = NULL; 2638e25f19bSMatthew Dillon } 2648e25f19bSMatthew Dillon if (bulk->r4) { 2658e25f19bSMatthew Dillon free(bulk->r4); 2668e25f19bSMatthew Dillon bulk->r4 = NULL; 2678e25f19bSMatthew Dillon } 2688e25f19bSMatthew Dillon free(bulk); 2698e25f19bSMatthew Dillon } 2708e25f19bSMatthew Dillon 2718e25f19bSMatthew Dillon #if 0 2728e25f19bSMatthew Dillon 2738e25f19bSMatthew Dillon /* 2748e25f19bSMatthew Dillon * Returns non-zero if unable to read specified number of bytes 2758e25f19bSMatthew Dillon */ 2768e25f19bSMatthew Dillon static 2778e25f19bSMatthew Dillon int 2788e25f19bSMatthew Dillon readall(int fd, void *buf, size_t bytes) 2798e25f19bSMatthew Dillon { 2808e25f19bSMatthew Dillon ssize_t r; 2818e25f19bSMatthew Dillon 2828e25f19bSMatthew Dillon for (;;) { 2838e25f19bSMatthew Dillon r = read(fd, buf, bytes); 2848e25f19bSMatthew Dillon if (r == (ssize_t)bytes) 2858e25f19bSMatthew Dillon break; 2868e25f19bSMatthew Dillon if (r > 0) { 2878e25f19bSMatthew Dillon buf = (char *)buf + r; 2888e25f19bSMatthew Dillon bytes -= r; 2898e25f19bSMatthew Dillon continue; 2908e25f19bSMatthew Dillon } 2918e25f19bSMatthew Dillon if (r < 0 && errno == EINTR) 2928e25f19bSMatthew Dillon continue; 2938e25f19bSMatthew Dillon return 1; 2948e25f19bSMatthew Dillon } 2958e25f19bSMatthew Dillon return 0; 2968e25f19bSMatthew Dillon } 2978e25f19bSMatthew Dillon 2988e25f19bSMatthew Dillon static 2998e25f19bSMatthew Dillon int 3008e25f19bSMatthew Dillon writeall(int fd, const void *buf, size_t bytes) 3018e25f19bSMatthew Dillon { 3028e25f19bSMatthew Dillon ssize_t r; 3038e25f19bSMatthew Dillon 3048e25f19bSMatthew Dillon for (;;) { 3058e25f19bSMatthew Dillon r = write(fd, buf, bytes); 3068e25f19bSMatthew Dillon if (r == (ssize_t)bytes) 3078e25f19bSMatthew Dillon break; 3088e25f19bSMatthew Dillon if (r > 0) { 3098e25f19bSMatthew Dillon buf = (const char *)buf + r; 3108e25f19bSMatthew Dillon bytes -= r; 3118e25f19bSMatthew Dillon continue; 3128e25f19bSMatthew Dillon } 3138e25f19bSMatthew Dillon if (r < 0 && errno == EINTR) 3148e25f19bSMatthew Dillon continue; 3158e25f19bSMatthew Dillon return 1; 3168e25f19bSMatthew Dillon } 3178e25f19bSMatthew Dillon return 0; 3188e25f19bSMatthew Dillon } 3198e25f19bSMatthew Dillon 3208e25f19bSMatthew Dillon #endif 3218e25f19bSMatthew Dillon 3228e25f19bSMatthew Dillon static void * 3238e25f19bSMatthew Dillon bulkthread(void *arg) 3248e25f19bSMatthew Dillon { 3258e25f19bSMatthew Dillon job_t *job = arg; 3268e25f19bSMatthew Dillon bulk_t *bulk; 3278e25f19bSMatthew Dillon 3288e25f19bSMatthew Dillon pthread_mutex_lock(&BulkMutex); 3298e25f19bSMatthew Dillon for (;;) { 3308e25f19bSMatthew Dillon if (job->terminate) 3318e25f19bSMatthew Dillon break; 3328e25f19bSMatthew Dillon if (job->active == NULL) 3338e25f19bSMatthew Dillon pthread_cond_wait(&job->cond, &BulkMutex); 3348e25f19bSMatthew Dillon bulk = job->active; 3358e25f19bSMatthew Dillon if (bulk) { 3368e25f19bSMatthew Dillon bulk->state = ISRUNNING; 3378e25f19bSMatthew Dillon 3388e25f19bSMatthew Dillon pthread_mutex_unlock(&BulkMutex); 3398e25f19bSMatthew Dillon BulkFunc(bulk); 3408e25f19bSMatthew Dillon pthread_mutex_lock(&BulkMutex); 3418e25f19bSMatthew Dillon 3428e25f19bSMatthew Dillon bulk->state = ONRESPONSE; 3438e25f19bSMatthew Dillon bulk->next = NULL; 3448e25f19bSMatthew Dillon *BulkResponseTail = bulk; 3458e25f19bSMatthew Dillon BulkResponseTail = &bulk->next; 3468e25f19bSMatthew Dillon --BulkCurJobs; 3478e25f19bSMatthew Dillon pthread_cond_signal(&BulkResponseCond); 3488e25f19bSMatthew Dillon } 3498e25f19bSMatthew Dillon 3508e25f19bSMatthew Dillon /* 3518e25f19bSMatthew Dillon * Optimization - automatically fetch the next job 3528e25f19bSMatthew Dillon */ 3538e25f19bSMatthew Dillon if ((bulk = BulkSubmit) != NULL && job->terminate == 0) { 3548e25f19bSMatthew Dillon BulkSubmit = bulk->next; 3558e25f19bSMatthew Dillon if (BulkSubmit == NULL) 3568e25f19bSMatthew Dillon BulkSubmitTail = &BulkSubmit; 3578e25f19bSMatthew Dillon bulk->state = ONRUN; 3588e25f19bSMatthew Dillon job->active = bulk; 3598e25f19bSMatthew Dillon ++BulkCurJobs; 3607f0eca56SMatthew Dillon } else { 3617f0eca56SMatthew Dillon job->active = NULL; 3628e25f19bSMatthew Dillon } 3638e25f19bSMatthew Dillon } 3648e25f19bSMatthew Dillon pthread_mutex_unlock(&BulkMutex); 3658e25f19bSMatthew Dillon 3668e25f19bSMatthew Dillon return NULL; 3678e25f19bSMatthew Dillon } 368