diff --git a/bwa.h b/bwa.h index 5d40aae..6fcc82e 100644 --- a/bwa.h +++ b/bwa.h @@ -10,8 +10,7 @@ #define BWA_IDX_PAC 0x4 #define BWA_IDX_ALL 0x7 -#define BWA_SHM_KEY 5291 -#define BWA_SHM_SIZE 0x10000 +#define BWA_CTL_SIZE 0x10000 typedef struct { bwt_t *bwt; // FM-index diff --git a/bwashm.c b/bwashm.c new file mode 100644 index 0000000..683d608 --- /dev/null +++ b/bwashm.c @@ -0,0 +1,169 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bwa.h" + +int bwa_shm_stage(bwaidx_t *idx, const char *hint) +{ + const char *name; + uint8_t *shm, *shm_idx; + uint16_t *cnt, i; + int shmid, to_init = 0, l; + char path[PATH_MAX + 1], *p; + + if (hint == 0 || hint[0] == 0) return -1; + for (name = hint + strlen(hint) - 1; name >= hint && *name != '/'; --name); + ++name; + + if ((shmid = shm_open("/bwactl", O_RDWR, 0444)) < 0) { + shmid = shm_open("/bwactl", O_CREAT|O_RDWR|O_EXCL, 0644); + to_init = 1; + } + if (shmid < 0) return -1; + ftruncate(shmid, BWA_CTL_SIZE); + shm = mmap(0, BWA_CTL_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, shmid, 0); + cnt = (uint16_t*)shm; + if (to_init) { + memset(shm, 0, BWA_CTL_SIZE); + cnt[1] = 4; + } else { + for (i = 0, p = (char*)shm + 4; i < cnt[0]; ++i) { + if (strcmp(p + 8, name) == 0) break; + p += 9 + strlen(p + 8); + } + if (i < cnt[0]) { + fprintf(stderr, "[W::%s] index '%s' is already in shared memory\n", __func__, name); + return -1; + } + } + + if (idx->mem == 0) bwa_idx2mem(idx); + + strcat(strcpy(path, "/bwaidx-"), name); + l = 8 + strlen(name) + 1; + if (cnt[1] + l > BWA_CTL_SIZE) return -1; + memcpy(shm + cnt[1], &idx->l_mem, 8); + memcpy(shm + cnt[1] + 8, name, l - 8); + if ((shmid = shm_open(path, O_CREAT|O_RDWR|O_EXCL, 0644)) < 0) { + shm_unlink(path); + perror("shm_open()"); + return -1; + } + cnt[1] += l; ++cnt[0]; + ftruncate(shmid, idx->l_mem); + shm_idx = mmap(0, idx->l_mem, PROT_READ|PROT_WRITE, MAP_SHARED, shmid, 0); + memcpy(shm_idx, idx->mem, idx->l_mem); + free(idx->mem); + idx->mem = shm_idx; + idx->is_shm = 1; + return 0; +} + +bwaidx_t *bwa_idx_load_from_shm(const char *hint) +{ + const char *name; + uint8_t *shm, *shm_idx; + uint16_t *cnt, i; + char *p, path[PATH_MAX + 1]; + int shmid; + int64_t l_mem; + bwaidx_t *idx; + + if (hint == 0 || hint[0] == 0) return 0; + for (name = hint + strlen(hint) - 1; name >= hint && *name != '/'; --name); + ++name; + if ((shmid = shm_open("/bwactl", O_RDONLY, 0444)) < 0) return 0; + shm = mmap(0, BWA_CTL_SIZE, PROT_READ, MAP_SHARED, shmid, 0); + cnt = (uint16_t*)shm; + if (cnt[0] == 0) return 0; + for (i = 0, p = (char*)(shm + 4); i < cnt[0]; ++i) { + memcpy(&l_mem, p, 8); p += 8; + if (strcmp(p, name) == 0) break; + p += strlen(p) + 1; + } + if (i == cnt[0]) return 0; + + strcat(strcpy(path, "/bwaidx-"), name); + if ((shmid = shm_open(path, O_RDONLY, 0444)) < 0) return 0; + shm_idx = mmap(0, l_mem, PROT_READ, MAP_SHARED, shmid, 0); + idx = calloc(1, sizeof(bwaidx_t)); + bwa_mem2idx(l_mem, shm_idx, idx); + idx->is_shm = 1; + return idx; +} + +int bwa_shm_list(void) +{ + int shmid; + uint16_t *cnt, i; + char *p, *shm; + if ((shmid = shm_open("/bwactl", O_RDONLY, 0444)) < 0) return -1; + shm = mmap(0, BWA_CTL_SIZE, PROT_READ, MAP_SHARED, shmid, 0); + cnt = (uint16_t*)shm; + for (i = 0, p = shm + 4; i < cnt[0]; ++i) { + int64_t l_mem; + memcpy(&l_mem, p, 8); p += 8; + printf("%s\t%ld\n", p, (long)l_mem); + p += strlen(p) + 1; + } + return 0; +} + +int bwa_shm_destroy(void) +{ + int shmid; + uint16_t *cnt, i; + char *p, *shm; + char path[PATH_MAX + 1]; + + if ((shmid = shm_open("/bwactl", O_RDONLY, 0444)) < 0) return -1; + shm = mmap(0, BWA_CTL_SIZE, PROT_READ, MAP_SHARED, shmid, 0); + cnt = (uint16_t*)shm; + for (i = 0, p = shm + 4; i < cnt[0]; ++i) { + int64_t l_mem; + memcpy(&l_mem, p, 8); p += 8; + strcat(strcpy(path, "/bwaidx-"), p); + shm_unlink(path); + p += strlen(p) + 1; + } + munmap(shm, BWA_CTL_SIZE); + shm_unlink("/bwactl"); + return 0; +} + +int main_shm(int argc, char *argv[]) +{ + int c, to_list = 0, to_drop = 0, ret = 0; + while ((c = getopt(argc, argv, "ld")) >= 0) { + if (c == 'l') to_list = 1; + else if (c == 'd') to_drop = 1; + } + if (optind == argc && !to_list && !to_drop) { + fprintf(stderr, "\nUsage: bwa shm [-d|-l] [idxbase]\n\n"); + fprintf(stderr, "Options: -d destroy all indices in shared memory\n"); + fprintf(stderr, " -l list names of indices in shared memory\n\n"); + return 1; + } + if (optind < argc && (to_list || to_drop)) { + fprintf(stderr, "[E::%s] open -l or -d cannot be used when 'idxbase' is present\n", __func__); + return 1; + } + if (optind < argc) { + bwaidx_t *idx; + idx = bwa_idx_load_from_disk(argv[optind], BWA_IDX_ALL); + if (bwa_shm_stage(idx, argv[optind]) < 0) { + fprintf(stderr, "[E::%s] failed to stage the index in shared memory\n", __func__); + ret = 1; + } + bwa_idx_destroy(idx); + } + if (to_list) bwa_shm_list(); + if (to_drop) bwa_shm_destroy(); + return ret; +}