blob: 48c79a51b285990388d6279bb977f207eef84b1e [file] [log] [blame]
/*
* 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 Port
* @brief Port Library
*/
#include <string.h>
#include "hyport.h"
#include "portpriv.h"
#include "hyportpg.h"
#ifdef ZOS
#include "atoe.h"
#endif
/**
* Initialize the port library.
*
* Given a pointer to a port library and the required version,
* populate the port library table with the appropriate functions
* and then call the startup function for the port library.
*
* @param[in] portLibrary The port library.
* @param[in] version The required version of the port library.
* @param[in] size Size of the port library.
*
* @return 0 on success, negative return value on failure
*/
I_32 VMCALL
hyport_init_library (struct HyPortLibrary *portLibrary,
struct HyPortLibraryVersion *version, UDATA size)
{
/* return value of 0 is success */
I_32 rc;
#if defined(ZOS)
/* Initialise the ascii2ebcdic functions if it has not already been done */
rc = iconv_init();
if (rc ==0)
#endif
{
rc = hyport_create_library (portLibrary, version, size);
}
if (rc == 0)
{
rc = hyport_startup_library (portLibrary);
}
if (rc == 0)
{
// try and initialise the nls data before any nls_* calls
initNLSCatalog(portLibrary);
}
return rc;
}
/**
* PortLibrary shutdown.
*
* Shutdown the port library, de-allocate resources required by the components of the portlibrary.
* Any resources that werer created by @ref hyport_startup_library should be destroyed here.
*
* @param[in] portLibrary The portlibrary.
*
* @return 0 on success, negative return code on failure
*/
I_32 VMCALL
hyport_shutdown_library (struct HyPortLibrary * portLibrary)
{
#ifdef HY_NO_THR
THREAD_ACCESS_FROM_PORT(portLibrary);
#endif /* HY_NO_THR */
portLibrary->shmem_shutdown (portLibrary);
portLibrary->shsem_shutdown (portLibrary);
portLibrary->str_shutdown (portLibrary);
portLibrary->sl_shutdown (portLibrary);
portLibrary->sysinfo_shutdown (portLibrary);
portLibrary->exit_shutdown (portLibrary);
portLibrary->gp_shutdown (portLibrary);
portLibrary->time_shutdown (portLibrary);
/* Shutdown the socket library before the tty, so it can write to the tty if required */
portLibrary->sock_shutdown (portLibrary);
portLibrary->nls_shutdown (portLibrary);
portLibrary->ipcmutex_shutdown (portLibrary);
portLibrary->mmap_shutdown (portLibrary);
portLibrary->tty_shutdown (portLibrary);
portLibrary->file_shutdown (portLibrary);
portLibrary->vmem_shutdown (portLibrary);
portLibrary->cpu_shutdown (portLibrary);
portLibrary->error_shutdown (portLibrary);
hyport_tls_shutdown (portLibrary);
portLibrary->mem_shutdown (portLibrary);
hythread_detach (portLibrary->attached_thread);
/* Last thing to do. If this port library was self allocated free this memory */
if (NULL != portLibrary->self_handle)
{
hymem_deallocate_portLibrary (portLibrary);
}
return (I_32) 0;
}
/**
* Create the port library.
*
* Given a pointer to a port library and the required version,
* populate the port library table with the appropriate functions
*
* @param[in] portLibrary The port library.
* @param[in] version The required version of the port library.
* @param[in] size Size of the port library.
*
* @return 0 on success, negative return value on failure
* @note The portlibrary version must be compatabile with the that which we are compiled against
*/
I_32 VMCALL
hyport_create_library (struct HyPortLibrary * portLibrary,
struct HyPortLibraryVersion * version, UDATA size)
{
UDATA versionSize = hyport_getSize (version);
if (HYPORT_MAJOR_VERSION_NUMBER != version->majorVersionNumber)
{
return -1;
}
if (versionSize > size)
{
return -1;
}
/* Ensure required functionality is there */
if ((version->capabilities & HYPORT_CAPABILITY_MASK) !=
version->capabilities)
{
return -1;
}
/* Null and initialize the table passed in */
memset (portLibrary, 0, size);
memcpy (portLibrary, &MasterPortLibraryTable, versionSize);
/* Reset capabilities to be what is actually there, not what was requested */
portLibrary->portVersion.majorVersionNumber = version->majorVersionNumber;
portLibrary->portVersion.minorVersionNumber = version->minorVersionNumber;
portLibrary->portVersion.capabilities = HYPORT_CAPABILITY_MASK;
return 0;
}
/**
* PortLibrary startup.
*
* Start the port library, allocate resources required by the components of the portlibrary.
* All resources created here should be destroyed in @ref hyport_shutdown_library.
*
* @param[in] portLibrary The portlibrary.
*
* @return 0 on success, negative error code on failure. Error code values returned are
* \arg HYPORT_ERROR_STARTUP_THREAD
* \arg HYPORT_ERROR_STARTUP_MEM
* \arg HYPORT_ERROR_STARTUP_TLS
* \arg HYPORT_ERROR_STARTUP_TLS_ALLOC
* \arg HYPORT_ERROR_STARTUP_TLS_MUTEX
* \arg HYPORT_ERROR_STARTUP_ERROR
* \arg HYPORT_ERROR_STARTUP_CPU
* \arg HYPORT_ERROR_STARTUP_VMEM
* \arg HYPORT_ERROR_STARTUP_FILE
* \arg HYPORT_ERROR_STARTUP_TTY
* \arg HYPORT_ERROR_STARTUP_TTY_HANDLE
* \arg HYPORT_ERROR_STARTUP_TTY_CONSOLE
* \arg HYPORT_ERROR_STARTUP_MMAP
* \arg HYPORT_ERROR_STARTUP_IPCMUTEX
* \arg HYPORT_ERROR_STARTUP_NLS
* \arg HYPORT_ERROR_STARTUP_SOCK
* \arg HYPORT_ERROR_STARTUP_TIME
* \arg HYPORT_ERROR_STARTUP_GP
* \arg HYPORT_ERROR_STARTUP_EXIT
* \arg HYPORT_ERROR_STARTUP_SYSINFO
* \arg HYPORT_ERROR_STARTUP_SL
* \arg HYPORT_ERROR_STARTUP_STR
* \arg HYPORT_ERROR_STARTUP_SHSEM
* \arg HYPORT_ERROR_STARTUP_SHMEM
* \arg HYPORT_ERROR_STARTUP_SIGNAL
*
* @note The port library memory is deallocated if it was created by @ref hyport_allocate_library
*/
I_32 VMCALL
hyport_startup_library (struct HyPortLibrary * portLibrary)
{
I_32 rc = 0;
#ifdef HY_NO_THR
HyThreadLibrary *hyThreadLibrary;
HyThreadLibraryVersion hyThreadLibraryVersion;
HYTHREAD_SET_VERSION(&hyThreadLibraryVersion, HYTHREAD_CAPABILITY_MASK);
rc = hythread_allocate_library(&hyThreadLibraryVersion, &hyThreadLibrary);
if ( 0 != rc ) {
rc = HYPORT_ERROR_STARTUP_THREAD;
goto cleanup;
}
rc = hythread_startup_library(hyThreadLibrary);
if ( 0 != rc )
{
rc = HYPORT_ERROR_STARTUP_THREAD;
goto cleanup;
}
#endif /* HY_NO_THR */
/* NLS uses the thread library */
#ifndef HY_NO_THR
rc = hythread_attach (&portLibrary->attached_thread);
#else /* HY_NO_THR */
rc = hyThreadLibrary->thread_attach (hyThreadLibrary, &portLibrary->attached_thread);
#endif /* HY_NO_THR */
if (0 != rc)
{
/* Reassign return code as hythread_attach only returns -1 on error */
rc = HYPORT_ERROR_STARTUP_THREAD;
goto cleanup;
}
/* Must not access anything in portGlobals, as this allocates them */
rc =
portLibrary->mem_startup (portLibrary, sizeof (HyPortLibraryGlobalData));
if (0 != rc)
{
goto cleanup;
}
#ifdef HY_NO_THR
/* Store threadLibrary in port globals */
portLibrary->portGlobals->threadLibrary = hyThreadLibrary;
#endif /* HY_NO_THR */
/* Create the tls buffers as early as possible */
rc = hyport_tls_startup (portLibrary);
if (0 != rc)
{
goto cleanup;
}
/* Start error handling as early as possible, require TLS buffers */
rc = portLibrary->error_startup (portLibrary);
if (0 != rc)
{
goto cleanup;
}
rc = portLibrary->cpu_startup (portLibrary);
if (0 != rc)
{
goto cleanup;
}
rc = portLibrary->vmem_startup (portLibrary);
if (0 != rc)
{
goto cleanup;
}
rc = portLibrary->file_startup (portLibrary);
if (0 != rc)
{
goto cleanup;
}
rc = portLibrary->tty_startup (portLibrary);
if (0 != rc)
{
goto cleanup;
}
rc = portLibrary->mmap_startup (portLibrary);
if (0 != rc)
{
goto cleanup;
}
rc = portLibrary->ipcmutex_startup (portLibrary);
if (0 != rc)
{
goto cleanup;
}
rc = portLibrary->nls_startup (portLibrary);
if (0 != rc)
{
goto cleanup;
}
rc = portLibrary->sock_startup (portLibrary);
if (0 != rc)
{
goto cleanup;
}
rc = portLibrary->time_startup (portLibrary);
if (0 != rc)
{
goto cleanup;
}
rc = portLibrary->gp_startup (portLibrary);
if (0 != rc)
{
goto cleanup;
}
rc = portLibrary->exit_startup (portLibrary);
if (0 != rc)
{
goto cleanup;
}
rc = portLibrary->sysinfo_startup (portLibrary);
if (0 != rc)
{
goto cleanup;
}
rc = portLibrary->sl_startup (portLibrary);
if (0 != rc)
{
goto cleanup;
}
rc = portLibrary->str_startup (portLibrary);
if (0 != rc)
{
goto cleanup;
}
rc = portLibrary->shsem_startup (portLibrary);
if (0 != rc)
{
goto cleanup;
}
rc = portLibrary->shmem_startup (portLibrary);
if (0 != rc)
{
goto cleanup;
}
return rc;
cleanup:
/* TODO: should call shutdown, but need to make all shutdown functions
* safe if the corresponding startup was not called. No worse than the existing
* code
*/
/* If this port library was self allocated free this memory */
if (NULL != portLibrary->self_handle)
{
hymem_deallocate_portLibrary (portLibrary);
}
return rc;
}
/**
* Determine the size of the port library.
*
* Given a port library version, return the size of the structure in bytes
* required to be allocated.
*
* @param[in] version The HyPortLibraryVersion structure.
*
* @return size of port library on success, zero on failure
*
* @note The portlibrary version must be compatabile with the that which we are compiled against
*/
UDATA VMCALL
hyport_getSize (struct HyPortLibraryVersion * version)
{
/* Can't initialize a structure that is not understood by this version of the port library */
if (HYPORT_MAJOR_VERSION_NUMBER != version->majorVersionNumber)
{
return 0;
}
/* The size of the portLibrary table is determined by the majorVersion number
* and the presence/absense of the HYPORT_CAPABILITY_STANDARD capability
*/
if (0 != (version->capabilities & HYPORT_CAPABILITY_STANDARD))
{
return sizeof (HyPortLibrary);
}
else
{
return offsetof (HyPortLibrary, attached_thread) + sizeof (void *);
}
}
/**
* Determine the version of the port library.
*
* Given a port library return the version of that instance.
*
* @param[in] portLibrary The port library.
* @param[in,out] version The HyPortLibraryVersion structure to be populated.
*
* @return 0 on success, negative return value on failure
* @note If portLibrary is NULL, version is populated with the version in the linked DLL
*/
I_32 VMCALL
hyport_getVersion (struct HyPortLibrary *portLibrary,
struct HyPortLibraryVersion *version)
{
if (NULL == version)
{
return -1;
}
if (portLibrary)
{
version->majorVersionNumber =
portLibrary->portVersion.majorVersionNumber;
version->minorVersionNumber =
portLibrary->portVersion.minorVersionNumber;
version->capabilities = portLibrary->portVersion.capabilities;
}
else
{
version->majorVersionNumber = HYPORT_MAJOR_VERSION_NUMBER;
version->minorVersionNumber = HYPORT_MINOR_VERSION_NUMBER;
version->capabilities = HYPORT_CAPABILITY_MASK;
}
return 0;
}
/**
* Determine port library compatibility.
*
* Given the minimum version of the port library that the application requires determine
* if the current port library meets that requirements.
*
* @param[in] expectedVersion The version the application requires as a minimum.
*
* @return 1 if compatible, 0 if not compatible
*/
I_32 VMCALL
hyport_isCompatible (struct HyPortLibraryVersion * expectedVersion)
{
/* Position of functions, signature of functions.
* Major number incremented when existing functions change positions or signatures
*/
if (HYPORT_MAJOR_VERSION_NUMBER != expectedVersion->majorVersionNumber)
{
return 0;
}
/* Size of table, it's ok to have more functions at end of table that are not used.
* Minor number incremented when new functions added to the end of the table
*/
if (HYPORT_MINOR_VERSION_NUMBER < expectedVersion->minorVersionNumber)
{
return 0;
}
/* Functionality supported */
return (HYPORT_CAPABILITY_MASK & expectedVersion->capabilities) ==
expectedVersion->capabilities;
}
/**
* Query the port library.
*
* Given a pointer to the port library and an offset into the table determine if
* the function at that offset has been overridden from the default value expected.
*
* @param[in] portLibrary The port library.
* @param[in] offset The offset of the function to be queried.
*
* @return 1 if the function is overriden, else 0.
*
* hyport_isFunctionOverridden(portLibrary, offsetof(HyPortLibrary, mem_allocate_memory));
*/
I_32 VMCALL
hyport_isFunctionOverridden (struct HyPortLibrary * portLibrary, UDATA offset)
{
UDATA requiredSize;
requiredSize = hyport_getSize (&(portLibrary->portVersion));
if (requiredSize < offset)
{
return 0;
}
return *((UDATA *) & (((U_8 *) portLibrary)[offset])) !=
*((UDATA *) & (((U_8 *) & MasterPortLibraryTable)[offset]));
}
/**
* Allocate a port library.
*
* Given a pointer to the required version of the port library allocate and initialize the structure.
* The startup function is not called (@ref hyport_startup_library) allowing the application to override
* any functions they desire. In the event @ref hyport_startup_library fails when called by the application
* the port library memory will be freed.
*
* @param[in] version The required version of the port library.
* @param[out] portLibrary Pointer to the allocated port library table.
*
* @return 0 on success, negative return value on failure
*
* @note portLibrary will be NULL on failure
* @note The portlibrary version must be compatabile with the that which we are compiled against
* @note @ref hyport_shutdown_library will deallocate this memory as part of regular shutdown
*/
I_32 VMCALL
hyport_allocate_library (struct HyPortLibraryVersion * version,
struct HyPortLibrary ** portLibrary)
{
UDATA size = hyport_getSize (version);
HyPortLibrary *portLib;
I_32 rc;
/* Allocate the memory */
*portLibrary = NULL;
if (0 == size)
{
return -1;
}
else
{
portLib = hymem_allocate_portLibrary (size);
if (NULL == portLib)
{
return -1;
}
}
/* Initialize with default values */
rc = hyport_create_library (portLib, version, size);
if (0 == rc)
{
/* Record this was self allocated */
portLib->self_handle = portLib;
*portLibrary = portLib;
}
else
{
hymem_deallocate_portLibrary (portLib);
}
return rc;
}
#ifdef HY_NO_THR
HyThreadLibrary * VMCALL
hyport_get_thread_library(HyPortLibrary * portLib)
{
return portLib->portGlobals->threadLibrary;
}
#endif /* HY_NO_THR */
/* Set up the NLS catalog. This must be called prior to attempting
* any nls_printf() calls on the port library.
*/
void
initNLSCatalog (HyPortLibrary * portLib)
{
char *endPathPtr = NULL;
char *launcherName = NULL;
const char **pathSet = portLib->mem_allocate_memory (portLib, sizeof(char*)*2);
char *vmPath = NULL;
hysysinfo_get_executable_name (portLib, NULL, &launcherName);
if (launcherName == NULL) {
/* TOFIX: This is really a hack to work around the fact that the
* hysysinfo_get_executable_name function currently only works
* when argv[0] is passed (not NULL as above) and/or when running
* on Linux (with /proc mounted).
*/
portLib->nls_set_catalog (portLib, (const char **) NULL, 0, "harmony", "properties");
} else {
endPathPtr = strrchr (launcherName, DIR_SEPARATOR);
endPathPtr[1] = '\0';
// launcherName now holds the name of the launcher's home directory
vmPath = portLib->mem_allocate_memory (portLib, strlen(launcherName) + 9);
strcpy(vmPath, launcherName);
strcat(vmPath, "default");
vmPath[strlen(vmPath)+1] = '\0';
vmPath[strlen(vmPath)] = DIR_SEPARATOR;
pathSet[0] = launcherName;
pathSet[1] = vmPath;
portLib->nls_set_catalog (portLib, pathSet, 2, "harmony", "properties");
// Free memory for launcherName -- necessary ??
portLib->mem_free_memory (portLib, launcherName);
portLib->mem_free_memory (portLib, (void*) pathSet);
portLib->mem_free_memory (portLib, vmPath);
}
}