void new_image(const struct bu_structparse *UNUSED(sdp), const char *UNUSED(name), void *base, const char *UNUSED(value), void *UNUSED(data)) { struct bbd_specific *bbd_sp = (struct bbd_specific *)base; struct bbd_img *bbdi; /* XXX - looks like we don't release this memory */ BU_ALLOC(bbdi, struct bbd_img); bbdi->img_mf = bu_open_mapped_file_with_path( bbd_sp->rtip->rti_dbip->dbi_filepath, bu_vls_addr(&bbd_sp->img_filename), NULL); if (!bbdi->img_mf) { bu_log("error opening image %s\n", bu_vls_addr(&bbd_sp->img_filename)); bu_bomb(""); } BU_CK_MAPPED_FILE(bbdi->img_mf); bbdi->img_width = bbd_sp->img_width; bbdi->img_width = bbd_sp->img_height; BU_LIST_APPEND(&bbd_sp->imgs, &(bbdi->l)); bbd_sp->img_count++; }
void bu_pr_mapped_file(const char *title, const struct bu_mapped_file *mp) { BU_CK_MAPPED_FILE(mp); bu_log("%p mapped_file %s %p len=%ld mapped=%d, uses=%d %s\n", (void *)mp, mp->name, mp->buf, mp->buflen, mp->is_mapped, mp->uses, title); }
void bu_free_mapped_files(int verbose) { struct bu_mapped_file *mp, *next; if (UNLIKELY(bu_debug&BU_DEBUG_MAPPED_FILE)) bu_log("bu_free_mapped_files(verbose=%d)\n", verbose); bu_semaphore_acquire(BU_SEM_MAPPEDFILE); next = BU_LIST_FIRST(bu_mapped_file, &bu_mapped_file_list); while (BU_LIST_NOT_HEAD(next, &bu_mapped_file_list)) { BU_CK_MAPPED_FILE(next); mp = next; next = BU_LIST_NEXT(bu_mapped_file, &mp->l); if (mp->uses > 0) continue; /* Found one that needs to have storage released */ if (UNLIKELY(verbose || (bu_debug&BU_DEBUG_MAPPED_FILE))) bu_pr_mapped_file("freeing", mp); BU_LIST_DEQUEUE(&mp->l); /* If application pointed mp->apbuf at mp->buf, break that * association so we don't double-free the buffer. */ if (mp->apbuf == mp->buf) mp->apbuf = (void *)NULL; #ifdef HAVE_SYS_MMAN_H if (mp->is_mapped) { int ret; bu_semaphore_acquire(BU_SEM_SYSCALL); ret = munmap(mp->buf, (size_t)mp->buflen); bu_semaphore_release(BU_SEM_SYSCALL); if (UNLIKELY(ret < 0)) perror("munmap"); /* XXX How to get this chunk of address space back to malloc()? */ } else #endif { bu_free(mp->buf, "bu_mapped_file.buf[]"); } mp->buf = (void *)NULL; /* sanity */ bu_free((void *)mp->name, "bu_mapped_file.name"); if (mp->appl) bu_free((void *)mp->appl, "bu_mapped_file.appl"); bu_free((void *)mp, "struct bu_mapped_file"); } bu_semaphore_release(BU_SEM_MAPPEDFILE); }
void bu_close_mapped_file(struct bu_mapped_file *mp) { BU_CK_MAPPED_FILE(mp); if (UNLIKELY(bu_debug&BU_DEBUG_MAPPED_FILE)) bu_pr_mapped_file("close:uses--", mp); if (UNLIKELY(!mp)) { bu_log("bu_close_mapped_file() called with null pointer\n"); return; } bu_semaphore_acquire(BU_SEM_MAPPEDFILE); --mp->uses; bu_semaphore_release(BU_SEM_MAPPEDFILE); }
struct bu_mapped_file * bu_open_mapped_file(const char *name, const char *appl) /* file name */ /* non-null only when app. will use 'apbuf' */ { struct bu_mapped_file *mp = (struct bu_mapped_file *)NULL; char *real_path = bu_realpath(name, NULL); #ifdef HAVE_SYS_STAT_H struct stat sb; int fd = -1; /* unix file descriptor */ int readval; ssize_t bytes_to_go, nbytes; #else FILE *fp = (FILE *)NULL; /* stdio file pointer */ #endif int ret; if (UNLIKELY(bu_debug&BU_DEBUG_MAPPED_FILE)) bu_log("bu_open_mapped_file(%s(canonical path - %s), %s)\n", name, real_path, appl?appl:"(NIL)"); /* See if file has already been mapped, and can be shared */ bu_semaphore_acquire(BU_SEM_MAPPEDFILE); if (!BU_LIST_IS_INITIALIZED(&bu_mapped_file_list)) { BU_LIST_INIT(&bu_mapped_file_list); } for (BU_LIST_FOR(mp, bu_mapped_file, &bu_mapped_file_list)) { BU_CK_MAPPED_FILE(mp); /* find a match */ if (!BU_STR_EQUAL(real_path, mp->name)) continue; if (appl && !BU_STR_EQUAL(appl, mp->appl)) continue; /* found a match */ /* if mapped file still exists, verify size and modtime */ if (!mp->dont_restat) { bu_semaphore_acquire(BU_SEM_SYSCALL); fd = open(real_path, O_RDONLY | O_BINARY); bu_semaphore_release(BU_SEM_SYSCALL); /* If file didn't vanish from disk, make sure it's the same file */ if (fd >= 0) { #ifdef HAVE_SYS_STAT_H bu_semaphore_acquire(BU_SEM_SYSCALL); ret = fstat(fd, &sb); bu_semaphore_release(BU_SEM_SYSCALL); if (ret < 0) { /* odd, open worked but fstat failed. assume it * vanished from disk and the mapped copy is still * OK. */ bu_semaphore_acquire(BU_SEM_SYSCALL); (void)close(fd); bu_semaphore_release(BU_SEM_SYSCALL); fd = -1; } if ((size_t)sb.st_size != mp->buflen) { bu_log("bu_open_mapped_file(%s) WARNING: File size changed from %ld to %ld, opening new version.\n", real_path, mp->buflen, sb.st_size); /* mp doesn't reflect the file any longer. Invalidate. */ mp->appl = bu_strdup("__STALE__"); /* Can't invalidate old copy, it may still be in use. */ break; } if (sb.st_mtime != mp->modtime) { bu_log("bu_open_mapped_file(%s) WARNING: File modified since last mapped, opening new version.\n", real_path); /* mp doesn't reflect the file any longer. Invalidate. */ mp->appl = bu_strdup("__STALE__"); /* Can't invalidate old copy, it may still be in use. */ break; } /* To be completely safe, should check st_dev and st_inum */ #endif } /* It is safe to reuse mp */ mp->uses++; bu_semaphore_release(BU_SEM_MAPPEDFILE); if (UNLIKELY(bu_debug&BU_DEBUG_MAPPED_FILE)) bu_pr_mapped_file("open_reused", mp); return mp; } /* It is safe to reuse mp */ mp->uses++; return mp; } /* done iterating over mapped file list */ bu_semaphore_release(BU_SEM_MAPPEDFILE); /* necessary in case we take a 'fail' path before BU_ALLOC() */ mp = NULL; /* File is not yet mapped or has changed, open file read only if * we didn't find it earlier. */ #ifdef HAVE_SYS_STAT_H if (fd < 0) { bu_semaphore_acquire(BU_SEM_SYSCALL); fd = open(real_path, O_RDONLY | O_BINARY); bu_semaphore_release(BU_SEM_SYSCALL); } if (UNLIKELY(fd < 0)) { if (UNLIKELY(bu_debug&BU_DEBUG_MAPPED_FILE)) perror(real_path); goto fail; } bu_semaphore_acquire(BU_SEM_SYSCALL); ret = fstat(fd, &sb); bu_semaphore_release(BU_SEM_SYSCALL); if (UNLIKELY(ret < 0)) { perror(real_path); goto fail; } if (UNLIKELY(sb.st_size == 0)) { bu_log("bu_open_mapped_file(%s) 0-length file\n", real_path); goto fail; } #endif /* HAVE_SYS_STAT_H */ /* Optimistically assume that things will proceed OK */ BU_ALLOC(mp, struct bu_mapped_file); mp->name = bu_strdup(real_path); if (appl) mp->appl = bu_strdup(appl); #ifdef HAVE_SYS_STAT_H mp->buflen = sb.st_size; mp->modtime = sb.st_mtime; # ifdef HAVE_SYS_MMAN_H /* Attempt to access as memory-mapped file */ bu_semaphore_acquire(BU_SEM_SYSCALL); mp->buf = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); bu_semaphore_release(BU_SEM_SYSCALL); if (UNLIKELY(mp->buf == MAP_FAILED)) perror(real_path); if (mp->buf != MAP_FAILED) { /* OK, its memory mapped in! */ mp->is_mapped = 1; /* It's safe to close the fd now, the manuals say */ } else # endif /* HAVE_SYS_MMAN_H */ { /* Allocate a local zero'd buffer, and slurp it in always * leaving space for a trailing zero. */ mp->buf = bu_calloc(1, sb.st_size+1, real_path); nbytes = 0; bytes_to_go = sb.st_size; bu_semaphore_acquire(BU_SEM_SYSCALL); while (nbytes < sb.st_size) { readval = read(fd, ((char *)(mp->buf)) + nbytes, ((bytes_to_go > INT_MAX) ? (INT_MAX) : (bytes_to_go))); if (UNLIKELY(readval < 0)) { bu_semaphore_release(BU_SEM_SYSCALL); perror(real_path); bu_free(mp->buf, real_path); goto fail; } else { nbytes += readval; bytes_to_go -= readval; } } bu_semaphore_release(BU_SEM_SYSCALL); if (UNLIKELY(nbytes != sb.st_size)) { perror(real_path); bu_free(mp->buf, real_path); goto fail; } } #else /* !HAVE_SYS_STAT_H */ /* Read it in with stdio, with no clue how big it is */ bu_semaphore_acquire(BU_SEM_SYSCALL); fp = fopen(real_path, "rb"); bu_semaphore_release(BU_SEM_SYSCALL); if (UNLIKELY(fp == NULL)) { perror(real_path); goto fail; } /* Read it once to see how large it is */ { char buf[32768] = {0}; int got; mp->buflen = 0; bu_semaphore_acquire(BU_SEM_SYSCALL); while ((got = fread(buf, 1, sizeof(buf), fp)) > 0) mp->buflen += got; rewind(fp); bu_semaphore_release(BU_SEM_SYSCALL); } /* Allocate the necessary buffer */ mp->buf = bu_calloc(1, mp->buflen+1, real_path); /* Read it again into the buffer */ bu_semaphore_acquire(BU_SEM_SYSCALL); ret = fread(mp->buf, mp->buflen, 1, fp); bu_semaphore_release(BU_SEM_SYSCALL); if (UNLIKELY(ret != 1)) { bu_semaphore_acquire(BU_SEM_SYSCALL); perror("fread"); fclose(fp); bu_semaphore_release(BU_SEM_SYSCALL); bu_log("bu_open_mapped_file() 2nd fread failed? len=%d\n", mp->buflen); bu_free(mp->buf, "non-unix fread buf"); goto fail; } bu_semaphore_acquire(BU_SEM_SYSCALL); fclose(fp); bu_semaphore_release(BU_SEM_SYSCALL); #endif if (fd >= 0) { bu_semaphore_acquire(BU_SEM_SYSCALL); (void)close(fd); bu_semaphore_release(BU_SEM_SYSCALL); } mp->uses = 1; mp->l.magic = BU_MAPPED_FILE_MAGIC; bu_semaphore_acquire(BU_SEM_MAPPEDFILE); BU_LIST_APPEND(&bu_mapped_file_list, &mp->l); bu_semaphore_release(BU_SEM_MAPPEDFILE); if (UNLIKELY(bu_debug&BU_DEBUG_MAPPED_FILE)) { bu_pr_mapped_file("1st_open", mp); } if (real_path) { bu_free(real_path, "real_path alloc from bu_realpath"); } return mp; fail: if (fd >= 0) { bu_semaphore_acquire(BU_SEM_SYSCALL); (void)close(fd); bu_semaphore_release(BU_SEM_SYSCALL); } if (mp) { bu_free(mp->name, "mp->name"); if (mp->appl) bu_free(mp->appl, "mp->appl"); /* Don't free mp->buf here, it might not be bu_malloced but mmaped */ bu_free(mp, "mp from bu_open_mapped_file fail"); } if (UNLIKELY(bu_debug&BU_DEBUG_MAPPED_FILE)) bu_log("bu_open_mapped_file(%s, %s) can't open file\n", real_path, appl ? appl: "(NIL)"); if (real_path) { bu_free(real_path, "real_path alloc from bu_realpath"); } return (struct bu_mapped_file *)NULL; }