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 68*a67bf8dbSMatthew Dillon /* 69*a67bf8dbSMatthew Dillon * Initialize for bulk scan operations. Always paired with donebulk() 70*a67bf8dbSMatthew 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*a67bf8dbSMatthew Dillon addbuildenv("__MAKE_CONF", "/dev/null", BENV_ENVIRONMENT); 86*a67bf8dbSMatthew Dillon 878e25f19bSMatthew Dillon pthread_mutex_init(&BulkMutex, NULL); 888e25f19bSMatthew Dillon pthread_cond_init(&BulkResponseCond, NULL); 898e25f19bSMatthew Dillon 908e25f19bSMatthew Dillon pthread_mutex_lock(&BulkMutex); 918e25f19bSMatthew Dillon for (i = 0; i < jobs; ++i) { 928e25f19bSMatthew Dillon pthread_cond_init(&JobsAry[i].cond, NULL); 938e25f19bSMatthew Dillon pthread_create(&JobsAry[i].td, NULL, bulkthread, &JobsAry[i]); 948e25f19bSMatthew Dillon } 958e25f19bSMatthew Dillon pthread_mutex_unlock(&BulkMutex); 968e25f19bSMatthew Dillon } 978e25f19bSMatthew Dillon 988e25f19bSMatthew Dillon void 998e25f19bSMatthew Dillon donebulk(void) 1008e25f19bSMatthew Dillon { 1018e25f19bSMatthew Dillon bulk_t *bulk; 1028e25f19bSMatthew Dillon int i; 1038e25f19bSMatthew Dillon 1048e25f19bSMatthew Dillon pthread_mutex_lock(&BulkMutex); 1058e25f19bSMatthew Dillon while ((bulk = BulkSubmit) != NULL) { 1068e25f19bSMatthew Dillon BulkSubmit = bulk->next; 1078e25f19bSMatthew Dillon freebulk(bulk); 1088e25f19bSMatthew Dillon } 1098e25f19bSMatthew Dillon BulkSubmitTail = &BulkSubmit; 1108e25f19bSMatthew Dillon 1118e25f19bSMatthew Dillon for (i = 0; i < BulkMaxJobs; ++i) { 1128e25f19bSMatthew Dillon JobsAry[i].terminate = 1; 1138e25f19bSMatthew Dillon pthread_cond_signal(&JobsAry[i].cond); 1148e25f19bSMatthew Dillon } 1158e25f19bSMatthew Dillon pthread_mutex_unlock(&BulkMutex); 1168e25f19bSMatthew Dillon for (i = 0; i < BulkMaxJobs; ++i) { 1178e25f19bSMatthew Dillon pthread_join(JobsAry[i].td, NULL); 1188e25f19bSMatthew Dillon pthread_cond_destroy(&JobsAry[i].cond); 1198e25f19bSMatthew Dillon if (JobsAry[i].active) { 1208e25f19bSMatthew Dillon freebulk(JobsAry[i].active); 1218e25f19bSMatthew Dillon JobsAry[i].active = NULL; 1223699ee09SMatthew Dillon pthread_mutex_lock(&BulkMutex); 1238e25f19bSMatthew Dillon --BulkCurJobs; 1243699ee09SMatthew Dillon pthread_mutex_unlock(&BulkMutex); 1258e25f19bSMatthew Dillon } 1268e25f19bSMatthew Dillon JobsAry[i].terminate = 0; 1278e25f19bSMatthew Dillon } 1288e25f19bSMatthew Dillon ddassert(BulkCurJobs == 0); 1298e25f19bSMatthew Dillon 1308e25f19bSMatthew Dillon while ((bulk = BulkResponse) != NULL) { 1318e25f19bSMatthew Dillon BulkResponse = bulk->next; 1328e25f19bSMatthew Dillon freebulk(bulk); 1338e25f19bSMatthew Dillon } 1348e25f19bSMatthew Dillon BulkResponseTail = &BulkResponse; 1358e25f19bSMatthew Dillon 1368e25f19bSMatthew Dillon BulkFunc = NULL; 1378e25f19bSMatthew Dillon 1388e25f19bSMatthew Dillon bzero(JobsAry, sizeof(JobsAry)); 139*a67bf8dbSMatthew Dillon 140*a67bf8dbSMatthew Dillon delbuildenv("__MAKE_CONF"); 1418e25f19bSMatthew Dillon } 1428e25f19bSMatthew Dillon 1437f0eca56SMatthew Dillon void 1448e25f19bSMatthew Dillon queuebulk(const char *s1, const char *s2, const char *s3, const char *s4) 1458e25f19bSMatthew Dillon { 1468e25f19bSMatthew Dillon bulk_t *bulk; 1478e25f19bSMatthew Dillon 1488e25f19bSMatthew Dillon bulk = calloc(1, sizeof(*bulk)); 1498e25f19bSMatthew Dillon if (s1) 1508e25f19bSMatthew Dillon bulk->s1 = strdup(s1); 1518e25f19bSMatthew Dillon if (s2) 1528e25f19bSMatthew Dillon bulk->s2 = strdup(s2); 1538e25f19bSMatthew Dillon if (s3) 1548e25f19bSMatthew Dillon bulk->s3 = strdup(s3); 1558e25f19bSMatthew Dillon if (s4) 1568e25f19bSMatthew Dillon bulk->s4 = strdup(s4); 1578e25f19bSMatthew Dillon bulk->state = ONSUBMIT; 1588e25f19bSMatthew Dillon 1598e25f19bSMatthew Dillon pthread_mutex_lock(&BulkMutex); 1608e25f19bSMatthew Dillon *BulkSubmitTail = bulk; 1618e25f19bSMatthew Dillon BulkSubmitTail = &bulk->next; 1627f0eca56SMatthew Dillon if (BulkCurJobs < BulkMaxJobs) { 1638e25f19bSMatthew Dillon pthread_mutex_unlock(&BulkMutex); 1648e25f19bSMatthew Dillon bulkstart(); 1657f0eca56SMatthew Dillon } else { 1667f0eca56SMatthew Dillon pthread_mutex_unlock(&BulkMutex); 1677f0eca56SMatthew Dillon } 1688e25f19bSMatthew Dillon } 1698e25f19bSMatthew Dillon 1708e25f19bSMatthew Dillon /* 1718e25f19bSMatthew Dillon * Fill any idle job slots with new jobs as available. 1728e25f19bSMatthew Dillon */ 1738e25f19bSMatthew Dillon static 1748e25f19bSMatthew Dillon void 1758e25f19bSMatthew Dillon bulkstart(void) 1768e25f19bSMatthew Dillon { 1778e25f19bSMatthew Dillon bulk_t *bulk; 1788e25f19bSMatthew Dillon int i; 1798e25f19bSMatthew Dillon 1808e25f19bSMatthew Dillon pthread_mutex_lock(&BulkMutex); 1818e25f19bSMatthew Dillon while ((bulk = BulkSubmit) != NULL && BulkCurJobs < BulkMaxJobs) { 1828e25f19bSMatthew Dillon i = BulkScanJob + 1; 1838e25f19bSMatthew Dillon for (;;) { 1848e25f19bSMatthew Dillon i = i % BulkMaxJobs; 1858e25f19bSMatthew Dillon if (JobsAry[i].active == NULL) 1868e25f19bSMatthew Dillon break; 1878e25f19bSMatthew Dillon ++i; 1888e25f19bSMatthew Dillon } 1898e25f19bSMatthew Dillon BulkScanJob = i; 1908e25f19bSMatthew Dillon BulkSubmit = bulk->next; 1918e25f19bSMatthew Dillon if (BulkSubmit == NULL) 1928e25f19bSMatthew Dillon BulkSubmitTail = &BulkSubmit; 1938e25f19bSMatthew Dillon 1948e25f19bSMatthew Dillon bulk->state = ONRUN; 1958e25f19bSMatthew Dillon JobsAry[i].active = bulk; 1968e25f19bSMatthew Dillon pthread_cond_signal(&JobsAry[i].cond); 1978e25f19bSMatthew Dillon ++BulkCurJobs; 1988e25f19bSMatthew Dillon } 1998e25f19bSMatthew Dillon pthread_mutex_unlock(&BulkMutex); 2008e25f19bSMatthew Dillon } 2018e25f19bSMatthew Dillon 2028e25f19bSMatthew Dillon /* 2038e25f19bSMatthew Dillon * Retrieve completed job or job with activity 2048e25f19bSMatthew Dillon */ 2058e25f19bSMatthew Dillon bulk_t * 2068e25f19bSMatthew Dillon getbulk(void) 2078e25f19bSMatthew Dillon { 2088e25f19bSMatthew Dillon bulk_t *bulk; 2098e25f19bSMatthew Dillon 2108e25f19bSMatthew Dillon pthread_mutex_lock(&BulkMutex); 2118e25f19bSMatthew Dillon while (BulkCurJobs && BulkResponse == NULL) { 2128e25f19bSMatthew Dillon pthread_cond_wait(&BulkResponseCond, &BulkMutex); 2138e25f19bSMatthew Dillon } 2148e25f19bSMatthew Dillon if (BulkResponse) { 2158e25f19bSMatthew Dillon bulk = BulkResponse; 2168e25f19bSMatthew Dillon ddassert(bulk->state == ONRESPONSE); 2178e25f19bSMatthew Dillon BulkResponse = bulk->next; 2188e25f19bSMatthew Dillon if (BulkResponse == NULL) 2198e25f19bSMatthew Dillon BulkResponseTail = &BulkResponse; 2208e25f19bSMatthew Dillon bulk->state = UNLISTED; 2218e25f19bSMatthew Dillon } else { 2228e25f19bSMatthew Dillon bulk = NULL; 2238e25f19bSMatthew Dillon } 2248e25f19bSMatthew Dillon pthread_mutex_unlock(&BulkMutex); 2258e25f19bSMatthew Dillon bulkstart(); 2268e25f19bSMatthew Dillon 2278e25f19bSMatthew Dillon return bulk; 2288e25f19bSMatthew Dillon } 2298e25f19bSMatthew Dillon 2308e25f19bSMatthew Dillon void 2318e25f19bSMatthew Dillon freebulk(bulk_t *bulk) 2328e25f19bSMatthew Dillon { 2338e25f19bSMatthew Dillon ddassert(bulk->state == UNLISTED); 2348e25f19bSMatthew Dillon 2358e25f19bSMatthew Dillon if (bulk->s1) { 2368e25f19bSMatthew Dillon free(bulk->s1); 2378e25f19bSMatthew Dillon bulk->s1 = NULL; 2388e25f19bSMatthew Dillon } 2398e25f19bSMatthew Dillon if (bulk->s2) { 2408e25f19bSMatthew Dillon free(bulk->s2); 2418e25f19bSMatthew Dillon bulk->s2 = NULL; 2428e25f19bSMatthew Dillon } 2438e25f19bSMatthew Dillon if (bulk->s3) { 2448e25f19bSMatthew Dillon free(bulk->s3); 2458e25f19bSMatthew Dillon bulk->s3 = NULL; 2468e25f19bSMatthew Dillon } 2478e25f19bSMatthew Dillon if (bulk->s4) { 2488e25f19bSMatthew Dillon free(bulk->s4); 2498e25f19bSMatthew Dillon bulk->s4 = NULL; 2508e25f19bSMatthew Dillon } 2518e25f19bSMatthew Dillon if (bulk->r1) { 2528e25f19bSMatthew Dillon free(bulk->r1); 2538e25f19bSMatthew Dillon bulk->r1 = NULL; 2548e25f19bSMatthew Dillon } 2558e25f19bSMatthew Dillon if (bulk->r2) { 2568e25f19bSMatthew Dillon free(bulk->r2); 2578e25f19bSMatthew Dillon bulk->r2 = NULL; 2588e25f19bSMatthew Dillon } 2598e25f19bSMatthew Dillon if (bulk->r3) { 2608e25f19bSMatthew Dillon free(bulk->r3); 2618e25f19bSMatthew Dillon bulk->r3 = NULL; 2628e25f19bSMatthew Dillon } 2638e25f19bSMatthew Dillon if (bulk->r4) { 2648e25f19bSMatthew Dillon free(bulk->r4); 2658e25f19bSMatthew Dillon bulk->r4 = NULL; 2668e25f19bSMatthew Dillon } 2678e25f19bSMatthew Dillon free(bulk); 2688e25f19bSMatthew Dillon } 2698e25f19bSMatthew Dillon 2708e25f19bSMatthew Dillon #if 0 2718e25f19bSMatthew Dillon 2728e25f19bSMatthew Dillon /* 2738e25f19bSMatthew Dillon * Returns non-zero if unable to read specified number of bytes 2748e25f19bSMatthew Dillon */ 2758e25f19bSMatthew Dillon static 2768e25f19bSMatthew Dillon int 2778e25f19bSMatthew Dillon readall(int fd, void *buf, size_t bytes) 2788e25f19bSMatthew Dillon { 2798e25f19bSMatthew Dillon ssize_t r; 2808e25f19bSMatthew Dillon 2818e25f19bSMatthew Dillon for (;;) { 2828e25f19bSMatthew Dillon r = read(fd, buf, bytes); 2838e25f19bSMatthew Dillon if (r == (ssize_t)bytes) 2848e25f19bSMatthew Dillon break; 2858e25f19bSMatthew Dillon if (r > 0) { 2868e25f19bSMatthew Dillon buf = (char *)buf + r; 2878e25f19bSMatthew Dillon bytes -= r; 2888e25f19bSMatthew Dillon continue; 2898e25f19bSMatthew Dillon } 2908e25f19bSMatthew Dillon if (r < 0 && errno == EINTR) 2918e25f19bSMatthew Dillon continue; 2928e25f19bSMatthew Dillon return 1; 2938e25f19bSMatthew Dillon } 2948e25f19bSMatthew Dillon return 0; 2958e25f19bSMatthew Dillon } 2968e25f19bSMatthew Dillon 2978e25f19bSMatthew Dillon static 2988e25f19bSMatthew Dillon int 2998e25f19bSMatthew Dillon writeall(int fd, const void *buf, size_t bytes) 3008e25f19bSMatthew Dillon { 3018e25f19bSMatthew Dillon ssize_t r; 3028e25f19bSMatthew Dillon 3038e25f19bSMatthew Dillon for (;;) { 3048e25f19bSMatthew Dillon r = write(fd, buf, bytes); 3058e25f19bSMatthew Dillon if (r == (ssize_t)bytes) 3068e25f19bSMatthew Dillon break; 3078e25f19bSMatthew Dillon if (r > 0) { 3088e25f19bSMatthew Dillon buf = (const char *)buf + r; 3098e25f19bSMatthew Dillon bytes -= r; 3108e25f19bSMatthew Dillon continue; 3118e25f19bSMatthew Dillon } 3128e25f19bSMatthew Dillon if (r < 0 && errno == EINTR) 3138e25f19bSMatthew Dillon continue; 3148e25f19bSMatthew Dillon return 1; 3158e25f19bSMatthew Dillon } 3168e25f19bSMatthew Dillon return 0; 3178e25f19bSMatthew Dillon } 3188e25f19bSMatthew Dillon 3198e25f19bSMatthew Dillon #endif 3208e25f19bSMatthew Dillon 3218e25f19bSMatthew Dillon static void * 3228e25f19bSMatthew Dillon bulkthread(void *arg) 3238e25f19bSMatthew Dillon { 3248e25f19bSMatthew Dillon job_t *job = arg; 3258e25f19bSMatthew Dillon bulk_t *bulk; 3268e25f19bSMatthew Dillon 3278e25f19bSMatthew Dillon pthread_mutex_lock(&BulkMutex); 3288e25f19bSMatthew Dillon for (;;) { 3298e25f19bSMatthew Dillon if (job->terminate) 3308e25f19bSMatthew Dillon break; 3318e25f19bSMatthew Dillon if (job->active == NULL) 3328e25f19bSMatthew Dillon pthread_cond_wait(&job->cond, &BulkMutex); 3338e25f19bSMatthew Dillon bulk = job->active; 3348e25f19bSMatthew Dillon if (bulk) { 3358e25f19bSMatthew Dillon bulk->state = ISRUNNING; 3368e25f19bSMatthew Dillon 3378e25f19bSMatthew Dillon pthread_mutex_unlock(&BulkMutex); 3388e25f19bSMatthew Dillon BulkFunc(bulk); 3398e25f19bSMatthew Dillon pthread_mutex_lock(&BulkMutex); 3408e25f19bSMatthew Dillon 3418e25f19bSMatthew Dillon bulk->state = ONRESPONSE; 3428e25f19bSMatthew Dillon bulk->next = NULL; 3438e25f19bSMatthew Dillon *BulkResponseTail = bulk; 3448e25f19bSMatthew Dillon BulkResponseTail = &bulk->next; 3458e25f19bSMatthew Dillon --BulkCurJobs; 3468e25f19bSMatthew Dillon pthread_cond_signal(&BulkResponseCond); 3478e25f19bSMatthew Dillon } 3488e25f19bSMatthew Dillon 3498e25f19bSMatthew Dillon /* 3508e25f19bSMatthew Dillon * Optimization - automatically fetch the next job 3518e25f19bSMatthew Dillon */ 3528e25f19bSMatthew Dillon if ((bulk = BulkSubmit) != NULL && job->terminate == 0) { 3538e25f19bSMatthew Dillon BulkSubmit = bulk->next; 3548e25f19bSMatthew Dillon if (BulkSubmit == NULL) 3558e25f19bSMatthew Dillon BulkSubmitTail = &BulkSubmit; 3568e25f19bSMatthew Dillon bulk->state = ONRUN; 3578e25f19bSMatthew Dillon job->active = bulk; 3588e25f19bSMatthew Dillon ++BulkCurJobs; 3597f0eca56SMatthew Dillon } else { 3607f0eca56SMatthew Dillon job->active = NULL; 3618e25f19bSMatthew Dillon } 3628e25f19bSMatthew Dillon } 3638e25f19bSMatthew Dillon pthread_mutex_unlock(&BulkMutex); 3648e25f19bSMatthew Dillon 3658e25f19bSMatthew Dillon return NULL; 3668e25f19bSMatthew Dillon } 367