blob: 72999ee829bce73d543344f66e96c3d05104c192 [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* @ingroup ZipSupport
* @brief Zip Support for Java VM
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "hyport.h"
#include "zipsup.h"
#include "hypool.h"
#include "hymutex.h"
typedef struct HyZipCachePoolEntry
{
HyZipCache *cache;
UDATA referenceCount;
} HyZipCachePoolEntry;
/* No typedef because an opaque typedef appears in zipsup.h (already included) */
struct HyZipCachePool
{
HyPool *pool;
HyZipCache *desiredCache;
I_64 zipTimeStamp;
char const *zipFileName;
IDATA zipFileNameLength;
IDATA zipFileSize;
MUTEX mutex;
};
void zipCachePool_doFindHandler
PROTOTYPE ((HyZipCachePoolEntry * entry, HyZipCachePool * zcp));
void zipCachePool_doKillHandler
PROTOTYPE ((HyZipCachePoolEntry * entry, HyZipCachePool * zcp));
/**
* Add a new cache to the pool with reference count of 1.
*
* When reference count reaches zero the pool will automatically be freed.
*
* @param[in] zcp the zip cache pool that is being added to.
* @param[in] zipCache the zip cache being added.
*
* @return TRUE if successful, FALSE otherwise.
*
* @note A cache may only reside in one pool (read: multiple VMs may not share caches with each other).
*/
BOOLEAN
zipCachePool_addCache (HyZipCachePool * zcp, HyZipCache * zipCache)
{
HyZipCachePoolEntry *entry;
if (!zcp || !zipCache)
return FALSE;
MUTEX_ENTER (zcp->mutex);
entry = pool_newElement (zcp->pool);
if (!entry)
{
MUTEX_EXIT (zcp->mutex);
return FALSE;
}
zipCache->cachePool = zcp;
zipCache->cachePoolEntry = entry;
entry->cache = zipCache;
entry->referenceCount = 1;
MUTEX_EXIT (zcp->mutex);
return TRUE;
}
/**
* Increment the reference count of a cache in the pool.
*
* @note Result is undefined if the cache is not actually in the pool!
*
* @param[in] zcp the zip cache pool that is being added to.
* @param[in] zipCache the zip cache being added.
*
* @return TRUE if successful, FALSE otherwise.
*/
BOOLEAN
zipCachePool_addRef (HyZipCachePool * zcp, HyZipCache * zipCache)
{
HyZipCachePoolEntry *entry;
if (!zcp || !zipCache)
return FALSE;
MUTEX_ENTER (zcp->mutex);
entry = (HyZipCachePoolEntry *) zipCache->cachePoolEntry;
if (!entry)
{
MUTEX_EXIT (zcp->mutex);
return FALSE;
}
entry->referenceCount++;
MUTEX_EXIT (zcp->mutex);
return TRUE;
}
/**
* Scans the pool for a cache with matching zipFileName, zipFileSize and zipTimeStamp.
*
* The reference count is incremented and the cache is returned if a match is found.
*
* @param[in] zcp the zip cache pool to search
* @param[in] zipFileName the name to test for match
* @param[in] zipFileNameLength the length of zipFileName
* @param[in] zipFileSize the size to test for match
* @param[in] zipTimeStamp the time stamp to test for match
*
* @return the matching zip cache
* @return NULL if no match is found.
*/
HyZipCache *
zipCachePool_findCache (HyZipCachePool * zcp, char const *zipFileName,
IDATA zipFileNameLength, IDATA zipFileSize,
I_64 zipTimeStamp)
{
HyZipCache *zipCache;
HyZipCachePoolEntry *entry;
if (!zcp || !zipFileName)
return NULL;
MUTEX_ENTER (zcp->mutex);
/* Find a suitable cache */
zcp->desiredCache = NULL;
zcp->zipFileName = zipFileName;
zcp->zipFileSize = zipFileSize;
zcp->zipTimeStamp = zipTimeStamp;
zcp->zipFileNameLength = zipFileNameLength;
pool_do (zcp->pool, (void (*)(void *, void *)) zipCachePool_doFindHandler,
zcp);
zipCache = zcp->desiredCache;
if (zipCache)
{
entry = (HyZipCachePoolEntry *) zipCache->cachePoolEntry;
entry->referenceCount++;
}
MUTEX_EXIT (zcp->mutex);
return zipCache;
}
/**
* Deletes a pool containing shareable zip caches.
*
* @param[in] zcp the zip cache pool that is being deleted
*
* @return none
*
* @note Warning: This also deletes remaining caches in the pool, regardless of their reference counts!
*
*/
void
zipCachePool_kill (HyZipCachePool * zcp)
{
void (VMCALL * memFree) (void *, void *);
void *userData;
if (!zcp)
return;
pool_do (zcp->pool, (void (*)(void *, void *)) zipCachePool_doKillHandler,
zcp);
MUTEX_DESTROY (zcp->mutex);
/* Grab the memFree and userData out of the pool BEFORE we destroy it. */
memFree = zcp->pool->memFree;
userData = zcp->pool->userData;
pool_kill (zcp->pool);
memFree (userData, zcp);
}
/**
* Creates a pool to hold shareable zip caches with their reference counts.
* This should be called once per VM.
*
* @param[in] portLib the port library
*
* @return a zip cache pool or NULL if one cannot be created
*
*/
HyZipCachePool *
zipCachePool_new (HyPortLibrary * portLib)
{
PORT_ACCESS_FROM_PORT (portLib);
HyZipCachePool *p = hymem_allocate_memory (sizeof (*p));
HyZipCachePool *toReturn = NULL;
if (p != NULL)
{
if (MUTEX_INIT (p->mutex))
{
p->pool = pool_forPortLib (sizeof (HyZipCachePoolEntry), portLib);
if (p->pool)
{
/* All initialization worked so set up to return the pointer */
toReturn = p;
}
else
{
/* pool discovery failed so give up the mutex */
MUTEX_DESTROY (p->mutex);
}
}
if (NULL == toReturn)
{
/* something went wrong so free the memory */
hymem_free_memory (p);
}
}
return toReturn;
}
/**
* Decrements the reference count of a cache in the pool.
* If the reference count reaches 0, the cache is removed from the pool and @ref zipCache_kill is called on it.
*
* @param[in] zcp the zip cache pool
* @param[in] zipCache the zip cache whose count is being decremented.
*
* @return TRUE if the cache was destroyed
* @return FALSE if the cache is still in the pool.
*
*/
BOOLEAN
zipCachePool_release (HyZipCachePool * zcp, HyZipCache * zipCache)
{
HyZipCachePoolEntry *entry;
if (!zcp || !zipCache)
return FALSE;
MUTEX_ENTER (zcp->mutex);
entry = (HyZipCachePoolEntry *) zipCache->cachePoolEntry;
if (!entry)
{
/* What the..? */
MUTEX_EXIT (zcp->mutex);
return FALSE;
}
if (--entry->referenceCount != 0)
{
MUTEX_EXIT (zcp->mutex);
return FALSE;
}
/* Reference count is zero, get rid of the cache */
zipCache_kill (entry->cache);
pool_removeElement (zcp->pool, entry);
MUTEX_EXIT (zcp->mutex);
return TRUE;
}
void
zipCachePool_doFindHandler (HyZipCachePoolEntry * entry, HyZipCachePool * zcp)
{
if (zcp->desiredCache)
return; /* already done */
if (entry->cache->zipTimeStamp != zcp->zipTimeStamp)
return;
if (entry->cache->zipFileSize != zcp->zipFileSize)
return;
if (memcmp
(entry->cache->zipFileName, zcp->zipFileName, zcp->zipFileNameLength))
return;
if (entry->cache->zipFileName[zcp->zipFileNameLength] != '\0')
return;
/* Looks like we have a match. */
zcp->desiredCache = entry->cache;
}
void
zipCachePool_doKillHandler (HyZipCachePoolEntry * entry, HyZipCachePool * zcp)
{
zipCache_kill (entry->cache);
}