static void evict_random_item(struct program_cache *cache) { const char hex[] = "0123456789abcde"; char *dir_path; int a, b; size_t size; /* With a reasonably-sized, full cache, (and with keys generated * from a cryptographic hash), we can choose two random hex digits * and reasonably expect the directory to exist with a file in it. */ a = rand() % 16; b = rand() % 16; asprintf (&dir_path, "%s/%c%c", cache->path, hex[a], hex[b]); if (dir_path == NULL) return; size = unlink_random_file_from_directory(dir_path); free(dir_path); if (size) { p_atomic_add(cache->size, - size); return; } /* In the case where the random choice of directory didn't find * something, we choose randomly from the existing directories. * * Really, the only reason this code exists is to allow the unit * tests to work, (which use an artificially-small cache to be able * to force a single cached item to be evicted). */ dir_path = choose_random_file_matching(cache->path, is_two_character_sub_directory); if (dir_path == NULL) return; size = unlink_random_file_from_directory(dir_path); free(dir_path); if (size) p_atomic_add(cache->size, - size); }
static void swr_UpdateStatsFE(HANDLE hPrivateContext, const SWR_STATS_FE *pStats) { swr_draw_context *pDC = (swr_draw_context*)hPrivateContext; if (!pDC) return; struct swr_query_result *pqr = pDC->pStats; SWR_STATS_FE *pSwrStats = &pqr->coreFE; p_atomic_add(&pSwrStats->IaVertices, pStats->IaVertices); p_atomic_add(&pSwrStats->IaPrimitives, pStats->IaPrimitives); p_atomic_add(&pSwrStats->VsInvocations, pStats->VsInvocations); p_atomic_add(&pSwrStats->HsInvocations, pStats->HsInvocations); p_atomic_add(&pSwrStats->DsInvocations, pStats->DsInvocations); p_atomic_add(&pSwrStats->GsInvocations, pStats->GsInvocations); p_atomic_add(&pSwrStats->CInvocations, pStats->CInvocations); p_atomic_add(&pSwrStats->CPrimitives, pStats->CPrimitives); p_atomic_add(&pSwrStats->GsPrimitives, pStats->GsPrimitives); for (unsigned i = 0; i < 4; i++) { p_atomic_add(&pSwrStats->SoPrimStorageNeeded[i], pStats->SoPrimStorageNeeded[i]); p_atomic_add(&pSwrStats->SoNumPrimsWritten[i], pStats->SoNumPrimsWritten[i]); } }
void cache_put(struct program_cache *cache, cache_key key, const void *data, size_t size) { int fd = -1, fd_final = -1, err, ret; size_t len; char *filename = NULL, *filename_tmp = NULL; const char *p = data; filename = get_cache_file(cache, key); if (filename == NULL) goto done; /* Write to a temporary file to allow for an atomic rename to the * final destination filename, (to prevent any readers from seeing * a partially written file). */ filename_tmp = ralloc_asprintf(cache, "%s.tmp", filename); if (filename_tmp == NULL) goto done; fd = open(filename_tmp, O_WRONLY | O_CLOEXEC | O_CREAT, 0644); /* Make the two-character subdirectory within the cache as needed. */ if (fd == -1) { if (errno != ENOENT) goto done; make_cache_file_directory(cache, key); fd = open(filename_tmp, O_WRONLY | O_CLOEXEC | O_CREAT, 0644); if (fd == -1) goto done; } /* With the temporary file open, we take an exclusive flock on * it. If the flock fails, then another process still has the file * open with the flock held. So just let that file be responsible * for writing the file. */ err = flock(fd, LOCK_EX | LOCK_NB); if (err == -1) goto done; /* Now that we have the lock on the open temporary file, we can * check to see if the destination file already exists. If so, * another process won the race between when we saw that the file * didn't exist and now. In this case, we don't do anything more, * (to ensure the size accounting of the cache doesn't get off). */ fd_final = open(filename, O_RDONLY | O_CLOEXEC); if (fd_final != -1) goto done; /* OK, we're now on the hook to write out a file that we know is * not in the cache, and is also not being written out to the cache * by some other process. * * Before we do that, if the cache is too large, evict something * else first. */ if (*cache->size + size > cache->max_size) evict_random_item(cache); /* Now, finally, write out the contents to the temporary file, then * rename them atomically to the destination filename, and also * perform an atomic increment of the total cache size. */ for (len = 0; len < size; len += ret) { ret = write(fd, p + len, size - len); if (ret == -1) { unlink(filename_tmp); goto done; } } rename(filename_tmp, filename); p_atomic_add(cache->size, size); /* This close finally releases the flock, (now that the final dile * has been renamed into place and the size has been added). */ close(fd); fd = -1; done: if (filename_tmp) ralloc_free(filename_tmp); if (filename) ralloc_free(filename); if (fd != -1) close(fd); }