mirror of
https://github.com/MariaDB/server.git
synced 2025-01-18 13:02:28 +01:00
192bf819eb
BitKeeper/etc/ignore: auto-union VC++Files/comp_err/comp_err.dsp: Auto merged VC++Files/my_print_defaults/my_print_defaults.dsp: Auto merged VC++Files/myisampack/myisampack.dsp: Auto merged acinclude.m4: Auto merged innobase/buf/buf0buf.c: Auto merged innobase/com/com0shm.c: Auto merged innobase/data/data0data.c: Auto merged innobase/ha/ha0ha.c: Auto merged innobase/include/buf0buf.ic: Auto merged innobase/include/dict0dict.h: Auto merged innobase/include/ibuf0ibuf.h: Auto merged innobase/include/lock0lock.h: Auto merged innobase/include/mtr0log.h: Auto merged innobase/include/mtr0mtr.h: Auto merged innobase/include/os0proc.h: Auto merged innobase/include/os0thread.h: Auto merged innobase/include/srv0srv.h: Auto merged innobase/include/sync0sync.h: Auto merged innobase/lock/lock0lock.c: Auto merged innobase/log/log0recv.c: Auto merged innobase/mem/mem0dbg.c: Auto merged innobase/mtr/mtr0mtr.c: Auto merged innobase/os/os0proc.c: Auto merged innobase/page/page0page.c: Auto merged innobase/que/que0que.c: Auto merged innobase/rem/rem0cmp.c: Auto merged innobase/row/row0ins.c: Auto merged innobase/row/row0mysql.c: Auto merged innobase/srv/srv0start.c: Auto merged innobase/sync/sync0sync.c: Auto merged innobase/trx/trx0rec.c: Auto merged innobase/trx/trx0trx.c: Auto merged innobase/ut/ut0mem.c: Auto merged innobase/ut/ut0ut.c: Auto merged libmysql/libmysql.c: Auto merged scripts/mysql_config.sh: Auto merged sql/net_serv.cc: Auto merged sql/sql_delete.cc: Auto merged sql/sql_yacc.yy: Auto merged
1130 lines
24 KiB
C
1130 lines
24 KiB
C
/******************************************************
|
|
The communication through shared memory
|
|
|
|
(c) 1995 Innobase Oy
|
|
|
|
Created 9/25/1995 Heikki Tuuri
|
|
*******************************************************/
|
|
|
|
#include "com0shm.h"
|
|
#ifdef UNIV_NONINL
|
|
#include "com0shm.ic"
|
|
#endif
|
|
|
|
#include "mem0mem.h"
|
|
#include "ut0mem.h"
|
|
#include "com0com.h"
|
|
#include "os0shm.h"
|
|
#include "sync0sync.h"
|
|
#include "sync0ipm.h"
|
|
#include "hash0hash.h"
|
|
|
|
/*
|
|
IMPLEMENTATION OF COMMUNICATION PRIMITIVES
|
|
==========================================
|
|
|
|
When bind is called for an endpoint, a shared memory area of
|
|
a size specified by com_shm_set_option is created with the
|
|
name of the address given concatenated to "_IBSHM".
|
|
Also a mutex is created for controlling the access to the
|
|
shared memory area. The name of the mutex is address + "_IBSHM_MTX".
|
|
An event with name address + "_IBSHM_EV_NE" is created. This event
|
|
is in signaled state when the shared memory area is not empty, i.e.,
|
|
there is a datagram to read. An event address + "_IBSHM_EV_EM"
|
|
is signaled, when the area is empty, i.e., a datagram can be
|
|
written to it.
|
|
|
|
The shared memory area consists of an info struct
|
|
at the beginning, containing fields telling:
|
|
if the area is valid, i.e., is anybody going to
|
|
read it, whether it currently contains a datagram, the
|
|
length of the address from which the datagram was received,
|
|
the length of the datagram, and the maximum allowed length of
|
|
a datagram.
|
|
After the info struct, there is a string of bytes
|
|
containing the sender address and the data
|
|
of the datagram.
|
|
*/
|
|
|
|
/* The following is set TRUE when the first endpoint is created. */
|
|
|
|
ibool com_shm_initialized = FALSE;
|
|
|
|
/* When a datagram is sent, the shared memory area
|
|
corresponding to the destination address is mapped
|
|
to the address space of this (sender) process.
|
|
We preserve it and keep the relevant info in the
|
|
following list. We can save a lot of CPU time
|
|
if the destination can be found on the list. The list is
|
|
protected by the mutex below. */
|
|
|
|
mutex_t com_shm_destination_mutex;
|
|
hash_table_t* com_shm_destination_cache;
|
|
UT_LIST_BASE_NODE_T(com_shm_endpoint_t)
|
|
com_shm_destination_list;
|
|
|
|
/* The number of successfully bound endpoints in this process. When this
|
|
number drops to 0, the destination cache is freed. This variable is protected
|
|
by com_shm_destination_mutex above. */
|
|
|
|
ulint com_shm_bind_count = 0;
|
|
|
|
/* The performance of communication in NT depends on how
|
|
many times a system call is made (excluding os_thread_yield,
|
|
as that is the fastest way to switch thread).
|
|
The following variable counts such events. */
|
|
|
|
ulint com_shm_system_call_count = 0;
|
|
|
|
/* The info struct at the beginning of a shared memory area */
|
|
|
|
typedef struct com_shm_info_struct com_shm_info_t;
|
|
|
|
/* An area of shared memory consists of an info struct followed
|
|
by a string of bytes. */
|
|
|
|
typedef com_shm_info_t com_shm_t;
|
|
|
|
struct com_shm_endpoint_struct{
|
|
ibool owns_shm; /* This is true if the shared memory
|
|
area is owned by this endpoint structure
|
|
(it may also be opened for this endpoint,
|
|
not created, in which case does not own it) */
|
|
char* addr; /* pointer to address the endpoint is bound
|
|
to, NULL if not bound */
|
|
ulint addr_len; /* address length */
|
|
ulint size; /* maximum allowed datagram size, initialized
|
|
to 0 at creation */
|
|
os_shm_t shm; /* operating system handle of the shared
|
|
memory area */
|
|
com_shm_t* map; /* pointer to the start address of the shared
|
|
memory area */
|
|
os_event_t not_empty; /* this is in the signaled state if
|
|
the area currently may contain a datagram;
|
|
NOTE: automatic event */
|
|
os_event_t empty; /* this is in the signaled state if the area
|
|
currently may be empty; NOTE: automatic
|
|
event */
|
|
ip_mutex_hdl_t* ip_mutex; /* handle to the interprocess mutex
|
|
protecting the shared memory */
|
|
UT_LIST_NODE_T(com_shm_endpoint_t) list; /* If the endpoint struct
|
|
is inserted into a list, this contains
|
|
pointers to next and prev */
|
|
com_shm_endpoint_t* addr_hash;
|
|
/* hash table link */
|
|
};
|
|
|
|
struct com_shm_info_struct{
|
|
ulint valid; /* This is COM_SHM_VALID if the creator
|
|
of the shared memory area has it still
|
|
mapped to its address space. Otherwise,
|
|
we may conclude that the datagram cannot
|
|
be delivered. */
|
|
ibool not_empty; /* TRUE if the area currently contains
|
|
a datagram */
|
|
ulint empty_waiters; /* Count of (writer) threads which are
|
|
waiting for the empty-event */
|
|
ulint max_len;/* maximum allowed length for a datagram */
|
|
ulint addr_len;/* address length for the sender address */
|
|
ulint data_len;/* datagram length */
|
|
ip_mutex_t ip_mutex;/* fast interprocess mutex protecting
|
|
the shared memory area */
|
|
};
|
|
|
|
#define COM_SHM_VALID 76640
|
|
|
|
/*************************************************************************
|
|
Accessor functions for a shared memory endpoint */
|
|
|
|
UNIV_INLINE
|
|
ibool
|
|
com_shm_endpoint_get_owns_shm(
|
|
/*==========================*/
|
|
com_shm_endpoint_t* ep)
|
|
{
|
|
ut_ad(ep);
|
|
return(ep->owns_shm);
|
|
}
|
|
|
|
UNIV_INLINE
|
|
void
|
|
com_shm_endpoint_set_owns_shm(
|
|
/*==========================*/
|
|
com_shm_endpoint_t* ep,
|
|
ibool flag)
|
|
{
|
|
ut_ad(ep);
|
|
|
|
ep->owns_shm = flag;
|
|
}
|
|
|
|
UNIV_INLINE
|
|
char*
|
|
com_shm_endpoint_get_addr(
|
|
/*======================*/
|
|
com_shm_endpoint_t* ep)
|
|
{
|
|
ut_ad(ep);
|
|
return(ep->addr);
|
|
}
|
|
|
|
UNIV_INLINE
|
|
void
|
|
com_shm_endpoint_set_addr(
|
|
/*======================*/
|
|
com_shm_endpoint_t* ep,
|
|
char* addr)
|
|
{
|
|
ut_ad(ep);
|
|
|
|
ep->addr = addr;
|
|
}
|
|
|
|
UNIV_INLINE
|
|
ulint
|
|
com_shm_endpoint_get_addr_len(
|
|
/*==========================*/
|
|
com_shm_endpoint_t* ep)
|
|
{
|
|
return(ep->addr_len);
|
|
}
|
|
|
|
UNIV_INLINE
|
|
void
|
|
com_shm_endpoint_set_addr_len(
|
|
/*==========================*/
|
|
com_shm_endpoint_t* ep,
|
|
ulint len)
|
|
{
|
|
ut_ad(ep);
|
|
ut_ad(len > 0);
|
|
|
|
ep->addr_len = len;
|
|
}
|
|
|
|
ulint
|
|
com_shm_endpoint_get_size(
|
|
/*======================*/
|
|
com_shm_endpoint_t* ep)
|
|
{
|
|
return(ep->size);
|
|
}
|
|
|
|
UNIV_INLINE
|
|
void
|
|
com_shm_endpoint_set_size(
|
|
/*======================*/
|
|
com_shm_endpoint_t* ep,
|
|
ulint size)
|
|
{
|
|
ut_ad(ep);
|
|
|
|
ep->size = size;
|
|
}
|
|
|
|
UNIV_INLINE
|
|
os_shm_t
|
|
com_shm_endpoint_get_shm(
|
|
/*=====================*/
|
|
com_shm_endpoint_t* ep)
|
|
{
|
|
return(ep->shm);
|
|
}
|
|
|
|
UNIV_INLINE
|
|
void
|
|
com_shm_endpoint_set_shm(
|
|
/*=====================*/
|
|
com_shm_endpoint_t* ep,
|
|
os_shm_t shm)
|
|
{
|
|
ut_ad(ep);
|
|
ut_ad(shm);
|
|
|
|
ep->shm = shm;
|
|
}
|
|
|
|
UNIV_INLINE
|
|
com_shm_t*
|
|
com_shm_endpoint_get_map(
|
|
/*=====================*/
|
|
com_shm_endpoint_t* ep)
|
|
{
|
|
return(ep->map);
|
|
}
|
|
|
|
UNIV_INLINE
|
|
void
|
|
com_shm_endpoint_set_map(
|
|
/*=====================*/
|
|
com_shm_endpoint_t* ep,
|
|
com_shm_t* map)
|
|
{
|
|
ut_ad(ep);
|
|
ut_ad(map);
|
|
|
|
ep->map = map;
|
|
}
|
|
|
|
UNIV_INLINE
|
|
os_event_t
|
|
com_shm_endpoint_get_empty(
|
|
/*=======================*/
|
|
com_shm_endpoint_t* ep)
|
|
{
|
|
return(ep->empty);
|
|
}
|
|
|
|
UNIV_INLINE
|
|
void
|
|
com_shm_endpoint_set_empty(
|
|
/*=======================*/
|
|
com_shm_endpoint_t* ep,
|
|
os_event_t event)
|
|
{
|
|
ut_ad(ep);
|
|
ut_ad(event);
|
|
|
|
ep->empty = event;
|
|
}
|
|
|
|
UNIV_INLINE
|
|
os_event_t
|
|
com_shm_endpoint_get_not_empty(
|
|
/*===========================*/
|
|
com_shm_endpoint_t* ep)
|
|
{
|
|
return(ep->not_empty);
|
|
}
|
|
|
|
UNIV_INLINE
|
|
void
|
|
com_shm_endpoint_set_not_empty(
|
|
/*===========================*/
|
|
com_shm_endpoint_t* ep,
|
|
os_event_t event)
|
|
{
|
|
ut_ad(ep);
|
|
ut_ad(event);
|
|
|
|
ep->not_empty = event;
|
|
}
|
|
|
|
/************************************************************************
|
|
Accessor functions for the shared memory area info struct. */
|
|
UNIV_INLINE
|
|
ulint
|
|
com_shm_get_valid(
|
|
/*==============*/
|
|
com_shm_info_t* info)
|
|
{
|
|
return(info->valid);
|
|
}
|
|
|
|
UNIV_INLINE
|
|
void
|
|
com_shm_set_valid(
|
|
/*==============*/
|
|
com_shm_info_t* info,
|
|
ulint flag)
|
|
{
|
|
ut_ad(info);
|
|
|
|
info->valid = flag;
|
|
}
|
|
|
|
UNIV_INLINE
|
|
ibool
|
|
com_shm_get_not_empty(
|
|
/*==================*/
|
|
com_shm_info_t* info)
|
|
{
|
|
return(info->not_empty);
|
|
}
|
|
|
|
UNIV_INLINE
|
|
void
|
|
com_shm_set_not_empty(
|
|
/*==================*/
|
|
com_shm_info_t* info,
|
|
ibool flag)
|
|
{
|
|
ut_ad(info);
|
|
|
|
info->not_empty = flag;
|
|
}
|
|
|
|
UNIV_INLINE
|
|
ulint
|
|
com_shm_get_empty_waiters(
|
|
/*======================*/
|
|
com_shm_info_t* info)
|
|
{
|
|
ut_ad(info->empty_waiters < 1000);
|
|
|
|
return(info->empty_waiters);
|
|
}
|
|
|
|
UNIV_INLINE
|
|
void
|
|
com_shm_set_empty_waiters(
|
|
/*======================*/
|
|
com_shm_info_t* info,
|
|
ulint count)
|
|
{
|
|
ut_ad(info);
|
|
ut_ad(count < 1000);
|
|
|
|
info->empty_waiters = count;
|
|
}
|
|
|
|
UNIV_INLINE
|
|
ulint
|
|
com_shm_get_max_len(
|
|
/*================*/
|
|
com_shm_info_t* info)
|
|
{
|
|
return(info->max_len);
|
|
}
|
|
|
|
UNIV_INLINE
|
|
void
|
|
com_shm_set_max_len(
|
|
/*================*/
|
|
com_shm_info_t* info,
|
|
ulint len)
|
|
{
|
|
ut_ad(info);
|
|
ut_ad(len > 0);
|
|
|
|
info->max_len = len;
|
|
}
|
|
|
|
UNIV_INLINE
|
|
ulint
|
|
com_shm_get_addr_len(
|
|
/*=================*/
|
|
com_shm_info_t* info)
|
|
{
|
|
return(info->addr_len);
|
|
}
|
|
|
|
UNIV_INLINE
|
|
void
|
|
com_shm_set_addr_len(
|
|
/*=================*/
|
|
com_shm_info_t* info,
|
|
ulint len)
|
|
{
|
|
ut_ad(info);
|
|
ut_ad(len > 0);
|
|
|
|
info->addr_len = len;
|
|
}
|
|
|
|
UNIV_INLINE
|
|
ulint
|
|
com_shm_get_data_len(
|
|
/*=================*/
|
|
com_shm_info_t* info)
|
|
{
|
|
return(info->data_len);
|
|
}
|
|
|
|
UNIV_INLINE
|
|
void
|
|
com_shm_set_data_len(
|
|
/*=================*/
|
|
com_shm_info_t* info,
|
|
ulint len)
|
|
{
|
|
ut_ad(info);
|
|
ut_ad(len > 0);
|
|
|
|
info->data_len = len;
|
|
}
|
|
|
|
UNIV_INLINE
|
|
ip_mutex_t*
|
|
com_shm_get_ip_mutex(
|
|
/*=================*/
|
|
com_shm_info_t* info)
|
|
{
|
|
return(&(info->ip_mutex));
|
|
}
|
|
|
|
/*************************************************************************
|
|
Accessor functions for the address and datagram fields inside a
|
|
shared memory area. */
|
|
|
|
UNIV_INLINE
|
|
char*
|
|
com_shm_get_addr(
|
|
/*=============*/
|
|
com_shm_t* area)
|
|
{
|
|
return((char*)area + sizeof(com_shm_info_t));
|
|
}
|
|
|
|
UNIV_INLINE
|
|
byte*
|
|
com_shm_get_data(
|
|
/*=============*/
|
|
com_shm_t* area)
|
|
{
|
|
return((byte*)com_shm_get_addr(area) + com_shm_get_addr_len(area));
|
|
}
|
|
|
|
/*************************************************************************
|
|
Initializes the shared memory communication system for this
|
|
process. */
|
|
UNIV_INLINE
|
|
void
|
|
com_shm_init(void)
|
|
/*==============*/
|
|
{
|
|
mutex_create(&com_shm_destination_mutex);
|
|
|
|
mutex_set_level(&com_shm_destination_mutex, SYNC_ANY_LATCH);
|
|
|
|
com_shm_destination_cache = hash_create(1000);
|
|
|
|
UT_LIST_INIT(com_shm_destination_list);
|
|
|
|
com_shm_initialized = TRUE;
|
|
}
|
|
|
|
/*************************************************************************
|
|
Reserves the ip mutex of the shared memory area of an endpoint. */
|
|
UNIV_INLINE
|
|
void
|
|
com_shm_enter(
|
|
/*==========*/
|
|
com_shm_endpoint_t* ep)
|
|
{
|
|
ulint ret;
|
|
|
|
ret = ip_mutex_enter(ep->ip_mutex, 10000000);
|
|
|
|
if (ret != 0) {
|
|
mutex_list_print_info();
|
|
|
|
ut_error;
|
|
}
|
|
}
|
|
|
|
/*************************************************************************
|
|
Releases the ip mutex of the shared memory area of an endpoint. */
|
|
UNIV_INLINE
|
|
void
|
|
com_shm_exit(
|
|
/*=========*/
|
|
com_shm_endpoint_t* ep)
|
|
{
|
|
ip_mutex_exit(ep->ip_mutex);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Looks for the given address in the cached destination addresses. */
|
|
UNIV_INLINE
|
|
com_shm_endpoint_t*
|
|
com_shm_destination_cache_search(
|
|
/*=============================*/
|
|
/* out: cached endpoint structure if found, else NULL */
|
|
char* addr, /* in: destination address */
|
|
ulint len) /* in: address length */
|
|
{
|
|
com_shm_endpoint_t* ep;
|
|
ulint fold;
|
|
|
|
fold = ut_fold_binary((byte*)addr, len);
|
|
/*
|
|
printf("Searching dest. cache %s %lu fold %lu\n", addr, len, fold);
|
|
*/
|
|
mutex_enter(&com_shm_destination_mutex);
|
|
|
|
HASH_SEARCH(addr_hash, com_shm_destination_cache, fold, ep,
|
|
((ep->addr_len == len)
|
|
&& (0 == ut_memcmp(addr, ep->addr, len))));
|
|
|
|
mutex_exit(&com_shm_destination_mutex);
|
|
|
|
return(ep);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Inserts the given endpoint structure in the cached destination addresses. */
|
|
static
|
|
void
|
|
com_shm_destination_cache_insert(
|
|
/*=============================*/
|
|
com_shm_endpoint_t* ep) /* in: endpoint struct to insert */
|
|
{
|
|
ulint fold;
|
|
|
|
fold = ut_fold_binary((byte*)(ep->addr), ep->addr_len);
|
|
|
|
mutex_enter(&com_shm_destination_mutex);
|
|
|
|
/* Add to hash table */
|
|
HASH_INSERT(com_shm_endpoint_t,
|
|
addr_hash, com_shm_destination_cache, fold, ep);
|
|
|
|
UT_LIST_ADD_LAST(list, com_shm_destination_list, ep);
|
|
|
|
/* printf("Inserting to dest. cache %s %lu fold %lu\n", ep->addr,
|
|
ep->addr_len, fold);
|
|
*/
|
|
mutex_exit(&com_shm_destination_mutex);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Frees the endpoint structs in the destination cache if the bind count is zero.
|
|
If it is not, some send operation may just be using a cached endpoint and it
|
|
cannot be freed. */
|
|
static
|
|
void
|
|
com_shm_destination_cache_no_binds(void)
|
|
/*====================================*/
|
|
{
|
|
com_shm_endpoint_t* ep;
|
|
ulint fold;
|
|
|
|
mutex_enter(&com_shm_destination_mutex);
|
|
|
|
if (com_shm_bind_count != 0) {
|
|
mutex_exit(&com_shm_destination_mutex);
|
|
|
|
return;
|
|
}
|
|
|
|
while (UT_LIST_GET_LEN(com_shm_destination_list) != 0) {
|
|
|
|
ep = UT_LIST_GET_FIRST(com_shm_destination_list);
|
|
|
|
UT_LIST_REMOVE(list, com_shm_destination_list, ep);
|
|
|
|
fold = ut_fold_binary((byte*)ep->addr, ep->addr_len);
|
|
/*
|
|
printf("Deleting from dest. cache %s %lu fold %lu\n",
|
|
ep->addr,
|
|
ep->addr_len, fold);
|
|
*/
|
|
HASH_DELETE(com_shm_endpoint_t, addr_hash,
|
|
com_shm_destination_cache, fold, ep);
|
|
|
|
com_shm_endpoint_free(ep);
|
|
}
|
|
|
|
mutex_exit(&com_shm_destination_mutex);
|
|
}
|
|
|
|
/***********************************************************************
|
|
Unbinds an endpoint at the time of freeing. */
|
|
static
|
|
void
|
|
com_shm_unbind(
|
|
/*===========*/
|
|
com_shm_endpoint_t* ep) /* in: endpoint */
|
|
{
|
|
com_shm_t* map;
|
|
|
|
map = com_shm_endpoint_get_map(ep);
|
|
|
|
/* Mark the shared memory area invalid */
|
|
|
|
com_shm_set_valid(map, 0);
|
|
|
|
/* Decrement the count of bindings */
|
|
|
|
mutex_enter(&com_shm_destination_mutex);
|
|
|
|
com_shm_bind_count--;
|
|
|
|
mutex_exit(&com_shm_destination_mutex);
|
|
|
|
/* If there are no binds left, free the cached endpoints */
|
|
|
|
com_shm_destination_cache_no_binds();
|
|
}
|
|
|
|
/*************************************************************************
|
|
Creates a communications endpoint. */
|
|
|
|
com_shm_endpoint_t*
|
|
com_shm_endpoint_create(void)
|
|
/*=========================*/
|
|
/* out, own: communications endpoint, NULL if
|
|
did not succeed */
|
|
{
|
|
com_shm_endpoint_t* ep;
|
|
|
|
if (!com_shm_initialized) {
|
|
|
|
com_shm_init();
|
|
}
|
|
|
|
ep = mem_alloc(sizeof(com_shm_endpoint_t));
|
|
|
|
com_shm_endpoint_set_owns_shm(ep, FALSE);
|
|
com_shm_endpoint_set_addr(ep, NULL);
|
|
com_shm_endpoint_set_size(ep, 0);
|
|
|
|
return(ep);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Frees a communications endpoint. */
|
|
|
|
ulint
|
|
com_shm_endpoint_free(
|
|
/*==================*/
|
|
/* out: O if succeed, else error number */
|
|
com_shm_endpoint_t* ep) /* in, own: communications endpoint */
|
|
{
|
|
com_shm_t* map;
|
|
|
|
ut_ad(ep);
|
|
|
|
if (com_shm_endpoint_get_addr(ep) != NULL) {
|
|
|
|
map = com_shm_endpoint_get_map(ep);
|
|
|
|
if (com_shm_endpoint_get_owns_shm(ep)) {
|
|
|
|
com_shm_unbind(ep);
|
|
}
|
|
|
|
/* We do not destroy the data structures in the shared memory
|
|
area, because we cannot be sure that there is currently no
|
|
process accessing it. Therefore we just close the ip_mutex
|
|
residing in the area. */
|
|
|
|
ip_mutex_close(ep->ip_mutex);
|
|
|
|
os_event_free(com_shm_endpoint_get_not_empty(ep));
|
|
os_event_free(com_shm_endpoint_get_empty(ep));
|
|
|
|
os_shm_unmap(map);
|
|
os_shm_free(com_shm_endpoint_get_shm(ep));
|
|
|
|
mem_free(com_shm_endpoint_get_addr(ep));
|
|
}
|
|
|
|
mem_free(ep);
|
|
|
|
return(0);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Sets an option, like the maximum datagram size for an endpoint.
|
|
The options may vary depending on the endpoint type. */
|
|
|
|
ulint
|
|
com_shm_endpoint_set_option(
|
|
/*========================*/
|
|
/* out: 0 if succeed, else error number */
|
|
com_shm_endpoint_t* ep, /* in: endpoint */
|
|
ulint optno, /* in: option number, only
|
|
COM_OPT_MAX_DGRAM_SIZE currently supported */
|
|
byte* optval, /* in: pointer to a buffer containing the
|
|
option value to set */
|
|
ulint optlen) /* in: option value buffer length */
|
|
{
|
|
ulint size;
|
|
|
|
UT_NOT_USED(optlen);
|
|
|
|
ut_ad(ep);
|
|
ut_a(optno == COM_OPT_MAX_DGRAM_SIZE);
|
|
ut_ad(NULL == com_shm_endpoint_get_addr(ep));
|
|
|
|
size = *((ulint*)optval);
|
|
|
|
ut_ad(size > 0);
|
|
|
|
com_shm_endpoint_set_size(ep, size);
|
|
|
|
return(0);
|
|
}
|
|
|
|
/*************************************************************************
|
|
This function is used either to create a new shared memory area or open an
|
|
existing one, but this does not do the operations necessary with the ip mutex.
|
|
They are performed in com_shm_bind or com_shm_open which call this function. */
|
|
static
|
|
ulint
|
|
com_shm_create_or_open(
|
|
/*===================*/
|
|
/* out: 0 if succeed, else error number */
|
|
com_shm_endpoint_t* ep, /* in: communications endpoint */
|
|
char* name, /* in: address name */
|
|
ulint len) /* in: address name length */
|
|
{
|
|
os_shm_t shm;
|
|
com_shm_t* map;
|
|
os_event_t event_ne;
|
|
os_event_t event_em;
|
|
char* buf;
|
|
|
|
ut_ad(ep);
|
|
ut_ad(name);
|
|
ut_ad(len > 0);
|
|
|
|
buf = mem_alloc(COM_MAX_ADDR_LEN + 20);
|
|
|
|
ut_memcpy(buf, name, len);
|
|
|
|
ut_strcpy(buf + len, (char*)"_IBSHM");
|
|
|
|
shm = os_shm_create(sizeof(com_shm_info_t) + COM_MAX_ADDR_LEN +
|
|
com_shm_endpoint_get_size(ep), buf);
|
|
if (shm == NULL) {
|
|
|
|
return(COM_ERR_NOT_SPECIFIED);
|
|
}
|
|
|
|
map = os_shm_map(shm);
|
|
|
|
if (map == NULL) {
|
|
os_shm_free(shm);
|
|
|
|
return(COM_ERR_NOT_SPECIFIED);
|
|
}
|
|
|
|
ut_strcpy(buf + len, (char*)"_IBSHM_EV_NE"),
|
|
|
|
event_ne = os_event_create(buf);
|
|
|
|
ut_ad(event_ne);
|
|
|
|
ut_strcpy(buf + len, (char*)"_IBSHM_EV_EM"),
|
|
|
|
event_em = os_event_create(buf);
|
|
|
|
ut_ad(event_em);
|
|
|
|
ut_a(0); /* event_ne and event_em should be auto events! */
|
|
|
|
com_shm_endpoint_set_shm(ep, shm);
|
|
com_shm_endpoint_set_map(ep, map);
|
|
|
|
com_shm_endpoint_set_not_empty(ep, event_ne);
|
|
com_shm_endpoint_set_empty(ep, event_em);
|
|
|
|
com_shm_endpoint_set_addr(ep, buf);
|
|
com_shm_endpoint_set_addr_len(ep, len);
|
|
|
|
return(0);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Opens a shared memory area for communication. */
|
|
static
|
|
ulint
|
|
com_shm_open(
|
|
/*=========*/
|
|
/* out: 0 if succeed, else error number */
|
|
com_shm_endpoint_t* ep, /* in: communications endpoint */
|
|
char* name, /* in: address name */
|
|
ulint len) /* in: address name length */
|
|
{
|
|
ip_mutex_hdl_t* ip_hdl;
|
|
com_shm_t* map;
|
|
ulint ret;
|
|
char buf[COM_MAX_ADDR_LEN + 20];
|
|
|
|
ret = com_shm_create_or_open(ep, name, len);
|
|
|
|
if (ret != 0) {
|
|
|
|
return(ret);
|
|
}
|
|
|
|
map = com_shm_endpoint_get_map(ep);
|
|
|
|
/* Open the interprocess mutex to protect the shared memory area */
|
|
|
|
ut_memcpy(buf, name, len);
|
|
ut_strcpy(buf + len, (char*)"_IBSHM_MTX");
|
|
|
|
ret = ip_mutex_open(com_shm_get_ip_mutex(map), buf, &ip_hdl);
|
|
|
|
if (ret != 0) {
|
|
|
|
return(COM_ERR_NOT_SPECIFIED);
|
|
}
|
|
|
|
ep->ip_mutex = ip_hdl;
|
|
|
|
return(0);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Creates a shared memory area for communication. */
|
|
|
|
ulint
|
|
com_shm_bind(
|
|
/*=========*/
|
|
/* out: 0 if succeed, else error number */
|
|
com_shm_endpoint_t* ep, /* in: communications endpoint */
|
|
char* name, /* in: address name */
|
|
ulint len) /* in: address name length */
|
|
{
|
|
com_shm_t* map;
|
|
ulint ret;
|
|
char buf[COM_MAX_ADDR_LEN + 20];
|
|
ip_mutex_hdl_t* ip_hdl;
|
|
|
|
if (com_shm_endpoint_get_size(ep) == 0) {
|
|
|
|
return(COM_ERR_MAX_DATAGRAM_SIZE_NOT_SET);
|
|
}
|
|
|
|
ret = com_shm_create_or_open(ep, name, len);
|
|
|
|
if (ret != 0) {
|
|
|
|
return(ret);
|
|
}
|
|
|
|
map = com_shm_endpoint_get_map(ep);
|
|
|
|
/* Create the interprocess mutex to protect the shared memory area */
|
|
|
|
ut_memcpy(buf, name, len);
|
|
ut_strcpy(buf + len, (char*)"_IBSHM_MTX");
|
|
|
|
ret = ip_mutex_create(com_shm_get_ip_mutex(map), buf, &ip_hdl);
|
|
|
|
if (ret != 0) {
|
|
|
|
return(COM_ERR_NOT_SPECIFIED);
|
|
}
|
|
|
|
/* This endpoint structure owns the shared memory area */
|
|
|
|
com_shm_endpoint_set_owns_shm(ep, TRUE);
|
|
ep->ip_mutex = ip_hdl;
|
|
|
|
mutex_enter(&com_shm_destination_mutex);
|
|
|
|
/* Increment the count of successful bindings */
|
|
|
|
com_shm_bind_count++;
|
|
|
|
mutex_exit(&com_shm_destination_mutex);
|
|
|
|
com_shm_set_not_empty(map, FALSE);
|
|
com_shm_set_empty_waiters(map, 0);
|
|
com_shm_set_max_len(map, com_shm_endpoint_get_size(ep));
|
|
|
|
com_shm_set_valid(map, COM_SHM_VALID);
|
|
|
|
os_event_set(com_shm_endpoint_get_empty(ep));
|
|
|
|
return(0);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Waits for a datagram to arrive at an endpoint. */
|
|
|
|
ulint
|
|
com_shm_recvfrom(
|
|
/*=============*/
|
|
/* out: 0 if succeed, else error number */
|
|
com_shm_endpoint_t* ep, /* in: communications endpoint */
|
|
byte* buf, /* out: datagram buffer; the buffer is
|
|
supplied by the caller */
|
|
ulint buf_len,/* in: datagram buffer length */
|
|
ulint* len, /* out: datagram length */
|
|
char* from, /* out: address name buffer; the buffer is
|
|
supplied by the caller */
|
|
ulint from_len,/* in: address name buffer length */
|
|
ulint* addr_len)/* out: address name length */
|
|
{
|
|
com_shm_t* map;
|
|
ulint loop_count;
|
|
|
|
map = com_shm_endpoint_get_map(ep);
|
|
|
|
loop_count = 0;
|
|
loop:
|
|
com_shm_system_call_count++;
|
|
|
|
/* NOTE: automatic event */
|
|
|
|
os_event_wait(com_shm_endpoint_get_not_empty(ep));
|
|
|
|
loop_count++;
|
|
|
|
if (loop_count > 1) {
|
|
printf("!!!!!!!!COM_SHM loop count %lu\n", (ulong) loop_count);
|
|
}
|
|
|
|
ut_ad(loop_count < 2);
|
|
|
|
com_shm_enter(ep);
|
|
|
|
if (!com_shm_get_not_empty(map)) {
|
|
/* There was no datagram, wait for the event */
|
|
|
|
com_shm_exit(ep);
|
|
|
|
goto loop;
|
|
}
|
|
|
|
if (com_shm_get_data_len(map) > buf_len) {
|
|
|
|
com_shm_exit(ep);
|
|
|
|
return(COM_ERR_DATA_BUFFER_TOO_SMALL);
|
|
}
|
|
|
|
if (com_shm_get_addr_len(map) > from_len) {
|
|
|
|
com_shm_exit(ep);
|
|
|
|
return(COM_ERR_ADDR_BUFFER_TOO_SMALL);
|
|
}
|
|
|
|
*len = com_shm_get_data_len(map);
|
|
*addr_len = com_shm_get_addr_len(map);
|
|
|
|
ut_memcpy(buf, com_shm_get_data(map), *len);
|
|
ut_memcpy(from, com_shm_get_addr(map), *addr_len);
|
|
|
|
com_shm_set_not_empty(map, FALSE);
|
|
|
|
/* If there may be writers queuing to insert the datagram, signal the
|
|
empty-event */
|
|
|
|
if (com_shm_get_empty_waiters(map) != 0) {
|
|
|
|
com_shm_system_call_count++;
|
|
|
|
os_event_set(com_shm_endpoint_get_empty(ep));
|
|
}
|
|
|
|
com_shm_exit(ep);
|
|
|
|
return(0);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Sends a datagram to the specified destination. */
|
|
|
|
ulint
|
|
com_shm_sendto(
|
|
/*===========*/
|
|
/* out: 0 if succeed, else error number */
|
|
com_shm_endpoint_t* ep, /* in: communications endpoint */
|
|
byte* buf, /* in: datagram buffer */
|
|
ulint len, /* in: datagram length */
|
|
char* to, /* in: address name buffer */
|
|
ulint tolen) /* in: address name length */
|
|
{
|
|
com_shm_endpoint_t* ep2;
|
|
com_shm_t* map;
|
|
ulint sender_len;
|
|
ulint ret;
|
|
ulint loop_count;
|
|
|
|
/* Try first to find from the cached destination addresses */
|
|
|
|
ep2 = com_shm_destination_cache_search(to, tolen);
|
|
|
|
if (ep2 == NULL) {
|
|
/* Did not find it in the cache */
|
|
ep2 = com_shm_endpoint_create();
|
|
|
|
ret = com_shm_open(ep2, to, tolen);
|
|
|
|
if (ret != 0) {
|
|
com_shm_endpoint_free(ep2);
|
|
|
|
return(ret);
|
|
}
|
|
|
|
/* Insert into the cached destination addresses */
|
|
|
|
com_shm_destination_cache_insert(ep2);
|
|
}
|
|
|
|
map = com_shm_endpoint_get_map(ep2);
|
|
|
|
if (com_shm_get_valid(map) != COM_SHM_VALID) {
|
|
|
|
com_shm_exit(ep2);
|
|
|
|
return(COM_ERR_DGRAM_NOT_DELIVERED);
|
|
}
|
|
|
|
if (com_shm_get_max_len(map) < len) {
|
|
|
|
com_shm_exit(ep2);
|
|
|
|
return(COM_ERR_DATA_TOO_LONG);
|
|
}
|
|
|
|
/* Optimistically, we first go to see if the datagram area is empty,
|
|
without waiting for the empty-event */
|
|
|
|
loop_count = 0;
|
|
loop:
|
|
loop_count++;
|
|
|
|
if (loop_count > 5) {
|
|
printf("!!!!!!COM_SHM Notempty loop count %lu\n",
|
|
(ulong) loop_count);
|
|
}
|
|
|
|
ut_ad(loop_count < 100);
|
|
|
|
com_shm_enter(ep2);
|
|
|
|
if (com_shm_get_not_empty(map)) {
|
|
|
|
/* Not empty, we cannot insert a datagram */
|
|
|
|
com_shm_set_empty_waiters(map,
|
|
1 + com_shm_get_empty_waiters(map));
|
|
com_shm_exit(ep2);
|
|
|
|
com_shm_system_call_count++;
|
|
|
|
/* Wait for the area to become empty */
|
|
/* NOTE: automatic event */
|
|
|
|
ret = os_event_wait_time(com_shm_endpoint_get_empty(ep2),
|
|
10000000);
|
|
ut_a(ret == 0);
|
|
|
|
com_shm_enter(ep2);
|
|
|
|
com_shm_set_empty_waiters(map,
|
|
com_shm_get_empty_waiters(map) - 1);
|
|
com_shm_exit(ep2);
|
|
|
|
goto loop;
|
|
}
|
|
|
|
sender_len = com_shm_endpoint_get_addr_len(ep);
|
|
|
|
com_shm_set_data_len(map, len);
|
|
com_shm_set_addr_len(map, sender_len);
|
|
|
|
ut_memcpy(com_shm_get_data(map), buf, len);
|
|
ut_memcpy(com_shm_get_addr(map), com_shm_endpoint_get_addr(ep),
|
|
sender_len);
|
|
com_shm_set_not_empty(map, TRUE);
|
|
com_shm_system_call_count++;
|
|
|
|
com_shm_exit(ep2);
|
|
|
|
/* Signal the event */
|
|
|
|
os_event_set(com_shm_endpoint_get_not_empty(ep2));
|
|
|
|
return(0);
|
|
}
|