Esempio n. 1
0
File: cache.c Progetto: etnaviv/mesa
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);
}
Esempio n. 2
0
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]);
   }
}
Esempio n. 3
0
File: cache.c Progetto: etnaviv/mesa
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);
}