blob: 5ebff51458950f871d643d7fe442f765f3df4da9 [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.
*/
#define CDEV_CURRENT_FUNCTION _comment_
/**
* @file
* @ingroup Port
* @brief Shared Semaphores
*/
#undef CDEV_CURRENT_FUNCTION
#include "portpriv.h"
#include "hyport.h"
#include "portnls.h"
#include "ut_hyprt.h"
#include "hysharedhelper.h"
#include <string.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <sys/stat.h>
#define CDEV_CURRENT_FUNCTION include_header
#include "hyshsem.h"
#undef CDEV_CURRENT_FUNCTION
/*These flags are only used internally*/
#define CREATE_ERROR -10
#define OPEN_ERROR -11
#define WRITE_ERROR -12
#define READ_ERROR -13
#define MALLOC_ERROR -14
#define HYSH_NO_DATA -21
#define HYSH_BAD_DATA -22
#define RETRY_COUNT 10
#define SLEEP_TIME 5
#define SEMAPHORE_OPENED 2
#define SEMAPHORE_CREATED 1
#define SUCCESS 0
#define FAILED -1
#define RETRY -2
#define SEMMARKER 769
#define CDEV_CURRENT_FUNCTION _prototypes_private
static IDATA checkMarker (hyshsem_handle * handle, int semsetsize);
static IDATA createbaseFile (struct HyPortLibrary *portLibrary,
char *filename);
static IDATA createSemaphore (struct HyPortLibrary *portLibrary,
char *baseFile, I_32 setSize,
hyshsem_handle ** handle);
static IDATA openSemaphore (struct HyPortLibrary *portLibrary, char *baseFile,
I_64 timestamp, hyshsem_handle ** handle);
static hyshsem_handle *createsemHandle (struct HyPortLibrary *portLibrary,
int semid, int nsems, char *baseFile);
static IDATA readbaseFile (struct HyPortLibrary *portLibrary, char *filename,
hyshsem_baseFileFormat ** basefileInfo);
static I_32 setMarker (hyshsem_handle * handle, int semsetsize);
static I_32 findError (I_32 errorCode, I_32 errorCode2);
static IDATA writebaseFile (struct HyPortLibrary *portLibrary, char *filename,
int proj_id, key_t key, int semid, int setSize);
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hyshsem_open
/**
* Open an existing semaphore set, or create a new one if it does not exist
*
* @param[in] portLibrary The port library.
* @param[out] handle A semaphore handle is allocated and initialised for use with further calls, NULL on failure.
* @param[in] semname Unique identifier of the semaphore.
* @param[in] setSize Size of the semaphore set.
* @param[in] permission Permission to the semaphore set.
*
* @return
* \arg HYPORT_ERROR_SHSEM_OPFAILED Failure - Error opening the semaphore
* \arg HYPORT_INFO_SHSEM_CREATED Success - Semaphore has been created
* \arg HYPORT_INFO_SHSEM_OPENED Success - Existing semaphore has been opened
* \arg HYPORT_INFO_SHSEM_SEMID_DIFF Success - Existing semaphore opened, but OS Semaphore key is different
*/
IDATA VMCALL
hyshsem_open (struct HyPortLibrary *portLibrary,
struct hyshsem_handle **handle, const char *semname,
int setSize, int permission)
{
/* TODO: needs to be longer? dynamic? */
char baseFile[HYSH_MAXPATH];
char versionStr[32];
struct stat statbuf;
I_8 retry = RETRY_COUNT;
I_8 exist = 0;
I_32 fd;
Trc_PRT_shsem_hyshsem_open_Entry (semname, setSize, permission);
if (ensureDirectory (portLibrary) == FAILED)
{
portLibrary->error_set_last_error (portLibrary, errno,
HYPORT_ERROR_SHSEM_DATA_DIRECTORY_FAILED);
Trc_PRT_shsem_hyshsem_open_Exit3 ();
return HYPORT_ERROR_SHSEM_OPFAILED;
}
GET_VERSION_STRING (portLibrary, versionStr);
portLibrary->str_printf (portLibrary, baseFile, HYSH_MAXPATH,
"%s%s_semaphore_%s", HYSH_BASEDIR, versionStr,
semname);
Trc_PRT_shsem_hyshsem_open_Debug1 (baseFile);
while (retry > 0)
{
I_64 timestamp = 0;
I_32 rc = 0;
/* check and see whether the basefile exist */
rc = portLibrary->file_attr (portLibrary, baseFile);
if (HyIsFile == rc)
{
/* baseFile exist, we should try and open the semaphore */
Trc_PRT_shsem_hyshsem_open_Event1 (baseFile);
rc = openSemaphore (portLibrary, baseFile, timestamp, handle);
}
else
{
/* baseFile probably not exist, we should try and create the semaphore */
/* For new semaphore setsize can't be 0 - failure */
if (setSize == 0)
{
return HYPORT_ERROR_SHSEM_OPFAILED;
}
Trc_PRT_shsem_hyshsem_open_Event2 (baseFile);
rc = createSemaphore (portLibrary, baseFile, setSize, handle);
}
switch (rc)
{
case RETRY:
Trc_PRT_shsem_hyshsem_open_Event3 (retry);
usleep (100);
retry--;
break;
case SEMAPHORE_OPENED:
Trc_PRT_shsem_hyshsem_open_Exit (HYPORT_INFO_SHSEM_OPENED, *handle);
return HYPORT_INFO_SHSEM_OPENED;
case HYPORT_INFO_SHSEM_SEMID_DIFF:
Trc_PRT_shsem_hyshsem_open_Exit (HYPORT_INFO_SHSEM_SEMID_DIFF,
*handle);
return HYPORT_INFO_SHSEM_SEMID_DIFF;
case SEMAPHORE_CREATED:
Trc_PRT_shsem_hyshsem_open_Exit (HYPORT_INFO_SHSEM_CREATED,
*handle);
return HYPORT_INFO_SHSEM_CREATED;
case FAILED:
default:
Trc_PRT_shsem_hyshsem_open_Exit1 ();
return HYPORT_ERROR_SHSEM_OPFAILED;
}
} /*end while */
/* we have retried too many times, return failed */
portLibrary->file_unlink (portLibrary, baseFile);
Trc_PRT_shsem_hyshsem_open_Exit2 ();
return HYPORT_ERROR_SHSEM_OPFAILED;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hyshsem_post
/**
* post operation increments the counter in the semaphore by 1 if there is no one in wait for the semaphore.
* if there are other processes suspended by wait then one of them will become runnable and
* the counter remains the same.
*
* @param[in] portLibrary The port library.
* @param[in] handle Semaphore set handle.
* @param[in] semset The no of semaphore in the semaphore set that you want to post.
* @param[in] flag The semaphore operation flag:
* \arg HYPORT_SHSEM_MODE_DEFAULT The default operation flag, same as 0
* \arg HYPORT_SHSEM_MODE_UNDO The changes made to the semaphore will be undone when this process finishes.
*
* @return 0 on success, -1 on failure.
*/
IDATA VMCALL
hyshsem_post (struct HyPortLibrary * portLibrary,
struct hyshsem_handle * handle, UDATA semset, UDATA flag)
{
struct sembuf buffer;
IDATA rc;
Trc_PRT_shsem_hyshsem_post_Entry (handle, semset, flag);
if (handle == NULL)
{
Trc_PRT_shsem_hyshsem_post_Exit1 ();
return HYPORT_ERROR_SHSEM_HANDLE_INVALID;
}
if (semset < 0 || semset >= handle->nsems)
{
Trc_PRT_shsem_hyshsem_post_Exit2 ();
return HYPORT_ERROR_SHSEM_SEMSET_INVALID;
}
buffer.sem_num = semset;
buffer.sem_op = 1; /* post */
if (flag & HYPORT_SHSEM_MODE_UNDO)
{
buffer.sem_flg = SEM_UNDO;
}
else
{
buffer.sem_flg = 0;
}
rc = semop (handle->semid, &buffer, 1);
if (-1 == rc)
{
Trc_PRT_shsem_hyshsem_post_Exit3 (rc, errno);
}
else
{
Trc_PRT_shsem_hyshsem_post_Exit (rc);
}
return rc;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hyshsem_wait
/**
* Wait operation decrements the counter in the semaphore set if the counter > 0
* if counter == 0 then the caller will be suspended.
*
* @param[in] portLibrary The port library.
* @param[in] handle Semaphore set handle.
* @param[in] semset The no of semaphore in the semaphore set that you want to post.
* @param[in] flag The semaphore operation flag:
* \arg HYPORT_SHSEM_MODE_DEFAULT The default operation flag, same as 0
* \arg HYPORT_SHSEM_MODE_UNDO The changes made to the semaphore will be undone when this process finishes.
* \arg HYPORT_SHSEM_MODE_NOWAIT The caller will not be suspended if sem == 0, a -1 is returned instead.
*
* @return 0 on success, -1 on failure.
*/
IDATA VMCALL
hyshsem_wait (struct HyPortLibrary * portLibrary,
struct hyshsem_handle * handle, UDATA semset, UDATA flag)
{
struct sembuf buffer;
IDATA rc;
Trc_PRT_shsem_hyshsem_wait_Entry (handle, semset, flag);
if (handle == NULL)
{
Trc_PRT_shsem_hyshsem_wait_Exit1 ();
return HYPORT_ERROR_SHSEM_HANDLE_INVALID;
}
if (semset < 0 || semset >= handle->nsems)
{
Trc_PRT_shsem_hyshsem_wait_Exit2 ();
return HYPORT_ERROR_SHSEM_SEMSET_INVALID;
}
buffer.sem_num = semset;
buffer.sem_op = -1; /* wait */
if (flag & HYPORT_SHSEM_MODE_UNDO)
{
buffer.sem_flg = SEM_UNDO;
}
else
{
buffer.sem_flg = 0;
}
if (flag & HYPORT_SHSEM_MODE_NOWAIT)
{
buffer.sem_flg = buffer.sem_flg | IPC_NOWAIT;
}
rc = semop (handle->semid, &buffer, 1);
if (-1 == rc)
{
Trc_PRT_shsem_hyshsem_wait_Exit3 (rc, errno);
}
else
{
Trc_PRT_shsem_hyshsem_wait_Exit (rc);
}
return rc;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hyshsem_getVal
/**
* reading the value of the semaphore in the set. This function
* uses no synchronisation prmitives
*
* @pre caller has to deal with synchronisation issue.
*
* @param[in] portLibrary The port library.
* @param[in] handle Semaphore set handle.
* @param[in] semset The number of semaphore in the semaphore set that you want to post.
*
* @return -1 on failure, the value of the semaphore on success
*
* @warning: The user will need to make sure locking is done correctly when
* accessing semaphore values. This is because getValue simply reads the semaphore
* value without stopping the access to the semaphore. Therefore the value of the semaphore
* can change before the function returns.
*/
IDATA VMCALL
hyshsem_getVal (struct HyPortLibrary * portLibrary,
struct hyshsem_handle * handle, UDATA semset)
{
IDATA rc;
Trc_PRT_shsem_hyshsem_getVal_Entry (handle, semset);
if (handle == NULL)
{
Trc_PRT_shsem_hyshsem_getVal_Exit1 ();
return HYPORT_ERROR_SHSEM_HANDLE_INVALID;
}
if (semset < 0 || semset >= handle->nsems)
{
Trc_PRT_shsem_hyshsem_getVal_Exit2 ();
return HYPORT_ERROR_SHSEM_SEMSET_INVALID;
}
rc = semctl (handle->semid, semset, GETVAL);
if (-1 == rc)
{
Trc_PRT_shsem_hyshsem_getVal_Exit3 (rc, errno);
}
else
{
Trc_PRT_shsem_hyshsem_getVal_Exit (rc);
}
return rc;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hyshsem_setVal
/**
*
* setting the value of the semaphore specified in semset. This function
* uses no synchronisation prmitives
*
* @pre Caller has to deal with synchronisation issue.
*
* @param[in] portLibrary The port Library.
* @param[in] handle Semaphore set handle.
* @param[in] semset The no of semaphore in the semaphore set that you want to post.
* @param[in] value The value that you want to set the semaphore to
*
* @warning The user will need to make sure locking is done correctly when
* accessing semaphore values. This is because setValue simply set the semaphore
* value without stopping the access to the semaphore. Therefore the value of the semaphore
* can change before the function returns.
*
* @return 0 on success, -1 on failure.
*/
IDATA VMCALL
hyshsem_setVal (struct HyPortLibrary * portLibrary,
struct hyshsem_handle * handle, UDATA semset, IDATA value)
{
union semun sem_union;
IDATA rc;
Trc_PRT_shsem_hyshsem_setVal_Entry (handle, semset, value);
if (handle == NULL)
{
Trc_PRT_shsem_hyshsem_setVal_Exit1 ();
return HYPORT_ERROR_SHSEM_HANDLE_INVALID;
}
if (semset < 0 || semset >= handle->nsems)
{
Trc_PRT_shsem_hyshsem_setVal_Exit2 ();
return HYPORT_ERROR_SHSEM_SEMSET_INVALID;
}
sem_union.val = value;
rc = semctl (handle->semid, semset, SETVAL, sem_union);
if (-1 == rc)
{
Trc_PRT_shsem_hyshsem_setVal_Exit3 (rc, errno);
}
else
{
Trc_PRT_shsem_hyshsem_setVal_Exit (rc);
}
return rc;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hyshsem_close
/**
* Release the resources allocated for the semaphore handles.
*
* @param[in] portLibrary The port library.
* @param[in] handle Semaphore set handle.
*
* @note The actual semaphore is not destroyed. Once the close operation has been performed
* on the semaphore handle, it is no longer valid and user needs to reissue @ref hyshsem_open call.
*/
void VMCALL
hyshsem_close (struct HyPortLibrary *portLibrary,
struct hyshsem_handle **handle)
{
Trc_PRT_shsem_hyshsem_close_Entry (*handle);
/* On Unix you don't need to close the semaphore handles */
if (NULL == *handle)
{
return;
}
portLibrary->mem_free_memory (portLibrary, (*handle)->baseFile);
portLibrary->mem_free_memory (portLibrary, *handle);
*handle = NULL;
Trc_PRT_shsem_hyshsem_close_Exit ();
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hyshsem_destroy
/**
* Destroy the semaphore and release the resources allocated for the semaphore handles.
*
* @param[in] portLibrary The port library.
* @param[in] handle Semaphore set handle.
*
* @return 0 on success, -1 on failure.
* @note Due to operating system restriction we may not be able to destroy the semaphore
*/
IDATA VMCALL
hyshsem_destroy (struct HyPortLibrary * portLibrary,
struct hyshsem_handle ** handle)
{
/*pre: user has not closed the handle, and assume user has perm to remove */
IDATA rc, rcunlink;
Trc_PRT_shsem_hyshsem_destroy_Entry (*handle);
if (*handle == NULL)
{
return SUCCESS;
}
if (semctl ((*handle)->semid, 0, IPC_RMID, 0))
{
/* EINVAL is okay - we just had a reboot so the semaphore id is no good */
if (errno != EINVAL)
{
rc = -1;
}
}
else
{
rc = 0;
}
rcunlink = portLibrary->file_unlink (portLibrary, (*handle)->baseFile);
Trc_PRT_shsem_hyshsem_destroy_Debug1 ((*handle)->baseFile, rcunlink, errno);
hyshsem_close (portLibrary, handle);
if (rc == 0)
{
Trc_PRT_shsem_hyshsem_destroy_Exit ();
}
else
{
Trc_PRT_shsem_hyshsem_destroy_Exit1 ();
}
return rc;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hyshsem_startup
/**
* PortLibrary startup.
*
* This function is called during startup of the portLibrary. Any resources that are required for
* the file operations may be created here. All resources created here should be destroyed
* in @ref hyshsem_shutdown.
*
* @param[in] portLibrary The port library.
*
* @return 0 on success, negative error code on failure. Error code values returned are
* \arg HYPORT_ERROR_STARTUP_SHSEM
*
* @note Most implementations will simply return success.
*/
I_32 VMCALL
hyshsem_startup (struct HyPortLibrary * portLibrary)
{
return 0;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hyshsem_shutdown
/**
* PortLibrary shutdown.
*
* This function is called during shutdown of the portLibrary. Any resources that were created by @ref hyshsem_startup
* should be destroyed here.
*
* @param[in] portLibrary The port library.
*
* @note Most implementations will be empty.
*/
void VMCALL
hyshsem_shutdown (struct HyPortLibrary *portLibrary)
{
/* Don't need to do anything for now, but maybe we will need to clean up
* some directories, etc over here.
*/
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION createbaseFile
static IDATA
createbaseFile (struct HyPortLibrary *portLibrary, char *filename)
{
IDATA fd;
I_32 flags = HyOpenCreate | HyOpenWrite | HyOpenCreateNew;
fd =
portLibrary->file_open (portLibrary, filename, flags, HYSH_BASEFILEPERM);
if (fd == -1)
{
I_32 errorno = portLibrary->error_last_error_number (portLibrary);
if (HYPORT_ERROR_FILE_EXIST == errorno)
{
return errorno;
}
return CREATE_ERROR;
}
portLibrary->file_close (portLibrary, fd);
return SUCCESS;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION writebaseFile
static IDATA
writebaseFile (struct HyPortLibrary *portLibrary, char *filename, int proj_id,
key_t key, int semid, int setSize)
{
I_32 fd, rc, flags, perm;
hyshsem_baseFileFormat info;
flags = HyOpenWrite | HyOpenTruncate;
perm = HYSH_BASEFILEPERM;
fd = portLibrary->file_open (portLibrary, filename, flags, perm);
if (-1 == fd)
{
return OPEN_ERROR;
}
info.version = HYSH_VERSION;
info.modlevel = HYSH_MODLEVEL;
info.proj_id = proj_id;
info.ftok_key = key;
info.semid = semid;
info.creator_pid = portLibrary->sysinfo_get_pid (portLibrary);
info.semsetSize = setSize;
rc =
portLibrary->file_write (portLibrary, fd, &info,
sizeof (hyshsem_baseFileFormat));
if (rc < 0)
{
rc = WRITE_ERROR;
}
else
{
rc = SUCCESS;
}
portLibrary->file_close (portLibrary, fd);
return rc;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION readbaseFile
static IDATA
readbaseFile (struct HyPortLibrary *portLibrary, char *filename,
hyshsem_baseFileFormat ** basefileInfo)
{
I_32 fd, rc;
hyshsem_baseFileFormat *info;
fd = portLibrary->file_open (portLibrary, filename, HyOpenRead, 0);
if (-1 == fd)
{
return OPEN_ERROR;
}
info =
portLibrary->mem_allocate_memory (portLibrary,
sizeof (hyshsem_baseFileFormat));
if (info == NULL)
{
/* malloc failure! */
return MALLOC_ERROR;
}
rc =
portLibrary->file_read (portLibrary, fd, info,
sizeof (hyshsem_baseFileFormat));
if (rc == 0)
{
rc = HYSH_NO_DATA;
}
else if (rc < 0)
{
rc = READ_ERROR;
}
else if (rc < sizeof (struct hyshsem_baseFileFormat))
{
rc = HYSH_BAD_DATA;
}
else
{
rc = SUCCESS;
}
portLibrary->file_close (portLibrary, fd);
if (rc != SUCCESS)
{
portLibrary->mem_free_memory (portLibrary, info);
*basefileInfo = NULL;
}
else
{
*basefileInfo = info;
}
return rc;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION createsemHandle
static hyshsem_handle *
createsemHandle (struct HyPortLibrary *portLibrary, int semid, int nsems,
char *baseFile)
{
hyshsem_handle *result;
IDATA baseFileLength = strlen (baseFile) + 1;
result =
portLibrary->mem_allocate_memory (portLibrary, sizeof (hyshsem_handle));
if (result == NULL)
{
return NULL; /* malloc error! */
}
result->semid = semid;
result->nsems = nsems;
result->baseFile =
portLibrary->mem_allocate_memory (portLibrary, baseFileLength);
if (result->baseFile == NULL)
{
portLibrary->mem_free_memory (portLibrary, result);
return NULL;
}
portLibrary->str_printf (portLibrary, result->baseFile, baseFileLength,
"%s", baseFile);
return result;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION setMarker
static I_32
setMarker (hyshsem_handle * handle, int semsetsize)
{
union semun sem_union;
if (NULL == handle)
{
return HYPORT_ERROR_SHSEM_HANDLE_INVALID;
}
sem_union.val = SEMMARKER;
return semctl (handle->semid, semsetsize, SETVAL, sem_union);
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION checkMarker
static IDATA
checkMarker (hyshsem_handle * handle, int semsetsize)
{
IDATA rc;
if (handle == NULL)
{
return HYPORT_ERROR_SHSEM_HANDLE_INVALID;
}
rc = semctl (handle->semid, semsetsize, GETVAL);
if (rc == -1)
{
/* can't getval, so return failed */
return 0;
}
return rc == SEMMARKER;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION createSemaphore
static IDATA
createSemaphore (struct HyPortLibrary *portLibrary, char *baseFile,
I_32 setSize, hyshsem_handle ** handle)
{
IDATA rc;
int projid = 1;
key_t fkey;
int semid;
int semflags =
portLibrary->portGlobals->control.
shmem_group_perm ? HYSHSEM_SEMFLAGS_GROUP : HYSHSEM_SEMFLAGS;
/* base file not exist, so create it now */
rc = createbaseFile (portLibrary, baseFile);
/*
* TODO: Here we are rely on port layer not to mess around with errno
* we need a proper mechanism to return error code from port layer
*/
if (HYPORT_ERROR_FILE_EXIST == rc)
{
/* creation race condition - need to go back to stat */
return RETRY;
}
else if (rc == CREATE_ERROR)
{
return FAILED;
}
/*successfully created base file, now create semaphores */
while (projid < HYSH_MAX_PROJ_ID)
{
/* first ftok to get key */
fkey = ftok (baseFile, projid);
if (fkey == -1)
{
if (errno == ENOENT || errno == ENOTDIR)
{
/*
* race condition: another JVM tries to clean up
* while we trying to connect to it
* just return and ask caller to retry
*/
return RETRY;
}
return FAILED;
}
#if defined(HYSHSEM_DEBUG)
portLibrary->tty_printf (portLibrary,
"creating semaphore, setSize = %d\n",
setSize + 1);
#endif
/*
* Notice that we create with setSize+1 - we create an extra semaphore
* so that we can put a "Marker" in there to say this is one of us
*/
semid = semget (fkey, setSize + 1, semflags);
if (semid == -1)
{
if (errno == EEXIST)
{
/* EEXIST means that there is a semaphore key that's already being used.
* It could means that someone has delete the semaphore control file
* and as a result we couldn't reopen the semaphore
* We should just bumped the projid, which will give us a different
* key and we can try to create again.
*/
projid++;
continue;
}
portLibrary->error_set_last_error (portLibrary, errno,
findError (errno, __errno2 ()));
return FAILED;
}
/* if we get here it means that we have success with getting a semaphore! */
break;
}
if (semid == -1)
{
/*
* If we get here it means that we have tried to ftok for a while and still can't get a unique id
* tell user and return
*/
return FAILED;
}
*handle = createsemHandle (portLibrary, semid, setSize, baseFile);
if (*handle == NULL)
{
return FAILED;
}
/* set the last value with our marker */
rc = setMarker (*handle, setSize);
rc = writebaseFile (portLibrary, baseFile, projid, fkey, semid, setSize);
if (rc != SUCCESS)
{
/*failed to write base file - fatal! */
return FAILED;
}
/* set the timestamp */
(*handle)->timestamp = portLibrary->file_lastmod (portLibrary, baseFile);
return SEMAPHORE_CREATED;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION openSemaphore
static IDATA
openSemaphore (struct HyPortLibrary *portLibrary, char *baseFile,
I_64 timestamp, hyshsem_handle ** handle)
{
/* base file exist - process the file and get sem info */
hyshsem_baseFileFormat *info;
I_8 retrycount = RETRY_COUNT;
key_t fkey;
I_32 rc;
while (retrycount > 0)
{
rc = readbaseFile (portLibrary, baseFile, &info);
switch (rc)
{
case OPEN_ERROR:
return FAILED;
case READ_ERROR:
return RETRY;
case HYSH_BAD_DATA:
/* basefile info bad! */
return FAILED;
case HYSH_NO_DATA:
/* retry? if file empty */
usleep (SLEEP_TIME);
retrycount--;
break;
default:
/*basefile info OK, stop retrying */
retrycount = 0;
break;
}
} /* end while */
if (info == NULL)
{
/*retry already but still can't get data */
if (portLibrary->file_unlink (portLibrary, baseFile) != 0)
{
return FAILED;
}
return RETRY;
}
/* check that the modlevel and version is okay */
if (info->version != HYSH_VERSION || info->modlevel != HYSH_MODLEVEL)
{
return FAILED;
}
*handle =
createsemHandle (portLibrary, info->semid, info->semsetSize, baseFile);
(*handle)->timestamp = timestamp;
/* need to see whether the semid is still valid */
if (!checkMarker (*handle, info->semsetSize))
{
/* we had a reboot, and as a result semaphore ID is not valid */
/* Just report to the user - we should not try to recover from here */
rc = HYPORT_INFO_SHSEM_SEMID_DIFF;
}
else
{
rc = SEMAPHORE_OPENED;
}
portLibrary->mem_free_memory (portLibrary, info);
return rc;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION findError
/**
* @internal
* Determines the proper portable error code to return given a native error code
*
* @param[in] errorCode The error code reported by the OS
*
* @return the (negative) portable error code
*/
static I_32
findError (I_32 errorCode, I_32 errorCode2)
{
switch (errorCode)
{
case EPERM:
case EACCES:
return HYPORT_ERROR_SHSEM_NOPERMISSION;
case EEXIST:
return HYPORT_ERROR_SHSEM_ALREADY_EXIST;
case ENOMEM:
case ENOSPC:
case EMFILE:
return HYPORT_ERROR_SHSEM_NOSPACE;
case ENOENT:
case EINVAL:
default:
return HYPORT_ERROR_SHSEM_OPFAILED;
}
}
#undef CDEV_CURRENT_FUNCTION