Enable AoT and wamr-sdk, and change arguments of call wasm API (#157)

* Implement memory profiler, optimize memory usage, modify code indent

* Implement memory.grow and limit heap space base offset to 1G; modify iwasm build type to Release and 64 bit by default

* Add a new extension library: connection

* Fix bug of reading magic number and version in big endian platform

* Re-org platform APIs: move most platform APIs from iwasm to shared-lib

* Enhance wasm loader to fix some security issues

* Fix issue about illegal load of EXC_RETURN into PC on stm32 board

* Updates that let a restricted version of the interpreter run in SGX

* Enable native/app address validation and conversion for wasm app

* Remove wasm_application_exectue_* APIs from wasm_export.h which makes confused

* Refine binary size and fix several minor issues

Optimize interpreter LOAD/STORE opcodes to decrease the binary size
Fix issues when using iwasm library: _bh_log undefined, bh_memory.h not found
Remove unused _stdin/_stdout/_stderr global variables resolve in libc wrapper
Add macros of global heap size, stack size, heap size for Zephyr main.c
Clear compile warning of wasm_application.c

* Add more strict security checks for libc wrapper API's

* Use one libc wrapper copy for sgx and other platforms; remove bh_printf macro for other platform header files

* Enhance security of libc strcpy/sprintf wrapper function

* Fix issue of call native for x86_64/arm/mips, add module inst parameter for native wrapper functions

* Remove get_module_inst() and fix issue of call native

* Refine wgl lib: remove module_inst parameter from widget functions; move function index check to runtime instantiate

* Refine interpreter call native process, refine memory boudary check

* Fix issues of invokeNative function of arm/mips/general version

* Add a switch to build simple sample without gui support

* Add BUILD_TARGET setting in makefile to replace cpu compiler flags in source code

* Re-org shared lib header files, remove unused info; fix compile issues of vxworks

* Add build target general

* Remove unused files

* Update license header

* test push

* Restore file

* Sync up with internal/feature

* Sync up with internal/feature

* Rename build_wamr_app to build_wasm_app

* Fix small issues of README

* Enhance malformed wasm file checking
Fix issue of print hex int and implement utf8 string check
Fix wasi file read/write right issue
Fix minor issue of build wasm app doc

* Sync up with internal/feature

* Sync up with internal/feature: fix interpreter arm issue, fix read leb issue

* Sync up with internal/feature

* Fix bug of config.h and rename wasi config.h to ssp_config.h

* Sync up with internal/feature

* Import wamr aot

* update document

* update document

* Update document, disable WASI in 32bit

* update document

* remove files

* update document

* Update document

* update document

* update document

* update samples

* Sync up with internal repo
This commit is contained in:
wenyongh
2020-01-21 13:26:14 +08:00
committed by Wang Xin
parent 2a4528c749
commit 46b93b9d22
464 changed files with 25137 additions and 7911 deletions

View File

@ -0,0 +1,30 @@
Copyright (c) (Year), (Name of copyright holder)
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,192 @@
/*
* Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the Contiki operating system.
*/
/**
* \file
* Collection of constants specified in the CoAP standard.
* \author
* Matthias Kovatsch <kovatsch@inf.ethz.ch>
*/
/**
* \addtogroup coap
* @{
*/
#ifndef COAP_CONSTANTS_H_
#define COAP_CONSTANTS_H_
#define COAP_DEFAULT_PORT 5683
#define COAP_DEFAULT_SECURE_PORT 5684
#define COAP_DEFAULT_MAX_AGE 60
#define COAP_RESPONSE_TIMEOUT 3
#define COAP_RESPONSE_RANDOM_FACTOR 1.5
#define COAP_MAX_RETRANSMIT 4
#define COAP_HEADER_LEN 4 /* | version:0x03 type:0x0C tkl:0xF0 | code | mid:0x00FF | mid:0xFF00 | */
#define COAP_TOKEN_LEN 8 /* The maximum number of bytes for the Token */
#define COAP_ETAG_LEN 8 /* The maximum number of bytes for the ETag */
#define COAP_HEADER_VERSION_MASK 0xC0
#define COAP_HEADER_VERSION_POSITION 6
#define COAP_HEADER_TYPE_MASK 0x30
#define COAP_HEADER_TYPE_POSITION 4
#define COAP_HEADER_TOKEN_LEN_MASK 0x0F
#define COAP_HEADER_TOKEN_LEN_POSITION 0
#define COAP_HEADER_OPTION_DELTA_MASK 0xF0
#define COAP_HEADER_OPTION_SHORT_LENGTH_MASK 0x0F
/* CoAP message types */
typedef enum {
COAP_TYPE_CON, /* confirmables */
COAP_TYPE_NON, /* non-confirmables */
COAP_TYPE_ACK, /* acknowledgements */
COAP_TYPE_RST /* reset */
} coap_message_type_t;
/* CoAP request method codes */
typedef enum {
COAP_GET = 1,
COAP_POST,
COAP_PUT,
COAP_DELETE
} coap_method_t;
/* CoAP response codes */
typedef enum {
NO_ERROR = 0,
CREATED_2_01 = 65, /* CREATED */
DELETED_2_02 = 66, /* DELETED */
VALID_2_03 = 67, /* NOT_MODIFIED */
CHANGED_2_04 = 68, /* CHANGED */
CONTENT_2_05 = 69, /* OK */
CONTINUE_2_31 = 95, /* CONTINUE */
BAD_REQUEST_4_00 = 128, /* BAD_REQUEST */
UNAUTHORIZED_4_01 = 129, /* UNAUTHORIZED */
BAD_OPTION_4_02 = 130, /* BAD_OPTION */
FORBIDDEN_4_03 = 131, /* FORBIDDEN */
NOT_FOUND_4_04 = 132, /* NOT_FOUND */
METHOD_NOT_ALLOWED_4_05 = 133, /* METHOD_NOT_ALLOWED */
NOT_ACCEPTABLE_4_06 = 134, /* NOT_ACCEPTABLE */
PRECONDITION_FAILED_4_12 = 140, /* BAD_REQUEST */
REQUEST_ENTITY_TOO_LARGE_4_13 = 141, /* REQUEST_ENTITY_TOO_LARGE */
UNSUPPORTED_MEDIA_TYPE_4_15 = 143, /* UNSUPPORTED_MEDIA_TYPE */
INTERNAL_SERVER_ERROR_5_00 = 160, /* INTERNAL_SERVER_ERROR */
NOT_IMPLEMENTED_5_01 = 161, /* NOT_IMPLEMENTED */
BAD_GATEWAY_5_02 = 162, /* BAD_GATEWAY */
SERVICE_UNAVAILABLE_5_03 = 163, /* SERVICE_UNAVAILABLE */
GATEWAY_TIMEOUT_5_04 = 164, /* GATEWAY_TIMEOUT */
PROXYING_NOT_SUPPORTED_5_05 = 165, /* PROXYING_NOT_SUPPORTED */
/* Erbium errors */
MEMORY_ALLOCATION_ERROR = 192,
PACKET_SERIALIZATION_ERROR,
/* Erbium hooks */
MANUAL_RESPONSE,
PING_RESPONSE
} coap_status_t;
/* CoAP header option numbers */
typedef enum {
COAP_OPTION_IF_MATCH = 1, /* 0-8 B */
COAP_OPTION_URI_HOST = 3, /* 1-255 B */
COAP_OPTION_ETAG = 4, /* 1-8 B */
COAP_OPTION_IF_NONE_MATCH = 5, /* 0 B */
COAP_OPTION_OBSERVE = 6, /* 0-3 B */
COAP_OPTION_URI_PORT = 7, /* 0-2 B */
COAP_OPTION_LOCATION_PATH = 8, /* 0-255 B */
COAP_OPTION_URI_PATH = 11, /* 0-255 B */
COAP_OPTION_CONTENT_FORMAT = 12, /* 0-2 B */
COAP_OPTION_MAX_AGE = 14, /* 0-4 B */
COAP_OPTION_URI_QUERY = 15, /* 0-255 B */
COAP_OPTION_ACCEPT = 17, /* 0-2 B */
COAP_OPTION_LOCATION_QUERY = 20, /* 0-255 B */
COAP_OPTION_BLOCK2 = 23, /* 1-3 B */
COAP_OPTION_BLOCK1 = 27, /* 1-3 B */
COAP_OPTION_SIZE2 = 28, /* 0-4 B */
COAP_OPTION_PROXY_URI = 35, /* 1-1034 B */
COAP_OPTION_PROXY_SCHEME = 39, /* 1-255 B */
COAP_OPTION_SIZE1 = 60, /* 0-4 B */
} coap_option_t;
/* CoAP Content-Formats */
typedef enum {
TEXT_PLAIN = 0,
TEXT_XML = 1,
TEXT_CSV = 2,
TEXT_HTML = 3,
IMAGE_GIF = 21,
IMAGE_JPEG = 22,
IMAGE_PNG = 23,
IMAGE_TIFF = 24,
AUDIO_RAW = 25,
VIDEO_RAW = 26,
APPLICATION_LINK_FORMAT = 40,
APPLICATION_XML = 41,
APPLICATION_OCTET_STREAM = 42,
APPLICATION_RDF_XML = 43,
APPLICATION_SOAP_XML = 44,
APPLICATION_ATOM_XML = 45,
APPLICATION_XMPP_XML = 46,
APPLICATION_EXI = 47,
APPLICATION_FASTINFOSET = 48,
APPLICATION_SOAP_FASTINFOSET = 49,
APPLICATION_JSON = 50,
APPLICATION_X_OBIX_BINARY = 51
} coap_content_format_t;
/**
* Resource flags for allowed methods and special functionalities.
*/
typedef enum {
NO_FLAGS = 0,
/* methods to handle */
METHOD_GET = (1 << 0),
METHOD_POST = (1 << 1),
METHOD_PUT = (1 << 2),
METHOD_DELETE = (1 << 3),
/* special flags */
HAS_SUB_RESOURCES = (1 << 4),
IS_SEPARATE = (1 << 5),
IS_OBSERVABLE = (1 << 6),
IS_PERIODIC = (1 << 7)
} coap_resource_flags_t;
#endif /* COAP_CONSTANTS_H_ */
/** @} */

View File

@ -0,0 +1,20 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef COAP_EXTENSION_COAP_EXT_H_
#define COAP_EXTENSION_COAP_EXT_H_
#include "coap-constants.h"
#ifdef __cplusplus
extern "C" {
#endif
#define COAP_EVENT (COAP_DELETE + 2)
#ifdef __cplusplus
}
#endif
#endif /* COAP_EXTENSION_COAP_EXT_H_ */

View File

@ -0,0 +1,12 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
set (LIB_COAP_DIR ${CMAKE_CURRENT_LIST_DIR})
include_directories(${LIB_COAP_DIR}/er-coap)
include_directories(${LIB_COAP_DIR}/extension)
file (GLOB_RECURSE source_all ${LIB_COAP_DIR}/*.c)
set (LIB_COAP_SOURCE ${source_all})

View File

@ -0,0 +1,34 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _BH_COMMON_H
#define _BH_COMMON_H
#include "bh_assert.h"
#include "bh_platform.h"
#include "bh_list.h"
typedef void (*bh_print_function_t)(const char* message);
void bh_set_print_function(bh_print_function_t pf);
#define bh_memcpy_s(dest, dlen, src, slen) do { \
int _ret = slen == 0 ? 0 : b_memcpy_s (dest, dlen, src, slen); \
(void)_ret; \
bh_assert (_ret == 0); \
} while (0)
#define bh_strcat_s(dest, dlen, src) do { \
int _ret = b_strcat_s (dest, dlen, src); \
(void)_ret; \
bh_assert (_ret == 0); \
} while (0)
#define bh_strcpy_s(dest, dlen, src) do { \
int _ret = b_strcpy_s (dest, dlen, src); \
(void)_ret; \
bh_assert (_ret == 0); \
} while (0)
#endif

View File

@ -0,0 +1,133 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef WASM_HASHMAP_H
#define WASM_HASHMAP_H
#include "bh_platform.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Maximum initial size of hash map */
#define HASH_MAP_MAX_SIZE 65536
struct HashMap;
typedef struct HashMap HashMap;
/* Hash function: to get the hash value of key. */
typedef uint32 (*HashFunc)(const void *key);
/* Key equal function: to check whether two keys are equal. */
typedef bool (*KeyEqualFunc)(void *key1, void *key2);
/* Key destroy function: to destroy the key, auto called
when an hash element is removed. */
typedef void (*KeyDestroyFunc)(void *key);
/* Value destroy function: to destroy the value, auto called
when an hash element is removed. */
typedef void (*ValueDestroyFunc)(void *key);
/**
* Create a hash map.
*
* @param size: the initial size of the hash map
* @param use_lock whether to lock the hash map when operating on it
* @param hash_func hash function of the key, must be specified
* @param key_equal_func key equal function, check whether two keys
* are equal, must be specified
* @param key_destroy_func key destroy function, called when an hash element
* is removed if it is not NULL
* @param value_destroy_func value destroy function, called when an hash
* element is removed if it is not NULL
*
* @return the hash map created, NULL if failed
*/
HashMap*
bh_hash_map_create(uint32 size, bool use_lock,
HashFunc hash_func,
KeyEqualFunc key_equal_func,
KeyDestroyFunc key_destroy_func,
ValueDestroyFunc value_destroy_func);
/**
* Insert an element to the hash map
*
* @param map the hash map to insert element
* @key the key of the element
* @value the value of the element
*
* @return true if success, false otherwise
* Note: fail if key is NULL or duplicated key exists in the hash map,
*/
bool
bh_hash_map_insert(HashMap *map, void *key, void *value);
/**
* Find an element in the hash map
*
* @param map the hash map to find element
* @key the key of the element
*
* @return the value of the found element if success, NULL otherwise
*/
void*
bh_hash_map_find(HashMap *map, void *key);
/**
* Update an element in the hash map with new value
*
* @param map the hash map to update element
* @key the key of the element
* @value the new value of the element
* @p_old_value if not NULL, copies the old value to it
*
* @return true if success, false otherwise
* Note: the old value won't be destroyed by value destroy function,
* it will be copied to p_old_value for user to process.
*/
bool
bh_hash_map_update(HashMap *map, void *key, void *value,
void **p_old_value);
/**
* Remove an element from the hash map
*
* @param map the hash map to remove element
* @key the key of the element
* @p_old_key if not NULL, copies the old key to it
* @p_old_value if not NULL, copies the old value to it
*
* @return true if success, false otherwise
* Note: the old key and old value won't be destroyed by key destroy
* function and value destroy function, they will be copied to
* p_old_key and p_old_value for user to process.
*/
bool
bh_hash_map_remove(HashMap *map, void *key,
void **p_old_key, void **p_old_value);
/**
* Destroy the hashmap
*
* @param map the hash map to destroy
*
* @return true if success, false otherwise
* Note: the key destroy function and value destroy function will be
* called to destroy each element's key and value if they are
* not NULL.
*/
bool
bh_hash_map_destroy(HashMap *map);
#ifdef __cplusplus
}
#endif
#endif /* endof WASM_HASHMAP_H */

View File

@ -0,0 +1,109 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _BH_LIST_H
#define _BH_LIST_H
#ifdef __cplusplus
extern "C" {
#endif
#include "bh_types.h" /*For bool type*/
#include "bh_platform.h"
/* List user should embedded bh_list_link into list elem data structure
* definition. And bh_list_link data field should be the first field.
* For example, if we would like to use bh_list for our own data type A,
* A must be defined as a structure like below:
* struct A {
* bh_list_link l;
* ...
* };
*
* bh_list_link is defined as a structure (not typedef void*).
* It will make extend list into bi-direction easy.
*/
typedef struct _bh_list_link {
struct _bh_list_link *next;
} bh_list_link;
typedef struct _bh_list {
bh_list_link head;
uint32 len;
} bh_list;
/* Beihai list operation return value */
typedef enum _bh_list_status {
BH_LIST_SUCCESS = 0, BH_LIST_ERROR = -1
} bh_list_status;
/**
* Initialize a list.
*
* @param list pointer to list.
* @return <code>BH_LIST_ERROR</code> if OK;
* <code>BH_LIST_ERROR</code> if list pointer is NULL.
*/
bh_list_status bh_list_init(bh_list *list);
/**
* Insert an elem pointer into list. The list node memory is maintained by list while
* elem memory is the responsibility of list user.
*
* @param list pointer to list.
* @param elem pointer to elem that will be inserted into list.
* @return <code>BH_LIST_ERROR</code> if OK;
* <code>BH_LIST_ERROR</code> if input is invalid or no memory available.
*/
extern bh_list_status _bh_list_insert(bh_list *list, void *elem);
#ifdef _INSTRUMENT_TEST_ENABLED
extern bh_list_status bh_list_insert_instr(bh_list *list, void *elem, const char*func_name);
#define bh_list_insert(list, elem) bh_list_insert_instr(list, elem, __FUNCTION__)
#else
#define bh_list_insert _bh_list_insert
#endif
/**
* Remove an elem pointer from list. The list node memory is maintained by list while
* elem memory is the responsibility of list user.
*
* @param list pointer to list.
* @param elem pointer to elem that will be inserted into list.
* @return <code>BH_LIST_ERROR</code> if OK;
* <code>BH_LIST_ERROR</code> if element does not exist in given list.
*/
bh_list_status bh_list_remove(bh_list *list, void *elem);
/**
* Get the list length.
*
* @param list pointer to list.
* @return the length of the list.
*/
uint32 bh_list_length(bh_list *list);
/**
* Get the first elem in the list.
*
* @param list pointer to list.
* @return pointer to the first node.
*/
void* bh_list_first_elem(bh_list *list);
/**
* Get the next elem of given list input elem.
*
* @param node pointer to list node.
* @return pointer to next list node.
*/
void* bh_list_elem_next(void *node);
#ifdef __cplusplus
}
#endif
#endif /* #ifndef _BH_LIST_H */

View File

@ -0,0 +1,144 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
/**
* @file bh_log.h
* @date Tue Nov 8 18:19:10 2011
*
* @brief This log system supports wrapping multiple outputs into one
* log message. This is useful for outputting variable-length logs
* without additional memory overhead (the buffer for concatenating
* the message), e.g. exception stack trace, which cannot be printed
* by a single log calling without the help of an additional buffer.
* Avoiding additional memory buffer is useful for resource-constraint
* systems. It can minimize the impact of log system on applications
* and logs can be printed even when no enough memory is available.
* Functions with prefix "_" are private functions. Only macros that
* are not start with "_" are exposed and can be used.
*/
#ifndef _BH_LOG_H
#define _BH_LOG_H
#include <stdarg.h>
#include "bh_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* The following functions are the primitive operations of this log
* system. A normal usage of the log system is to call bh_log_printf
* or bh_log_vprintf one or multiple times and then call bh_log_commit
* to wrap (mark) the previous outputs into one log message. The
* bh_log and macros LOG_ERROR etc. can be used to output log messages
* that can be wrapped into one log calling.
*/
int _bh_log_init(void);
void _bh_log_set_verbose_level(int level);
void _bh_log_printf(const char *fmt, ...);
void _bh_log_vprintf(const char *fmt, va_list ap);
void _bh_log_commit(void);
#if WASM_ENABLE_LOG != 0
# define bh_log_init() _bh_log_init ()
# define bh_log_set_verbose_level(l) _bh_log_set_verbose_level (l)
# define bh_log_printf(...) _bh_log_printf (__VA_ARGS__)
# define bh_log_vprintf(...) _bh_log_vprintf (__VA_ARGS__)
# define bh_log_commit() _bh_log_commit ()
#else /* WASM_ENABLE_LOG != 0 */
# define bh_log_init() 0
# define bh_log_set_verbose_level(l) (void)0
# define bh_log_printf(...) (void)0
# define bh_log_vprintf(...) (void)0
# define bh_log_commit() (void)0
#endif /* WASM_ENABLE_LOG != 0 */
void _bh_log(const char *tag, const char *file, int line, const char *fmt, ...);
/* Always print fatal message */
# define LOG_FATAL(...) _bh_log ("V0.", NULL, 0, __VA_ARGS__)
#if WASM_ENABLE_LOG != 0
# define LOG_ERROR(...) _bh_log ("V1.", NULL, 0, __VA_ARGS__)
# define LOG_WARNING(...) _bh_log ("V2.", NULL, 0, __VA_ARGS__)
# define LOG_INFO_RELEASE(...) _bh_log ("V3.", NULL, 0, __VA_ARGS__)
# define LOG_INFO_APP_DEV(...) _bh_log ("V4.", NULL, 0, __VA_ARGS__)
# define LOG_VERBOSE(...) _bh_log ("V5.", NULL, 0, __VA_ARGS__)
# if BEIHAI_ENABLE_MEMORY_PROFILING != 0
# define LOG_PROFILE(...) _bh_log ("V3.", NULL, 0, __VA_ARGS__)
# else
# define LOG_PROFILE(...) (void)0
#endif
# if BEIHAI_ENABLE_QUEUE_PROFILING != 0
# define LOG_QUEUE_PROFILE(...) _bh_log ("V3.", NULL, 0, __VA_ARGS__)
# else
# define LOG_QUEUE_PROFILE(...) (void)0
#endif
# if BEIHAI_ENABLE_GC_STAT_PROFILING != 0
# define LOG_GC_STAT_PROFILE(...) _bh_log ("V3.", NULL, 0, __VA_ARGS__)
# else
# define LOG_GC_STAT_PROFILE(...) (void)0
#endif
#else /* WASM_ENABLE_LOG != 0 */
# define LOG_ERROR(...) (void)0
# define LOG_WARNING(...) (void)0
# define LOG_INFO_APP_DEV(...) (void)0
# define LOG_INFO_RELEASE(...) (void)0
# define LOG_VERBOSE(...) (void)0
# define LOG_PROFILE(...) (void)0
# define LOG_QUEUE_PROFILE(...) (void)0
# define LOG_GC_STAT_PROFILE(...) (void)0
#endif /* WASM_ENABLE_LOG != 0 */
#define LOG_PROFILE_INSTANCE_HEAP_CREATED(heap) \
LOG_PROFILE ("PROF.INSTANCE.HEAP_CREATED: HEAP=%08X", heap)
#define LOG_PROFILE_INSTANCE_THREAD_STARTED(heap) \
LOG_PROFILE ("PROF.INSTANCE.THREAD_STARTED: HEAP=%08X", heap)
#define LOG_PROFILE_HEAP_ALLOC(heap, size) \
LOG_PROFILE ("PROF.HEAP.ALLOC: HEAP=%08X SIZE=%d", heap, size)
#define LOG_PROFILE_HEAP_FREE(heap, size) \
LOG_PROFILE ("PROF.HEAP.FREE: HEAP=%08X SIZE=%d", heap, size)
#define LOG_PROFILE_HEAP_NEW(heap, size) \
LOG_PROFILE ("PROF.HEAP.NEW: HEAP=%08X SIZE=%d", heap, size)
#define LOG_PROFILE_HEAP_GC(heap, size) \
LOG_PROFILE ("PROF.HEAP.GC: HEAP=%08X SIZE=%d", heap, size)
#define LOG_PROFILE_STACK_PUSH(used) \
LOG_PROFILE ("PROF.STACK.PUSH: USED=%d", used)
#define LOG_PROFILE_STACK_POP() \
LOG_PROFILE ("PROF.STACK.POP")
/* Please add your component ahead of LOG_COM_MAX */
enum {
LOG_COM_APP_MANAGER = 0,
LOG_COM_GC,
LOG_COM_HMC,
LOG_COM_UTILS,
LOG_COM_VERIFIER_JEFF,
LOG_COM_VMCORE_JEFF,
LOG_COM_MAX
};
#if defined(BH_DEBUG)
void log_parse_coms(const char *coms);
int bh_log_dcom_is_enabled(int component);
#define LOG_DEBUG(component, ...) do { \
if (bh_log_dcom_is_enabled (component)) \
_bh_log ("V6: ", __FILE__, __LINE__, __VA_ARGS__); \
} while (0)
#else /* defined(BH_DEBUG) */
#define LOG_DEBUG(component, ...) (void)0
#endif /* defined(BH_DEBUG) */
#ifdef __cplusplus
}
#endif
#endif /* _BH_LOG_H */

View File

@ -0,0 +1,99 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _BH_MEMORY_H
#define _BH_MEMORY_H
#ifdef __cplusplus
extern "C" {
#endif
#define BH_KB (1024)
#define BH_MB ((BH_KB)*1024)
#define BH_GB ((BH_MB)*1024)
/**
* Initialize memory allocator with a pool, the bh_malloc/bh_free function
* will malloc/free memory from the pool
*
* @param mem the pool buffer
* @param bytes the size bytes of the buffer
*
* @return 0 if success, -1 otherwise
*/
int bh_memory_init_with_pool(void *mem, unsigned int bytes);
/**
* Initialize memory allocator with memory allocator, the bh_malloc/bh_free
* function will malloc/free memory with the allocator passed
*
* @param malloc_func the malloc function
* @param free_func the free function
*
* @return 0 if success, -1 otherwise
*/
int bh_memory_init_with_allocator(void *malloc_func, void *free_func);
/**
* Destroy memory
*/
void bh_memory_destroy();
/**
* Get the pool size of memory, if memory is initialized with allocator,
* return 1GB by default.
*/
unsigned bh_memory_pool_size();
#if BEIHAI_ENABLE_MEMORY_PROFILING == 0
/**
* This function allocates a memory chunk from system
*
* @param size bytes need allocate
*
* @return the pointer to memory allocated
*/
void* bh_malloc(unsigned int size);
/**
* This function frees memory chunk
*
* @param ptr the pointer to memory need free
*/
void bh_free(void *ptr);
#else
void* bh_malloc_profile(const char *file, int line, const char *func, unsigned int size);
void bh_free_profile(const char *file, int line, const char *func, void *ptr);
#define bh_malloc(size) bh_malloc_profile(__FILE__, __LINE__, __func__, size)
#define bh_free(ptr) bh_free_profile(__FILE__, __LINE__, __func__, ptr)
/**
* Print current memory profiling data
*
* @param file file name of the caller
* @param line line of the file of the caller
* @param func function name of the caller
*/
void memory_profile_print(const char *file, int line, const char *func, int alloc);
/**
* Summarize memory usage and print it out
* Can use awk to analyze the output like below:
* awk -F: '{print $2,$4,$6,$8,$9}' OFS="\t" ./out.txt | sort -n -r -k 1
*/
void memory_usage_summarize();
#endif
#ifdef __cplusplus
}
#endif
#endif /* #ifndef _BH_MEMORY_H */

View File

@ -0,0 +1,84 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _BH_QUEUE_H
#define _BH_QUEUE_H
#ifdef __cplusplus
extern "C" {
#endif
#include "bh_types.h" /*For bool type*/
#include "bh_platform.h"
struct _bh_queue_node;
typedef struct _bh_queue_node * bh_message_t;
struct bh_queue;
typedef struct bh_queue bh_queue;
typedef void (*bh_queue_handle_msg_callback)(void *message, void *arg);
#define bh_queue_malloc bh_malloc
#define bh_queue_free bh_free
#define bh_queue_mutex korp_mutex
#define bh_queue_sem korp_sem
#define bh_queue_cond korp_cond
#define bh_queue_mutex_init vm_mutex_init
#define bh_queue_mutex_destroy vm_mutex_destroy
#define bh_queue_mutex_lock vm_mutex_lock
#define bh_queue_mutex_unlock vm_mutex_unlock
#define bh_queue_sem_init vm_sem_init
#define bh_queue_sem_destroy vm_sem_destroy
#define bh_queue_sem_wait vm_sem_wait
#define bh_queue_sem_reltimedwait vm_sem_reltimedwait
#define bh_queue_sem_post vm_sem_post
#define bh_queue_cond_init vm_cond_init
#define bh_queue_cond_destroy vm_cond_destroy
#define bh_queue_cond_wait vm_cond_wait
#define bh_queue_cond_timedwait vm_cond_reltimedwait
#define bh_queue_cond_signal vm_cond_signal
#define bh_queue_cond_broadcast vm_cond_broadcast
typedef void (*bh_msg_cleaner)(void *msg);
bh_queue *
bh_queue_create();
void
bh_queue_destroy(bh_queue *queue);
char * bh_message_payload(bh_message_t message);
uint32 bh_message_payload_len(bh_message_t message);
int bh_message_type(bh_message_t message);
bh_message_t bh_new_msg(unsigned short tag, void *body, unsigned int len,
void * handler);
void bh_free_msg(bh_message_t msg);
bool bh_post_msg(bh_queue *queue, unsigned short tag, void *body,
unsigned int len);
bool bh_post_msg2(bh_queue *queue, bh_message_t msg);
bh_message_t bh_get_msg(bh_queue *queue, int timeout);
unsigned
bh_queue_get_message_count(bh_queue *queue);
void
bh_queue_enter_loop_run(bh_queue *queue,
bh_queue_handle_msg_callback handle_cb,
void *arg);
void
bh_queue_exit_loop_run(bh_queue *queue);
#ifdef __cplusplus
}
#endif
#endif /* #ifndef _BH_QUEUE_H */

View File

@ -0,0 +1,126 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _WASM_VECTOR_H
#define _WASM_VECTOR_H
#include "bh_platform.h"
#ifdef __cplusplus
extern "C" {
#endif
#define DEFAULT_VECTOR_INIT_SIZE 8
typedef struct Vector {
/* size of each element */
uint32 size_elem;
/* max element number */
uint32 max_elements;
/* current element num */
uint32 num_elements;
/* vector data allocated */
uint8 *data;
} Vector;
/**
* Initialize vector
*
* @param vector the vector to init
* @param init_length the initial length of the vector
* @param size_elem size of each element
*
* @return true if success, false otherwise
*/
bool
bh_vector_init(Vector *vector, uint32 init_length, uint32 size_elem);
/**
* Set element of vector
*
* @param vector the vector to set
* @param index the index of the element to set
* @param elem_buf the element buffer which stores the element data
*
* @return true if success, false otherwise
*/
bool
bh_vector_set(Vector *vector, uint32 index, const void *elem_buf);
/**
* Get element of vector
*
* @param vector the vector to get
* @param index the index of the element to get
* @param elem_buf the element buffer to store the element data,
* whose length must be no less than element size
*
* @return true if success, false otherwise
*/
bool
bh_vector_get(const Vector *vector, uint32 index, void *elem_buf);
/**
* Insert element of vector
*
* @param vector the vector to insert
* @param index the index of the element to insert
* @param elem_buf the element buffer which stores the element data
*
* @return true if success, false otherwise
*/
bool
bh_vector_insert(Vector *vector, uint32 index, const void *elem_buf);
/**
* Append element to the end of vector
*
* @param vector the vector to append
* @param elem_buf the element buffer which stores the element data
*
* @return true if success, false otherwise
*/
bool
bh_vector_append(Vector *vector, const void *elem_buf);
/**
* Remove element from vector
*
* @param vector the vector to remove element
* @param index the index of the element to remove
* @param old_elem_buf if not NULL, copies the element data to the buffer
*
* @return true if success, false otherwise
*/
bool
bh_vector_remove(Vector *vector, uint32 index, void *old_elem_buf);
/**
* Return the size of the vector
*
* @param vector the vector to get size
*
* @return return the size of the vector
*/
uint32
bh_vector_size(const Vector *vector);
/**
* Destroy the vector
*
* @param vector the vector to destroy
*
* @return true if success, false otherwise
*/
bool
bh_vector_destroy(Vector *vector);
#ifdef __cplusplus
}
#endif
#endif /* endof _WASM_VECTOR_H */

225
core/shared/include/bni.h Normal file
View File

@ -0,0 +1,225 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
/**
* @file bni.h
* @date Mon Jul 2 16:54:58 2012
*
* @brief Beihai native interface.
*/
#ifndef BNI_H
#define BNI_H
#include "bh_types.h"
/* Primitive types */
typedef uint8 jboolean;
typedef int8 jbyte;
typedef uint16 jchar;
typedef int16 jshort;
typedef int32 jint;
typedef int64 jlong;
typedef float jfloat;
typedef double jdouble;
typedef jint jsize;
/* Predefined Java class types. */
struct _jobject;
typedef struct _jobject *jobject;
struct _jclass;
typedef struct _jclass *jclass;
struct _jstring;
typedef struct _jstring *jstring;
/* Values of jboolean: */
#define BNI_FALSE 0
#define BNI_TRUE 1
/**
* Return the length of the array object.
*
* @param array Java array object
*
* @return the length of the Java array
*/
#define bni_array_length(array) ((jsize)((uint32)(array)->__length >> 2))
/**
* Return the address of the first element of array object.
*
* @param array Java array object
*
* @return the address of the first element of array object
*/
#define bni_array_elem(array) ((array)->__elem)
/**
* Find the Java class with given class name.
*
* @param name Java class name
*
* @return class object of the Java class if found, NULL otherwise
*
* @throws OutOfMemoryError if VM runs out of memory.
*/
jclass
bni_find_class(const char *name);
/**
* Throw an exception of given class with message.
*
* @param clazz class object of a subclass of java.lang.Throwable
* @param msg message for the exception or NULL if no message
*
* @return 0 if succeeds, nonzero otherwise
*/
jint
bni_throw_new(jclass clazz, const char *msg);
/**
* Throw a NullPointerException.
*
* @throws NullPointerException
*/
void
bni_throw_npe(void);
/**
* Throw an ArrayIndexOutOfBoundsException
*
* @param index the index used to access the array
*
* @throws ArrayIndexOutOfBoundsException
*/
void
bni_throw_aioobe(int index);
/**
* Determine whether an exception is being thrown.
*
* @return exception object if exception is thrown, NULL otherwise
*/
jobject
bni_exception_occurred(void);
/**
* Print the current exception to error-reporting channel.
*/
void
bni_exception_describe(void);
/**
* Clear the currently thrown exception.
*/
void
bni_exception_clear(void);
/**
* Return the Unicode character number of a string.
*
* @param str Java string object
*
* @return the Unicode character number of the string
*/
jsize
bni_string_length(jstring str);
/**
* Return the length in bytes of the modified UTF-8 representation of
* a string.
*
* @param str Java string object
* @param start start offset in the string
* @param len number of Unicode characters
*
* @return the UTF-8 length of the string
*
* @throws StringIndexOutOfBoundsException on index overflow.
*/
jsize
bni_string_utf_length(jstring str, jsize start, jsize len);
/**
* Copies len number of Unicode characters beginning at offset start
* to the given buffer buf.
*
* @param str Java string object
* @param start start offset in the string
* @param len number of Unicode characters to copy
* @param buf buffer for storing the result
*/
void
bni_string_region(jstring str, jsize start, jsize len, jchar *buf);
/**
* Translates len number of Unicode characters beginning at offset
* start into modified UTF-8 encoding and place the result in the
* given buffer buf.
*
* @param str Java string object
* @param start start offset in the string
* @param len number of Unicode characters to copy
* @param buf buffer for storing the result
*
* @throws StringIndexOutOfBoundsException on index overflow.
*/
void
bni_string_utf_region(jstring str, jsize start, jsize len, char *buf);
/**
* Translate Unicode characters into modified UTF-8 encoding and return
* the result.
*
* @param str Java string object
*
* @return the UTF-8 encoding string if succeeds, NULL otherwise
*/
char *
bni_string_get_utf_chars(jstring str);
/**
* Get the given Java object's class index.
*
* @param obj Java object
*
* @return -1 if obj is an array, class index of the object otherwise
*/
jint
bni_object_class_index(jobject obj);
/**
* Allocate memory from the current instance's private heap.
*
* @param size bytes to allocate
*
* @return pointer to the allocated memory
*
* @throws OutOfMemoryError if VM runs out of memory.
*/
void*
bni_malloc(unsigned size);
/**
* Allocate memory from the current instance's private heap and clear
* to zero.
*
* @param size bytes to allocate
*
* @return pointer to the allocated memory
*
* @throws OutOfMemoryError if VM runs out of memory.
*/
void*
bni_calloc(unsigned size);
/**
* Free the memory allocated from the current instance's private heap.
*
* @param ptr pointer to the memory in current instance's private heap
*/
void
bni_free(void *ptr);
#endif

View File

@ -0,0 +1,153 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _CONFIG_H_
#define _CONFIG_H_
#if !defined(BUILD_TARGET_X86_64) \
&& !defined(BUILD_TARGET_AMD_64) \
&& !defined(BUILD_TARGET_X86_32) \
&& !defined(BUILD_TARGET_ARM) \
&& !defined(BUILD_TARGET_ARM_VFP) \
&& !defined(BUILD_TARGET_THUMB) \
&& !defined(BUILD_TARGET_THUMB_VFP) \
&& !defined(BUILD_TARGET_MIPS) \
&& !defined(BUILD_TARGET_XTENSA)
#if defined(__x86_64__) || defined(__x86_64)
#define BUILD_TARGET_X86_64
#elif defined(__amd64__) || defined(__amd64)
#define BUILD_TARGET_AMD_64
#elif defined(__i386__) || defined(__i386) || defined(i386)
#define BUILD_TARGET_X86_32
#elif defined(__thumb__)
#define BUILD_TARGET_THUMB
#define BUILD_TARGET "THUMBV4T"
#elif defined(__arm__)
#define BUILD_TARGET_ARM
#define BUILD_TARGET "ARMV4T"
#elif defined(__mips__) || defined(__mips) || defined(mips)
#define BUILD_TARGET_MIPS
#elif defined(__XTENSA__)
#define BUILD_TARGET_XTENSA
#else
#error "Build target isn't set"
#endif
#endif
enum {
/* Memory allocator ems */
MEM_ALLOCATOR_EMS = 0,
/* Memory allocator tlsf */
MEM_ALLOCATOR_TLSF
};
/* Default memory allocator */
#define DEFAULT_MEM_ALLOCATOR MEM_ALLOCATOR_EMS
#ifndef WASM_ENABLE_INTERP
#define WASM_ENABLE_INTERP 0
#endif
#ifndef WASM_ENABLE_AOT
#define WASM_ENABLE_AOT 0
#endif
#ifndef WASM_ENABLE_JIT
#define WASM_ENABLE_JIT 0
#endif
#if (WASM_ENABLE_AOT == 0) && (WASM_ENABLE_JIT != 0)
/* JIT can only be enabled when AOT is enabled */
#undef WASM_ENABLE_JIT
#define WASM_ENABLE_JIT 0
#endif
#ifndef WASM_ENABLE_LIBC_BUILTIN
#define WASM_ENABLE_LIBC_BUILTIN 0
#endif
#ifndef WASM_ENABLE_LIBC_WASI
#define WASM_ENABLE_LIBC_WASI 0
#endif
#ifndef WASM_ENABLE_BASE_LIB
#define WASM_ENABLE_BASE_LIB 0
#endif
/* WASM log system */
#ifndef WASM_ENABLE_LOG
#define WASM_ENABLE_LOG 1
#endif
#if defined(BUILD_TARGET_X86_32) || defined(BUILD_TARGET_X86_64)
#define WASM_CPU_SUPPORTS_UNALIGNED_64BIT_ACCESS 1
#else
#define WASM_CPU_SUPPORTS_UNALIGNED_64BIT_ACCESS 0
#endif
/* WASM Interpreter labels-as-values feature */
#define WASM_ENABLE_LABELS_AS_VALUES 1
/* Heap and stack profiling */
#define BEIHAI_ENABLE_MEMORY_PROFILING 0
/* Max app number of all modules */
#define MAX_APP_INSTALLATIONS 3
/* Default timer number in one app */
#define DEFAULT_TIMERS_PER_APP 20
/* Max timer number in one app */
#define MAX_TIMERS_PER_APP 30
/* Max connection number in one app */
#define MAX_CONNECTION_PER_APP 20
/* Max resource registration number in one app */
#define RESOURCE_REGISTRATION_NUM_MAX 16
/* Max length of resource/event url */
#define RESOUCE_EVENT_URL_LEN_MAX 256
/* Default length of queue */
#define DEFAULT_QUEUE_LENGTH 50
/* Default watchdog interval in ms */
#define DEFAULT_WATCHDOG_INTERVAL (3 * 60 * 1000)
/* Support memory.grow opcode and enlargeMemory function */
#define WASM_ENABLE_MEMORY_GROW 1
/* The max percentage of global heap that app memory space can grow */
#define APP_MEMORY_MAX_GLOBAL_HEAP_PERCENT 1 / 3
/* Default base offset of app heap space */
#define DEFAULT_APP_HEAP_BASE_OFFSET (1 * BH_GB)
/* Default min/max heap size of each app */
#define APP_HEAP_SIZE_DEFAULT (8 * 1024)
#define APP_HEAP_SIZE_MIN (2 * 1024)
#define APP_HEAP_SIZE_MAX (1024 * 1024)
/* Default wasm stack size of each app */
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
#define DEFAULT_WASM_STACK_SIZE (16 * 1024)
#else
#define DEFAULT_WASM_STACK_SIZE (12 * 1024)
#endif
/* Default/min/max stack size of each app thread */
#if !defined(BH_PLATFORM_ZEPHYR) && !defined(BH_PLATFORM_ALIOS_THINGS)
#define APP_THREAD_STACK_SIZE_DEFAULT (20 * 1024)
#define APP_THREAD_STACK_SIZE_MIN (16 * 1024)
#define APP_THREAD_STACK_SIZE_MAX (256 * 1024)
#else
#define APP_THREAD_STACK_SIZE_DEFAULT (4 * 1024)
#define APP_THREAD_STACK_SIZE_MIN (2 * 1024)
#define APP_THREAD_STACK_SIZE_MAX (256 * 1024)
#endif
#endif /* end of _CONFIG_H_ */

View File

@ -0,0 +1,604 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
/**
* @file jeff-export.h
* @date Wed Aug 3 18:17:30 2011
*
* @brief Exported interface for operating or executing JEFF files.
* All interface names start with "jeff_", which is the namespace name
* of this module.
*/
#ifndef JEFF_EXPORT_H
#define JEFF_EXPORT_H
#include "bni.h"
#include "bh_types.h"
/********************************************************************
* Exported internal types
********************************************************************/
/**
* JEFF file handle type
*/
struct JeffFileHeaderLinked;
typedef struct JeffFileHeaderLinked *jeff_file_t;
/**
* JEFF class type
*/
struct JeffClassHeaderLinked;
typedef struct JeffClassHeaderLinked *jeff_class_t;
/**
* VM instance handle type
*/
struct JeffInstanceLocalRoot;
typedef struct JeffInstanceLocalRoot *jeff_instance_t;
/**
* Record of one native method's definition.
*/
struct JeffNativeMethodDef {
/* Mangled name of the native method. NULL for initialization
functions. */
const char *mangled_name;
/* Points to the native C function. */
void (*func_ptr)(uint32 *);
/* Return size type of the native function. */
uint32 return_size_type;
};
/********************************************************************
* Interface for operating global environment of the JEFF VM
********************************************************************/
/**
* Load the core library from the given file buffer and initialize the
* runtime environment (global objects etc.) of the VM. The thread
* calls this function becomes the supervisor thread, which belongs to
* a unique supervisor instance. Currently, if this init failed,
* partially initialized states of the VM runtime environment won't be
* cleaned up, so the VM must be shutdown and restarted. method_defs
* points to an array of native method definition records.
* Initialization functions must be in the front of the array and
* following native method definitions must be sorted by their mangled
* names.
*
* @param file the JEFF file of the core library
* @param file_size the size of the JEFF file of the core library
* @param method_defs native method definition records
* @param method_defs_num number of native method records
* @param heap the heap for the current (supervisor) instance
*
* @return true if succeeds, otherwise the error cannot be recovered
*/
bool
jeff_runtime_init(jeff_file_t file, unsigned file_size,
struct JeffNativeMethodDef *method_defs, unsigned method_defs_num,
void *heap);
/**
* Load a JEFF file into the VM from the given file buffer. It can be
* called from any VM thread.
*
* @param file the JEFF file to be loaded
* @param size the size of the JEFF file
* @param is_library whether the JEFF file is a library
* @param allow_to_load a function that returns true if classes in the
* given package is allowed to be loaded. The NULL function pointer
* allows all packages.
* @param allow_to_link a function that returns true if classes in the
* given package is allowed to be linked to. The NULL function
* pointer allows all packages.
*
* @return true if succeeds, otherwise detailed error information is
* passed to vmci_diagnostic_print. The caller can catch it by
* implementing that function.
*/
bool
jeff_runtime_load(jeff_file_t file, unsigned size, bool is_library,
bool (*allow_to_load)(const uint8 *pname, unsigned len),
bool (*allow_to_link)(const uint8 *pname, unsigned plen,
const uint8 *cname, unsigned clen));
/**
* Unload a JEFF file from the VM. All resources related to the JEFF
* file except the JEFF file itself are released. It can be called
* from any VM thread.
*
* @param file the JEFF file to be unloaded
*
* @return true if succeeds, otherwise detailed error information is
* passed to vmci_diagnostic_print. The caller can catch it by
* implementing that function.
*/
bool
jeff_runtime_unload(jeff_file_t file);
/**
* Return the JEFF file with the given file uid.
*
* @param fuid the unique id of a loaded JEFF file
*
* @return the JEFF file is exists, otherwise NULL
*/
jeff_file_t
jeff_runtime_fuid_to_file(unsigned fuid);
/**
* Return the file uid of the given JEFF file.
*
* @param file a loaded JEFF file
*
* @return the unique id of the given JEFF file
*/
unsigned
jeff_runtime_file_to_fuid(jeff_file_t file);
/**
* Create a supervisor thread belonging to the supervisor instance.
* Threads that may interact with VM core must be either the main
* thread of supervisor instance (which calls jeff_runtime_init) or
* created by this function so that VM core required data structures
* can be set up correctly.
*
* @param start_routine the start routine of the new thread
* @param arg argument to the start routine
*
* @return true if succeeds, false otherwise
*/
bool
jeff_runtime_create_supervisor_thread(void* (*start_routine)(void *),
void *arg);
/**
* Create a supervisor thread belonging to the supervisor instance.
* Threads that may interact with VM core must be either the main
* thread of supervisor instance (which calls jeff_runtime_init) or
* created by this function so that VM core required data structures
* can be set up correctly.
*
* @param start_routine the start routine of the new thread
* @param arg argument to the start routine
* @param prio thread priority
*
* @return true if succeeds, false otherwise
*/
bool
jeff_runtime_create_supervisor_thread_with_prio(void* (*start_routine)(void *),
void *arg, int prio);
/********************************************************************
* Interface for operating instance local environment
********************************************************************/
/**
* Create a VM instance with the given JEFF file as its main file,
* (i.e. the file containing the main class of the VM instance). This
* function can be called from any VM thread, but it must be isolated
* from JEFF file's unloading operation so that the main file won't be
* unloaded before it's locked by the new instance. All instance
* local memory except stacks of threads are allocated from the given
* heap. If succeeds, it increases reference count of the main_file
* and returns the handle of the new VM instance. The new instance's
* main thread will run the start_routine with argument arg. If the
* cleanup_routine is not NULL, it will be called after start_routine
* returns and just before the main thread exits. It will also be
* called after the instance is destroied. It is guaranteed to be
* called exactly once no matter how the instance terminates.
*
* @param main_file the main JEFF file of the new instance
* @param heap the private heap of the new instance
* @param stack_depth the maximal nesting levels of Java methods of
* the new instance. It must be <= 16 * 1024. Otherwise the instance
* creation will fail.
* @param start_routine start routine of the main thread. Don't
* destroy the heap or inform other thread to do this at the end of
* this routine since after it returns, VM core will call destroy
* functions on objects allocated in this heap (e.g. locks and
* condition variables). Do the destroying or informing of destroying
* in the cleanup_routine.
* @param arg the instance argument that will be passed to the start
* routine. It can be get or set by jeff_runtime_get_instance_arg and
* jeff_runtime_set_instance arg from threads of the instance. The
* caller can use it to store instance local data.
* @param cleanup_routine the optional cleanup routine for the
* instance, which may be NULL. It may be executed in the end of the
* main thread of the created instance by this function if this
* instance exits normally, or it may be executed in a thread of other
* instance in case this instance is being killed by that instance.
* In both cases, this routine regards it is executed in a thread of
* this instance (the instance created by this function) because
* jeff_runtime_get_instance_arg will always return the argument of
* this instance.
*
* @return the VM instance handle if succeeds, NULL otherwise
*/
jeff_instance_t
jeff_runtime_create_instance(jeff_file_t main_file, void *heap,
unsigned stack_depth, void* (*start_routine)(void *), void *arg,
void (*cleanup_routine)(void));
/**
* Destroy the given VM instance and decrease the reference count of
* its main file and all explicitly used JEFF files. It can be called
* from any VM thread. If there are alive threads of the instance,
* they will be terminated mandatorily and then the cleanup routine is
* called if it's not NULL.
*
* @param handle the handle of the instance to be destroyed
*/
void
jeff_runtime_destroy_instance(jeff_instance_t handle);
/**
* Retrieve the current instance's argument.
*
* @return the current instance's argument
*/
void*
jeff_runtime_get_instance_arg(void);
/**
* Set the current instance's argument.
*
* @return the new argument for the current instance
*/
void
jeff_runtime_set_instance_arg(void *arg);
/**
* Retrieve the current instance's heap.
*
* @return the current instance's heap
*/
void*
jeff_runtime_get_instance_heap(void);
/**
* Suspend all threads of the given VM instance. This function can
* only be called from thread that is not of the given VM instance.
*
* @param handle the handle of the instance to be suspended
*/
void
jeff_runtime_suspend_instance(jeff_instance_t handle);
/**
* Resume all threads of the given VM instance. This function can
* only be called from thread that is not of the given VM instance.
*
* @param handle the handle of the instance to be resumed
*/
void
jeff_runtime_resume_instance(jeff_instance_t handle);
/**
* Interrupt all threads of the given VM instance. This function can
* only be called from thread that is not of the given VM instance.
*
* @param handle the handle of the instance to be interrupted
* @param by_force whether the interruption is by force
*/
void
jeff_runtime_interrupt_instance(jeff_instance_t handle, bool by_force);
/**
* Wait for the given VM instance to terminate.
*
* @param ilr the VM instance to be waited for
* @param mills wait millseconds to return
*/
void
jeff_runtime_wait_for_instance(jeff_instance_t ilr, int mills);
/********************************************************************
* Interface for operating thread local environment
********************************************************************/
/**
* Return true if there is an uncaught exception (thrown during
* running an application or applet command).
*
* @return true if there is an uncaught exception
*/
bool
jeff_runtime_check_uncaught_exception(void);
/**
* Print qualified name of the uncaught exception (and stack trace if
* enabled) by calling vmci_diagnostic_print.
*/
void
jeff_runtime_print_uncaught_exception(void);
/**
* Clear the uncaught exception.
*/
void
jeff_runtime_reset_uncaught_exception(void);
/**
* Change current thread to a safe state (VMWAIT). After calling this
* and before calling jeff_runtime_exit_safe_state, all operations
* must be safe, i.e. no GC or system level resource operations are
* allowed because in a safe state, the VM instance is assumed to be
* able to perform GC, JDWP or termination at any time. Usually, this
* function is called just before the native code is going to wait for
* something and the exiting safe state function is called just after
* the waiting returns.
*/
void
jeff_runtime_enter_safe_state(void);
/**
* Change current thread to an unsafe state (RUNNING) so that unsafe
* operations can also be done.
*/
void
jeff_runtime_exit_safe_state(void);
/**
* Set thread local error code for the current thread.
*
* @param code the error code to be set
*/
void
jeff_runtime_set_error(unsigned code);
/**
* Get the last error code of current thread.
*
* @return the last error code of current thread
*/
unsigned
jeff_runtime_get_error(void);
/********************************************************************
* Interface for GC support
********************************************************************/
/**
* Traverse all objects of the given heap that are global or locate in
* threads' frames and return them by calling vmci_gc_rootset_elem.
* This function will suspend all threads except the current one of
* the VM instance owning the given heap before traversing. It
* traverses either all or none of the rootset objects, and returns
* true and false respectively. If it returns false, the GC process
* shouldn't proceed and is not necessary to unmark anything because
* no objects are marked. The function jeff_runtime_gc_finished must
* be called if and only if this function returns true so as to resume
* threads that are suspended during GC process.
*
* @param heap the heap for which rootset objects are looked up
*
* @return true if succeeds, false otherwise
*/
bool
jeff_runtime_traverse_gc_rootset(void *heap);
/**
* Get the reference offset table of the given object. If the
* returned value R >= 0, *ret points to the reference offset table of
* the object and R is the number of offsets in the table. Otherwise,
* if the returned value R < 0, all reference fields of the object
* must be in a continuous region (usually the object is an array),
* then *ret is the offset to the first field in the region and R is
* the number of such fields in the region.
*
* @param obj pointer to the Java object
* @param ret points to a pointer for storing the reference offset
* table if return value >= 0, or for storing the offset to the first
* object reference in the Java object if return value < 0
*
* @return number of offsets in the reference_offset table if >= 0, or
* number of object references in the object if < 0
*/
int
jeff_object_get_reference_offsets(const jobject obj, uint16 **ret);
/**
* Inform the containing VM instance that GC has finished and all
* suspended threads can be resumed. This function must be called if
* and only if jeff_runtime_traverse_gc_rootset returns true.
*/
void
jeff_runtime_gc_finished(void);
/********************************************************************
* Interface for tooling support
********************************************************************/
/**
* This function is used to suspend the main thread of VM instance so
* that debugger can have chance to connect to the VM instance, set
* breakpoints and do any other debug settings. It must be called
* from the main thread of VM instance at the point just after VM
* instance initialization finishes and just before application code
* is to be executed.
*/
void
jeff_tool_suspend_self(void);
/**
* Start up tool agent thread for the given VM instance. It can be
* called from any VM thread.
*
* @param handle the VM instance for which tool agent is started up
* @param queue queue of the tool agent
* @return true if succeeds, false otherwise
*/
bool
jeff_tool_start_agent(jeff_instance_t handle, void *queue);
/********************************************************************
* Interface for toolkit support
********************************************************************/
/**
* Return the JEFF class pointer of the given class name.
*
* @param class_name the qualified class name
*
* @return the JEFF class pointer
*/
jeff_class_t
jeff_tool_get_jeff_class(const char *class_name);
/**
* Get the mangled class name of the given class.
*
* @param clz the JEFF class
* @param buf buffer for returning the mangled name
* @param buf_size size of the buffer
*
* @return actual size of the mangled class name including the
* terminating null byte
*/
unsigned
jeff_tool_get_mangled_class_name(jeff_class_t clz, char *buf,
unsigned buf_size);
/**
* Get class index of given class in its containing JEFF file.
*
* @param clz the JEFF class
*
* @return class index in the containing JEFF file
*/
int
jeff_tool_get_class_index(jeff_class_t clz);
/**
* Callback handler prototype for traversing fields of class.
*
* @param arg argument passed to the handler from caller
* @param access_flag access flag of the method
* @param name the field name
* @param descriptor mangled field type descriptor
* @param offset the offset of the field in the class
* @param size size of the field
*/
typedef void
(*JeffToolFieldHandler)(void *arg, unsigned access_flag, const char *name,
const char *descriptor, unsigned offset, unsigned size);
/**
* Traverse all fields of the given class, including those inherited
* from super classes. The fields are traversed in the same order as
* the field layout of the class.
*
* @param arg argument to be passed to the handler
* @param clz the JEFF class
* @param instance instance fields or static fielts
* @param handler the callback handler for each field
*/
void
jeff_tool_foreach_field(void *arg, jeff_class_t clz, bool instance,
JeffToolFieldHandler handler);
/**
* Callback handler prototype for traversing methods of class.
*
* @param arg argument passed to the handler from caller
* @param access_flag access flag of the method
* @param name mangled name of the method
* @param descriptor mangled method arguments descriptor
* @param retune_type mangled descriptor of method's return type
*/
typedef void
(*JeffToolMethodHandler)(void *arg, unsigned access_flag, const char *name,
const char *descriptor, const char *return_type);
/**
* Traverse all methods of the given class.
*
* @param arg argument to be passed to the handler
* @param clz the JEFF class
* @param handler the callback handler for each method
*/
void
jeff_tool_foreach_method(void *arg, jeff_class_t clz,
JeffToolMethodHandler handler);
/**
* Callback handler prototype for traversing classes of main file.
*
* @param arg argument passed to the handler from caller
* @param clz pointer to one class in the main file
*/
typedef void
(*JeffToolClassHandler)(void *arg, jeff_class_t clz);
/**
* Traverse all classes of the main file.
*
* @param arg argument to be passed to the handler
* @param handler the callback handler for each class
*/
void
jeff_tool_foreach_class(void *arg, JeffToolClassHandler handler);
/********************************************************************
* Interface for executing applications
********************************************************************/
/**
* Initialize global environment for executing Java applications.
*
* @return true if succeeds, false otherwise
*/
bool
jeff_application_env_init(void);
/**
* Find the unique class containing a public static "main
* ([Ljava.lang.String;)V" method from the main JEFF file of the
* current instance and execute that method.
*
* @param argc the number of arguments
* @param argv the arguments array
*
* @return true if the main method is called, false otherwise (e.g. an
* exception occurs when preparing the arguments Java string array)
*/
bool
jeff_application_execute(int argc, char *argv[]);
/********************************************************************
* Interface for executing applets
********************************************************************/
/**
* Initialize global environment for executing applets.
*
* @return true if succeeds, false otherwise
*/
bool
jeff_applet_env_init(void);
/**
* Start to run from com.intel.runtime.core.RuntimeContext.main with a
* default message queue size and a default service class object. If
* the main JEFF file of the current VM instance contains exactly one
* class that is derived from com.intel.util.IntelApplet, then use it
* as the default service class.
*
* @param queue_size the default main message queue size
* @param default_service_class qualified class name of the default
* service class (entry point class), which must be in the main JEFF
* file. If NULL, find the default main class with rules described
* above.
*
* @return true if succeeds, false otherwise
*/
bool
jeff_applet_start(int queue_size, const char *default_service_class);
#endif

View File

@ -0,0 +1,34 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef __MEM_ALLOC_H
#define __MEM_ALLOC_H
#include <inttypes.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef void *mem_allocator_t;
mem_allocator_t
mem_allocator_create(void *mem, uint32_t size);
void
mem_allocator_destroy(mem_allocator_t allocator);
void *
mem_allocator_malloc(mem_allocator_t allocator, uint32_t size);
void
mem_allocator_free(mem_allocator_t allocator, void *ptr);
#ifdef __cplusplus
}
#endif
#endif /* #ifndef __MEM_ALLOC_H */

View File

@ -0,0 +1,319 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_config.h"
#include "bh_platform.h"
#include "bh_memory.h"
#include "mem_alloc.h"
#include <stdlib.h>
#if BEIHAI_ENABLE_MEMORY_PROFILING != 0
#include "bh_thread.h"
/* Memory profile data of a function */
typedef struct memory_profile {
struct memory_profile *next;
const char *function_name;
const char *file_name;
int line_in_file;
int malloc_num;
int free_num;
int total_malloc;
int total_free;
} memory_profile_t;
/* Memory in use which grows when bh_malloc was called
* and decreases when bh_free was called */
static unsigned int memory_in_use = 0;
/* Memory profile data list */
static memory_profile_t *memory_profiles_list = NULL;
/* Lock of the memory profile list */
static korp_mutex profile_lock;
#endif
#ifndef MALLOC_MEMORY_FROM_SYSTEM
typedef enum Memory_Mode {
MEMORY_MODE_UNKNOWN = 0,
MEMORY_MODE_POOL,
MEMORY_MODE_ALLOCATOR
} Memory_Mode;
static Memory_Mode memory_mode = MEMORY_MODE_UNKNOWN;
static mem_allocator_t pool_allocator = NULL;
static void *(*malloc_func)(unsigned int size) = NULL;
static void (*free_func)(void *ptr) = NULL;
static unsigned int global_pool_size;
int bh_memory_init_with_pool(void *mem, unsigned int bytes)
{
mem_allocator_t _allocator = mem_allocator_create(mem, bytes);
if (_allocator) {
memory_mode = MEMORY_MODE_POOL;
pool_allocator = _allocator;
#if BEIHAI_ENABLE_MEMORY_PROFILING != 0
vm_mutex_init(&profile_lock);
#endif
global_pool_size = bytes;
return 0;
}
bh_printf("Init memory with pool (%p, %u) failed.\n", mem, bytes);
return -1;
}
int bh_memory_init_with_allocator(void *_malloc_func, void *_free_func)
{
if (_malloc_func && _free_func && _malloc_func != _free_func) {
memory_mode = MEMORY_MODE_ALLOCATOR;
malloc_func = _malloc_func;
free_func = _free_func;
#if BEIHAI_ENABLE_MEMORY_PROFILING != 0
vm_mutex_init(&profile_lock);
#endif
return 0;
}
bh_printf("Init memory with allocator (%p, %p) failed.\n", _malloc_func,
_free_func);
return -1;
}
void bh_memory_destroy()
{
#if BEIHAI_ENABLE_MEMORY_PROFILING != 0
vm_mutex_destroy(&profile_lock);
#endif
if (memory_mode == MEMORY_MODE_POOL)
mem_allocator_destroy(pool_allocator);
memory_mode = MEMORY_MODE_UNKNOWN;
}
unsigned bh_memory_pool_size()
{
if (memory_mode == MEMORY_MODE_POOL)
return global_pool_size;
else
return 1 * BH_GB;
}
void* bh_malloc_internal(unsigned int size)
{
if (memory_mode == MEMORY_MODE_UNKNOWN) {
bh_printf("bh_malloc failed: memory hasn't been initialize.\n");
return NULL;
} else if (memory_mode == MEMORY_MODE_POOL) {
return mem_allocator_malloc(pool_allocator, size);
} else {
return malloc_func(size);
}
}
void bh_free_internal(void *ptr)
{
if (memory_mode == MEMORY_MODE_UNKNOWN) {
bh_printf("bh_free failed: memory hasn't been initialize.\n");
} else if (memory_mode == MEMORY_MODE_POOL) {
mem_allocator_free(pool_allocator, ptr);
} else {
free_func(ptr);
}
}
#if BEIHAI_ENABLE_MEMORY_PROFILING != 0
void* bh_malloc_profile(const char *file,
int line,
const char *func,
unsigned int size)
{
void *p = bh_malloc_internal(size + 8);
if (p) {
memory_profile_t *profile;
vm_mutex_lock(&profile_lock);
profile = memory_profiles_list;
while (profile) {
if (strcmp(profile->function_name, func) == 0
&& strcmp(profile->file_name, file) == 0) {
break;
}
profile = profile->next;
}
if (profile) {
profile->total_malloc += size;/* TODO: overflow check */
profile->malloc_num++;
} else {
profile = bh_malloc_internal(sizeof(memory_profile_t));
if (!profile) {
vm_mutex_unlock(&profile_lock);
bh_memcpy_s(p, size + 8, &size, sizeof(size));
return (char *)p + 8;
}
memset(profile, 0, sizeof(memory_profile_t));
profile->file_name = file;
profile->line_in_file = line;
profile->function_name = func;
profile->malloc_num = 1;
profile->total_malloc = size;
profile->next = memory_profiles_list;
memory_profiles_list = profile;
}
vm_mutex_unlock(&profile_lock);
bh_memcpy_s(p, size + 8, &size, sizeof(size));
memory_in_use += size;
memory_profile_print(file, line, func, size);
return (char *)p + 8;
}
return NULL;
}
void bh_free_profile(const char *file, int line, const char *func, void *ptr)
{
unsigned int size = *(unsigned int *)((char *)ptr - 8);
memory_profile_t *profile;
bh_free_internal((char *)ptr - 8);
if (memory_in_use >= size)
memory_in_use -= size;
vm_mutex_lock(&profile_lock);
profile = memory_profiles_list;
while (profile) {
if (strcmp(profile->function_name, func) == 0
&& strcmp(profile->file_name, file) == 0) {
break;
}
profile = profile->next;
}
if (profile) {
profile->total_free += size;/* TODO: overflow check */
profile->free_num++;
} else {
profile = bh_malloc_internal(sizeof(memory_profile_t));
if (!profile) {
vm_mutex_unlock(&profile_lock);
return;
}
memset(profile, 0, sizeof(memory_profile_t));
profile->file_name = file;
profile->line_in_file = line;
profile->function_name = func;
profile->free_num = 1;
profile->total_free = size;
profile->next = memory_profiles_list;
memory_profiles_list = profile;
}
vm_mutex_unlock(&profile_lock);
}
/**
* Summarize memory usage and print it out
* Can use awk to analyze the output like below:
* awk -F: '{print $2,$4,$6,$8,$9}' OFS="\t" ./out.txt | sort -n -r -k 1
*/
void memory_usage_summarize()
{
memory_profile_t *profile;
vm_mutex_lock(&profile_lock);
profile = memory_profiles_list;
while (profile) {
bh_printf("malloc:%d:malloc_num:%d:free:%d:free_num:%d:%s\n",
profile->total_malloc,
profile->malloc_num,
profile->total_free,
profile->free_num,
profile->function_name);
profile = profile->next;
}
vm_mutex_unlock(&profile_lock);
}
void memory_profile_print(const char *file,
int line,
const char *func,
int alloc)
{
bh_printf("location:%s@%d:used:%d:contribution:%d\n",
func, line, memory_in_use, alloc);
}
#else
void* bh_malloc(unsigned int size)
{
return bh_malloc_internal(size);
}
void bh_free(void *ptr)
{
bh_free_internal(ptr);
}
#endif
#else /* else of MALLOC_MEMORY_FROM_SYSTEM */
#if BEIHAI_ENABLE_MEMORY_PROFILING == 0
void* bh_malloc(unsigned int size)
{
return malloc(size);
}
void bh_free(void *ptr)
{
if (ptr)
free(ptr);
}
#else /* else of BEIHAI_ENABLE_MEMORY_PROFILING */
void* bh_malloc_profile(const char *file,
int line,
const char *func,
unsigned int size)
{
(void)file;
(void)line;
(void)func;
(void)memory_profiles_list;
(void)profile_lock;
(void)memory_in_use;
return malloc(size);
}
void bh_free_profile(const char *file, int line, const char *func, void *ptr)
{
(void)file;
(void)line;
(void)func;
if (ptr)
free(ptr);
}
#endif /* end of BEIHAI_ENABLE_MEMORY_PROFILING */
#endif /* end of MALLOC_MEMORY_FROM_SYSTEM*/

View File

@ -0,0 +1,576 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "ems_gc_internal.h"
static int hmu_is_in_heap(gc_heap_t* heap, hmu_t* hmu)
{
return heap && hmu && (gc_uint8*) hmu >= heap->base_addr
&& (gc_uint8*) hmu < heap->base_addr + heap->current_size;
}
/* Remove a node from the tree it belongs to*/
/* @p can not be NULL*/
/* @p can not be the ROOT node*/
/* Node @p will be removed from the tree and left,right,parent pointers of node @p will be*/
/* set to be NULL. Other fields will not be touched.*/
/* The tree will be re-organized so that the order conditions are still satisified.*/
BH_STATIC void remove_tree_node(hmu_tree_node_t *p)
{
hmu_tree_node_t *q = NULL, **slot = NULL;
bh_assert(p);
bh_assert(p->parent); /* @p can not be the ROOT node*/
/* get the slot which holds pointer to node p*/
if (p == p->parent->right) {
slot = &p->parent->right;
} else {
bh_assert(p == p->parent->left); /* @p should be a child of its parent*/
slot = &p->parent->left;
}
/* algorithms used to remove node p*/
/* case 1: if p has no left child, replace p with its right child*/
/* case 2: if p has no right child, replace p with its left child*/
/* case 3: otherwise, find p's predecessor, remove it from the tree and replace p with it.*/
/* use predecessor can keep the left <= root < right condition.*/
if (!p->left) {
/* move right child up*/
*slot = p->right;
if (p->right)
p->right->parent = p->parent;
p->left = p->right = p->parent = NULL;
return;
}
if (!p->right) {
/* move left child up*/
*slot = p->left;
p->left->parent = p->parent; /* p->left can never be NULL.*/
p->left = p->right = p->parent = NULL;
return;
}
/* both left & right exist, find p's predecessor at first*/
q = p->left;
while (q->right)
q = q->right;
remove_tree_node(q); /* remove from the tree*/
*slot = q;
q->parent = p->parent;
q->left = p->left;
q->right = p->right;
if (q->left)
q->left->parent = q;
if (q->right)
q->right->parent = q;
p->left = p->right = p->parent = NULL;
}
static void unlink_hmu(gc_heap_t *heap, hmu_t *hmu)
{
gc_size_t size;
bh_assert(gci_is_heap_valid(heap));
bh_assert(
hmu && (gc_uint8*) hmu >= heap->base_addr
&& (gc_uint8*) hmu < heap->base_addr + heap->current_size);
bh_assert(hmu_get_ut(hmu) == HMU_FC);
size = hmu_get_size(hmu);
if (HMU_IS_FC_NORMAL(size)) {
uint32 node_idx = size >> 3;
hmu_normal_node_t* node = heap->kfc_normal_list[node_idx].next;
hmu_normal_node_t** p = &(heap->kfc_normal_list[node_idx].next);
while (node) {
if ((hmu_t*) node == hmu) {
*p = node->next;
break;
}
p = &(node->next);
node = node->next;
}
if (!node) {
bh_printf("[GC_ERROR]couldn't find the node in the normal list");
}
} else {
remove_tree_node((hmu_tree_node_t *) hmu);
}
}
static void hmu_set_free_size(hmu_t *hmu)
{
gc_size_t size;
bh_assert(hmu && hmu_get_ut(hmu) == HMU_FC);
size = hmu_get_size(hmu);
*((uint32*) ((char*) hmu + size) - 1) = size;
}
/* Add free chunk back to KFC*/
/* @heap should not be NULL and it should be a valid heap*/
/* @hmu should not be NULL and it should be a HMU of length @size inside @heap*/
/* @hmu should be aligned to 8*/
/* @size should be positive and multiple of 8*/
/* @hmu with size @size will be added into KFC as a new FC.*/
void gci_add_fc(gc_heap_t *heap, hmu_t *hmu, gc_size_t size)
{
hmu_normal_node_t *np = NULL;
hmu_tree_node_t *root = NULL, *tp = NULL, *node = NULL;
uint32 node_idx;
bh_assert(gci_is_heap_valid(heap));
bh_assert(
hmu && (gc_uint8*) hmu >= heap->base_addr
&& (gc_uint8*) hmu < heap->base_addr + heap->current_size);
bh_assert(((gc_uint32)(uintptr_t)hmu_to_obj(hmu) & 7) == 0);
bh_assert(
size > 0
&& ((gc_uint8*) hmu) + size
<= heap->base_addr + heap->current_size);
bh_assert(!(size & 7));
hmu_set_ut(hmu, HMU_FC);
hmu_set_size(hmu, size);
hmu_set_free_size(hmu);
if (HMU_IS_FC_NORMAL(size)) {
np = (hmu_normal_node_t*) hmu;
node_idx = size >> 3;
np->next = heap->kfc_normal_list[node_idx].next;
heap->kfc_normal_list[node_idx].next = np;
return;
}
/* big block*/
node = (hmu_tree_node_t*) hmu;
node->size = size;
node->left = node->right = node->parent = NULL;
/* find proper node to link this new node to*/
root = &heap->kfc_tree_root;
tp = root;
bh_assert(tp->size < size);
while (1) {
if (tp->size < size) {
if (!tp->right) {
tp->right = node;
node->parent = tp;
break;
}
tp = tp->right;
} else /* tp->size >= size*/
{
if (!tp->left) {
tp->left = node;
node->parent = tp;
break;
}
tp = tp->left;
}
}
}
/* Find a proper hmu for required memory size*/
/* @heap should not be NULL and it should be a valid heap*/
/* @size should cover the header and it should be 8 bytes aligned*/
/* GC will not be performed here.*/
/* Heap extension will not be performed here.*/
/* A proper HMU will be returned. This HMU can include the header and given size. The returned HMU will be aligned to 8 bytes.*/
/* NULL will be returned if there are no proper HMU.*/
BH_STATIC hmu_t *alloc_hmu(gc_heap_t *heap, gc_size_t size)
{
hmu_normal_node_t *node = NULL, *p = NULL;
uint32 node_idx = 0, init_node_idx = 0;
hmu_tree_node_t *root = NULL, *tp = NULL, *last_tp = NULL;
hmu_t *next, *rest;
bh_assert(gci_is_heap_valid(heap));
bh_assert(size > 0 && !(size & 7));
if (size < GC_SMALLEST_SIZE)
size = GC_SMALLEST_SIZE;
/* check normal list at first*/
if (HMU_IS_FC_NORMAL(size)) {
/* find a non-empty slot in normal_node_list with good size*/
init_node_idx = (size >> 3);
for (node_idx = init_node_idx; node_idx < HMU_NORMAL_NODE_CNT;
node_idx++) {
node = heap->kfc_normal_list + node_idx;
if (node->next)
break;
node = NULL;
}
/* not found in normal list*/
if (node) {
bh_assert(node_idx >= init_node_idx);
p = node->next;
node->next = p->next;
bh_assert(((gc_int32)(uintptr_t)hmu_to_obj(p) & 7) == 0);
if ((gc_size_t)node_idx != (uint32)init_node_idx
&& ((gc_size_t)node_idx << 3) >= size + GC_SMALLEST_SIZE) { /* with bigger size*/
rest = (hmu_t*) (((char *) p) + size);
gci_add_fc(heap, rest, (node_idx << 3) - size);
hmu_mark_pinuse(rest);
} else {
size = node_idx << 3;
next = (hmu_t*) ((char*) p + size);
if (hmu_is_in_heap(heap, next))
hmu_mark_pinuse(next);
}
#if GC_STAT_DATA != 0
heap->total_free_size -= size;
if ((heap->current_size - heap->total_free_size)
> heap->highmark_size)
heap->highmark_size = heap->current_size
- heap->total_free_size;
#endif
hmu_set_size((hmu_t* ) p, size);
return (hmu_t*) p;
}
}
/* need to find a node in tree*/
root = &heap->kfc_tree_root;
/* find the best node*/
bh_assert(root);
tp = root->right;
while (tp) {
if (tp->size < size) {
tp = tp->right;
continue;
}
/* record the last node with size equal to or bigger than given size*/
last_tp = tp;
tp = tp->left;
}
if (last_tp) {
bh_assert(last_tp->size >= size);
/* alloc in last_p*/
/* remove node last_p from tree*/
remove_tree_node(last_tp);
if (last_tp->size >= size + GC_SMALLEST_SIZE) {
rest = (hmu_t*) ((char*) last_tp + size);
gci_add_fc(heap, rest, last_tp->size - size);
hmu_mark_pinuse(rest);
} else {
size = last_tp->size;
next = (hmu_t*) ((char*) last_tp + size);
if (hmu_is_in_heap(heap, next))
hmu_mark_pinuse(next);
}
#if GC_STAT_DATA != 0
heap->total_free_size -= size;
if ((heap->current_size - heap->total_free_size) > heap->highmark_size)
heap->highmark_size = heap->current_size - heap->total_free_size;
#endif
hmu_set_size((hmu_t* ) last_tp, size);
return (hmu_t*) last_tp;
}
return NULL;
}
/* Find a proper HMU for given size*/
/* @heap should not be NULL and it should be a valid heap*/
/* @size should cover the header and it should be 8 bytes aligned*/
/* This function will try several ways to satisfy the allocation request.*/
/* 1. Find a proper on available HMUs.*/
/* 2. GC will be triggered if 1 failed.*/
/* 3. Find a proper on available HMUS.*/
/* 4. Return NULL if 3 failed*/
/* A proper HMU will be returned. This HMU can include the header and given size. The returned HMU will be aligned to 8 bytes.*/
/* NULL will be returned if there are no proper HMU.*/
BH_STATIC hmu_t* alloc_hmu_ex(gc_heap_t *heap, gc_size_t size)
{
hmu_t *ret = NULL;
bh_assert(gci_is_heap_valid(heap));
bh_assert(size > 0 && !(size & 7));
#ifdef GC_IN_EVERY_ALLOCATION
gci_gc_heap(heap);
ret = alloc_hmu(heap, size);
#else
# if GC_STAT_DATA != 0
if (heap->gc_threshold < heap->total_free_size)
ret = alloc_hmu(heap, size);
# else
ret = alloc_hmu(heap, size);
# endif
if (ret)
return ret;
/*gci_gc_heap(heap);*//* disable gc claim currently */
ret = alloc_hmu(heap, size);
#endif
return ret;
}
unsigned long g_total_malloc = 0;
unsigned long g_total_free = 0;
gc_object_t _gc_alloc_vo_i_heap(void *vheap,
gc_size_t size ALLOC_EXTRA_PARAMETERS)
{
gc_heap_t* heap = (gc_heap_t*) vheap;
hmu_t *hmu = NULL;
gc_object_t ret = (gc_object_t) NULL;
gc_size_t tot_size = 0;
/* align size*/
tot_size = GC_ALIGN_8(size + HMU_SIZE + OBJ_PREFIX_SIZE + OBJ_SUFFIX_SIZE); /* hmu header, prefix, suffix*/
if (tot_size < size)
return NULL;
gct_vm_mutex_lock(&heap->lock);
hmu = alloc_hmu_ex(heap, tot_size);
if (!hmu)
goto FINISH;
g_total_malloc += tot_size;
hmu_set_ut(hmu, HMU_VO);
hmu_unfree_vo(hmu);
#if defined(GC_VERIFY)
hmu_init_prefix_and_suffix(hmu, tot_size, file_name, line_number);
#endif
ret = hmu_to_obj(hmu);
#if BH_ENABLE_MEMORY_PROFILING != 0
bh_printf("HEAP.ALLOC: heap: %p, size: %u", heap, size);
#endif
FINISH:
gct_vm_mutex_unlock(&heap->lock);
return ret;
}
/* see ems_gc.h for description*/
gc_object_t _gc_alloc_jo_i_heap(void *vheap,
gc_size_t size ALLOC_EXTRA_PARAMETERS)
{
gc_heap_t* heap = (gc_heap_t*) vheap;
gc_object_t ret = (gc_object_t) NULL;
hmu_t *hmu = NULL;
gc_size_t tot_size = 0;
bh_assert(gci_is_heap_valid(heap));
/* align size*/
tot_size = GC_ALIGN_8(size + HMU_SIZE + OBJ_PREFIX_SIZE + OBJ_SUFFIX_SIZE); /* hmu header, prefix, suffix*/
if (tot_size < size)
return NULL;
hmu = alloc_hmu_ex(heap, tot_size);
if (!hmu)
goto FINISH;
/* reset all fields*/
memset((char*) hmu + sizeof(*hmu), 0, tot_size - sizeof(*hmu));
/* hmu->header = 0; */
hmu_set_ut(hmu, HMU_JO);
hmu_unmark_jo(hmu);
#if defined(GC_VERIFY)
hmu_init_prefix_and_suffix(hmu, tot_size, file_name, line_number);
#endif
ret = hmu_to_obj(hmu);
#if BH_ENABLE_MEMORY_PROFILING != 0
bh_printf("HEAP.ALLOC: heap: %p, size: %u", heap, size);
#endif
FINISH:
return ret;
}
/* Do some checking to see if given pointer is a possible valid heap*/
/* Return GC_TRUE if all checking passed*/
/* Return GC_FALSE otherwise*/
int gci_is_heap_valid(gc_heap_t *heap)
{
if (!heap)
return GC_FALSE;
if (heap->heap_id != (gc_handle_t) heap)
return GC_FALSE;
return GC_TRUE;
}
int gc_free_i_heap(void *vheap, gc_object_t obj ALLOC_EXTRA_PARAMETERS)
{
gc_heap_t* heap = (gc_heap_t*) vheap;
hmu_t *hmu = NULL;
hmu_t *prev = NULL;
hmu_t *next = NULL;
gc_size_t size = 0;
hmu_type_t ut;
int ret = GC_SUCCESS;
if (!obj) {
return GC_SUCCESS;
}
hmu = obj_to_hmu(obj);
gct_vm_mutex_lock(&heap->lock);
if ((gc_uint8 *) hmu >= heap->base_addr
&& (gc_uint8 *) hmu < heap->base_addr + heap->current_size) {
#ifdef GC_VERIFY
hmu_verify(hmu);
#endif
ut = hmu_get_ut(hmu);
if (ut == HMU_VO) {
if (hmu_is_vo_freed(hmu)) {
bh_assert(0);
ret = GC_ERROR;
goto out;
}
size = hmu_get_size(hmu);
g_total_free += size;
#if GC_STAT_DATA != 0
heap->total_free_size += size;
#endif
#if BH_ENABLE_MEMORY_PROFILING != 0
bh_printf("HEAP.FREE, heap: %p, size: %u\n",heap, size);
#endif
if (!hmu_get_pinuse(hmu)) {
prev = (hmu_t*) ((char*) hmu - *((int*) hmu - 1));
if (hmu_is_in_heap(heap, prev) && hmu_get_ut(prev) == HMU_FC) {
size += hmu_get_size(prev);
hmu = prev;
unlink_hmu(heap, prev);
}
}
next = (hmu_t*) ((char*) hmu + size);
if (hmu_is_in_heap(heap, next)) {
if (hmu_get_ut(next) == HMU_FC) {
size += hmu_get_size(next);
unlink_hmu(heap, next);
next = (hmu_t*) ((char*) hmu + size);
}
}
gci_add_fc(heap, hmu, size);
if (hmu_is_in_heap(heap, next)) {
hmu_unmark_pinuse(next);
}
} else {
ret = GC_ERROR;
goto out;
}
ret = GC_SUCCESS;
goto out;
}
out:
gct_vm_mutex_unlock(&heap->lock);
return ret;
}
void gc_dump_heap_stats(gc_heap_t *heap)
{
bh_printf("heap: %p, heap start: %p\n", heap, heap->base_addr);
bh_printf(
"total malloc: totalfree: %u, current: %u, highmark: %u, gc cnt: %u\n",
heap->total_free_size, heap->current_size, heap->highmark_size,
heap->total_gc_count);
bh_printf("g_total_malloc=%lu, g_total_free=%lu, occupied=%lu\n",
g_total_malloc, g_total_free, g_total_malloc - g_total_free);
}
#ifdef GC_TEST
void gci_dump(char* buf, gc_heap_t *heap)
{
hmu_t *cur = NULL, *end = NULL;
hmu_type_t ut;
gc_size_t size;
int i = 0;
int p;
char inuse;
int mark;
cur = (hmu_t*)heap->base_addr;
end = (hmu_t*)((char*)heap->base_addr + heap->current_size);
while(cur < end)
{
ut = hmu_get_ut(cur);
size = hmu_get_size(cur);
p = hmu_get_pinuse(cur);
mark = hmu_is_jo_marked (cur);
if(ut == HMU_VO)
inuse = 'V';
else if(ut == HMU_JO)
inuse = hmu_is_jo_marked(cur) ? 'J' : 'j';
else if(ut == HMU_FC)
inuse = 'F';
bh_assert(size > 0);
buf += sprintf(buf, "#%d %08x %x %x %d %c %d\n", i, (char*) cur - (char*) heap->base_addr, ut, p, mark, inuse, hmu_obj_size(size));
cur = (hmu_t*)((char *)cur + size);
i++;
}
bh_assert(cur == end);
}
#endif

View File

@ -0,0 +1,330 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
/**
* @file ems_gc.h
* @date Wed Aug 3 10:46:38 2011
*
* @brief This file defines GC modules types and interfaces.
*
*
*/
#ifndef _EMS_GC_H
#define _EMS_GC_H
#include "bh_platform.h"
#ifdef __cplusplus
extern "C" {
#endif
/*Pre-compile configuration can be done here or on Makefiles*/
/*#define GC_EMBEDDED or GC_STANDALONE*/
/*#define GC_DEBUG*/
/*#define GC_TEST // TEST mode is a sub-mode of STANDALONE*/
/* #define GC_ALLOC_TRACE */
/* #define GC_STAT */
#ifndef GC_STAT_DATA
#define GC_STAT_DATA 1
#endif
#define GC_HEAD_PADDING 4
/* Standalone GC is used for testing.*/
#ifndef GC_EMBEDDED
# ifndef GC_STANDALONE
# define GC_STANDALONE
# endif
#endif
#if defined(GC_EMBEDDED) && defined(GC_STANDALONE)
# error "Can not define GC_EMBEDDED and GC_STANDALONE at the same time"
#endif
#ifdef BH_TEST
# ifndef GC_TEST
# define GC_TEST
# endif
#endif
#ifdef BH_DEBUG
/*instrument mode ignore GC_DEBUG feature, for instrument testing gc_alloc_vo_i_heap only has func_name parameter*/
#if !defined INSTRUMENT_TEST_ENABLED && !defined GC_DEBUG
# define GC_DEBUG
#endif
#endif
#if defined(GC_EMBEDDED) && defined(GC_TEST)
# error "Can not defined GC_EMBEDDED and GC_TEST at the same time"
#endif
typedef void *gc_handle_t;
typedef void *gc_object_t;
#define NULL_REF ((gc_object_t)NULL)
#define GC_SUCCESS (0)
#define GC_ERROR (-1)
#define GC_TRUE (1)
#define GC_FALSE (0)
#define GC_MAX_HEAP_SIZE (256 * BH_KB)
typedef int64 gc_int64;
typedef unsigned int gc_uint32;
typedef signed int gc_int32;
typedef unsigned short gc_uint16;
typedef signed short gc_int16;
typedef unsigned char gc_uint8;
typedef signed char gc_int8;
typedef gc_uint32 gc_size_t;
typedef enum {
MMT_SHARED = 0,
MMT_INSTANCE = 1,
MMT_APPMANAGER = MMT_SHARED,
MMT_VERIFIER = MMT_SHARED,
MMT_JHI = MMT_SHARED,
MMT_LOADER = MMT_SHARED,
MMT_APPLET = MMT_INSTANCE,
MMT_INTERPRETER = MMT_INSTANCE
} gc_mm_t;
#ifdef GC_STAT
#define GC_HEAP_STAT_SIZE (128 / 4)
typedef struct {
int usage;
int usage_block;
int vo_usage;
int jo_usage;
int free;
int free_block;
int vo_free;
int jo_free;
int usage_sizes[GC_HEAP_STAT_SIZE];
int free_sizes[GC_HEAP_STAT_SIZE];
}gc_stat_t;
extern void gc_heap_stat(void* heap, gc_stat_t* gc_stat);
extern void __gc_print_stat(void *heap, int verbose);
#define gc_print_stat __gc_print_stat
#else
#define gc_print_stat(heap, verbose)
#endif
#if GC_STAT_DATA != 0
typedef enum {
GC_STAT_TOTAL = 0,
GC_STAT_FREE,
GC_STAT_HIGHMARK,
GC_STAT_COUNT,
GC_STAT_TIME,
GC_STAT_MAX_1,
GC_STAT_MAX_2,
GC_STAT_MAX_3,
GC_STAT_MAX
} GC_STAT_INDEX;
#endif
/*////////////// Exported APIs*/
/**
* GC initialization from a buffer
*
* @param buf the buffer to be initialized to a heap
* @param buf_size the size of buffer
*
* @return gc handle if success, NULL otherwise
*/
extern gc_handle_t gc_init_with_pool(char *buf, gc_size_t buf_size);
/**
* Destroy heap which is initilized from a buffer
*
* @param handle handle to heap needed destroy
*
* @return GC_SUCCESS if success
* GC_ERROR for bad parameters or failed system resource freeing.
*/
extern int gc_destroy_with_pool(gc_handle_t handle);
#if GC_STAT_DATA != 0
/**
* Get Heap Stats
*
* @param stats [out] integer array to save heap stats
* @param size [in] the size of stats
* @param mmt [in] type of heap, MMT_SHARED or MMT_INSTANCE
*/
extern void* gc_heap_stats(void *heap, uint32* stats, int size, gc_mm_t mmt);
/**
* Set GC threshold factor
*
* @param heap [in] the heap to set
* @param factor [in] the threshold size is free_size * factor / 1000
*
* @return GC_SUCCESS if success.
*/
extern int gc_set_threshold_factor(void *heap, unsigned int factor);
#endif
/*////// Allocate heap object*/
/* There are two versions of allocate functions. The functions with _i suffix should be only used*/
/* internally. Functions without _i suffix are just wrappers with the corresponded functions with*/
/* _i suffix. Allocation operation code position are record under DEBUG model for debugging.*/
#ifdef GC_DEBUG
# define ALLOC_EXTRA_PARAMETERS ,const char*file_name,int line_number
# define ALLOC_EXTRA_ARGUMENTS , __FILE__, __LINE__
# define ALLOC_PASSDOWN_EXTRA_ARGUMENTS , file_name, line_number
# define gc_alloc_vo_h(heap, size) gc_alloc_vo_i_heap(heap, size, __FILE__, __LINE__)
# define gc_free_h(heap, obj) gc_free_i_heap(heap, obj, __FILE__, __LINE__)
#else
# define ALLOC_EXTRA_PARAMETERS
# define ALLOC_EXTRA_ARGUMENTS
# define ALLOC_PASSDOWN_EXTRA_ARGUMENTS
# define gc_alloc_vo_h gc_alloc_vo_i_heap
# define gc_free_h gc_free_i_heap
#endif
/**
* Invoke a GC
*
* @param heap
*
* @return GC_SUCCESS if success
*/
extern int gci_gc_heap(void *heap);
/**
* Allocate VM Object in specific heap.
*
* @param heap heap to allocate.
* @param size bytes to allocate.
*
* @return pointer to VM object allocated
* NULL if failed.
*/
extern gc_object_t _gc_alloc_vo_i_heap(void *heap,
gc_size_t size ALLOC_EXTRA_PARAMETERS);
extern gc_object_t _gc_alloc_jo_i_heap(void *heap,
gc_size_t size ALLOC_EXTRA_PARAMETERS);
#ifdef INSTRUMENT_TEST_ENABLED
extern gc_object_t gc_alloc_vo_i_heap_instr(void *heap, gc_size_t size, const char* func_name );
extern gc_object_t gc_alloc_jo_i_heap_instr(void *heap, gc_size_t size, const char* func_name);
# define gc_alloc_vo_i_heap(heap, size) gc_alloc_vo_i_heap_instr(heap, size, __FUNCTION__)
# define gc_alloc_jo_i_heap(heap, size) gc_alloc_jo_i_heap_instr(heap, size, __FUNCTION__)
#else
# define gc_alloc_vo_i_heap _gc_alloc_vo_i_heap
# define gc_alloc_jo_i_heap _gc_alloc_jo_i_heap
#endif
/**
* Allocate Java object in specific heap.
*
* @param heap heap to allocate.
* @param size bytes to allocate.
*
* @return pointer to Java object allocated
* NULL if failed.
*/
extern gc_object_t _gc_alloc_jo_i_heap(void *heap,
gc_size_t size ALLOC_EXTRA_PARAMETERS);
/**
* Free VM object
*
* @param heap heap to free.
* @param obj pointer to object need free.
*
* @return GC_SUCCESS if success
*/
extern int gc_free_i_heap(void *heap, gc_object_t obj ALLOC_EXTRA_PARAMETERS);
/**
* Add ref to rootset of gc for current instance.
*
* @param obj pointer to real load of a valid Java object managed by gc for current instance.
*
* @return GC_SUCCESS if success.
* GC_ERROR for invalid parameters.
*/
extern int gc_add_root(void* heap, gc_object_t obj);
/*////////////// Imported APIs which should be implemented in other components*/
/*////// Java object layout related APIs*/
/**
* Get Java object size from corresponding VM module
*
* @param obj pointer to the real load of a Java object.
*
* @return size of java object.
*/
extern gc_size_t vm_get_java_object_size(gc_object_t obj);
/**
* Get reference list of this object
*
* @param obj [in] pointer to java object.
* @param is_compact_mode [in] indicate the java object mode. GC_TRUE or GC_FALSE.
* @param ref_num [out] the size of ref_list.
* @param ref_list [out] if is_compact_mode is GC_FALSE, this parameter will be set to a list of offset.
* @param ref_start_offset [out] If is_compact_mode is GC_TRUE, this parameter will be set to the start offset of the references in this object.
*
* @return GC_SUCCESS if success.
* GC_ERROR when error occurs.
*/
extern int vm_get_java_object_ref_list(gc_object_t obj, int *is_compact_mode,
gc_size_t *ref_num, gc_uint16 **ref_list, gc_uint32 *ref_start_offset);
/**
* Get gc handle for current instance
*
*
* @return instance heap handle.
*/
extern gc_handle_t app_manager_get_cur_applet_heap(void);
/**
* Begin current instance heap rootset enumeration
*
*
* @return GC_SUCCESS if success.
* GC_ERROR when error occurs.
*/
extern int vm_begin_rootset_enumeration(void *heap);
#ifdef _INSTRUMENT_TEST_ENABLED
extern int vm_begin_rootset_enumeration_instr(void *heap, const char*func_name);
#define vm_begin_rootset_enumeration(heap) vm_begin_rootset_enumeration_instr(heap, __FUNCTION__)
#else
#define vm_begin_rootset_enumeration _vm_begin_rootset_enumeration
#endif /* INSTUMENT_TEST_ENABLED*/
#ifndef offsetof
#define offsetof(Type, field) ((size_t)(&((Type *)0)->field))
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,271 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _EMS_GC_INTERNAL_H
#define _EMS_GC_INTERNAL_H
#ifdef __cplusplus
extern "C" {
#endif
#include "bh_platform.h"
#include "bh_thread.h"
#include "bh_memory.h"
#include "bh_assert.h"
#include "ems_gc.h"
/* basic block managed by EMS gc is the so-called HMU (heap memory unit)*/
typedef enum _hmu_type_enum
{
HMU_TYPE_MIN = 0,
HMU_TYPE_MAX = 3,
HMU_JO = 3,
HMU_VO = 2,
HMU_FC = 1,
HMU_FM = 0
}hmu_type_t;
typedef struct _hmu_struct
{
gc_uint32 header;
}hmu_t;
#if defined(GC_VERIFY)
#define GC_OBJECT_PREFIX_PADDING_CNT 3
#define GC_OBJECT_SUFFIX_PADDING_CNT 4
#define GC_OBJECT_PADDING_VALUE (0x12345678)
typedef struct _gc_object_prefix
{
const char *file_name;
gc_int32 line_no;
gc_int32 size;
gc_uint32 padding[GC_OBJECT_PREFIX_PADDING_CNT];
}gc_object_prefix_t;
#define OBJ_PREFIX_SIZE (sizeof(gc_object_prefix_t))
typedef struct _gc_object_suffix
{
gc_uint32 padding[GC_OBJECT_SUFFIX_PADDING_CNT];
}gc_object_suffix_t;
#define OBJ_SUFFIX_SIZE (sizeof(gc_object_suffix_t))
extern void hmu_init_prefix_and_suffix(hmu_t *hmu, gc_size_t tot_size, const char *file_name, int line_no);
extern void hmu_verify(hmu_t *hmu);
#define SKIP_OBJ_PREFIX(p) ((void*)((gc_uint8*)(p) + OBJ_PREFIX_SIZE))
#define SKIP_OBJ_SUFFIX(p) ((void*)((gc_uint8*)(p) + OBJ_SUFFIX_SIZE))
#define OBJ_EXTRA_SIZE (HMU_SIZE + OBJ_PREFIX_SIZE + OBJ_SUFFIX_SIZE)
#else
#define OBJ_PREFIX_SIZE 0
#define OBJ_SUFFIX_SIZE 0
#define SKIP_OBJ_PREFIX(p) ((void*)((gc_uint8*)(p) + OBJ_PREFIX_SIZE))
#define SKIP_OBJ_SUFFIX(p) ((void*)((gc_uint8*)(p) + OBJ_SUFFIX_SIZE))
#define OBJ_EXTRA_SIZE (HMU_SIZE + OBJ_PREFIX_SIZE + OBJ_SUFFIX_SIZE)
#endif /* GC_DEBUG*/
#define hmu_obj_size(s) ((s)-OBJ_EXTRA_SIZE)
#define GC_ALIGN_8(s) (((uint32)(s) + 7) & (uint32)~7)
#define GC_SMALLEST_SIZE GC_ALIGN_8(HMU_SIZE + OBJ_PREFIX_SIZE + OBJ_SUFFIX_SIZE + 8)
#define GC_GET_REAL_SIZE(x) GC_ALIGN_8(HMU_SIZE + OBJ_PREFIX_SIZE + OBJ_SUFFIX_SIZE + (((x) > 8) ? (x): 8))
/*////// functions for bit operation*/
#define SETBIT(v, offset) (v) |= (1 << (offset))
#define GETBIT(v, offset) ((v) & (1 << (offset)) ? 1 : 0)
#define CLRBIT(v, offset) (v) &= (uint32)(~(1 << (offset)))
#define SETBITS(v, offset, size, value) do { \
(v) &= (uint32)(~(((1 << size) - 1) << offset));\
(v) |= (uint32)(value << offset); \
} while(0)
#define CLRBITS(v, offset, size) (v) &= ~(((1 << size) - 1) << offset)
#define GETBITS(v, offset, size) (((v) & ((uint32)(((1 << size) - 1) << offset))) >> offset)
/*////// gc object layout definition*/
#define HMU_SIZE (sizeof(hmu_t))
#define hmu_to_obj(hmu) (gc_object_t)(SKIP_OBJ_PREFIX((hmu_t*) (hmu) + 1))
#define obj_to_hmu(obj) ((hmu_t *)((gc_uint8*)(obj) - OBJ_PREFIX_SIZE) - 1)
#define HMU_UT_SIZE 2
#define HMU_UT_OFFSET 30
#define hmu_get_ut(hmu) GETBITS ((hmu)->header, HMU_UT_OFFSET, HMU_UT_SIZE)
#define hmu_set_ut(hmu, type) SETBITS ((hmu)->header, HMU_UT_OFFSET, HMU_UT_SIZE, type)
#define hmu_is_ut_valid(tp) (tp >= HMU_TYPE_MIN && tp <= HMU_TYPE_MAX)
/* P in use bit means the previous chunk is in use */
#define HMU_P_OFFSET 29
#define hmu_mark_pinuse(hmu) SETBIT ((hmu)->header, HMU_P_OFFSET)
#define hmu_unmark_pinuse(hmu) CLRBIT ((hmu)->header, HMU_P_OFFSET)
#define hmu_get_pinuse(hmu) GETBIT ((hmu)->header, HMU_P_OFFSET)
#define HMU_JO_VT_SIZE 27
#define HMU_JO_VT_OFFSET 0
#define HMU_JO_MB_OFFSET 28
#define hmu_mark_jo(hmu) SETBIT ((hmu)->header, HMU_JO_MB_OFFSET)
#define hmu_unmark_jo(hmu) CLRBIT ((hmu)->header, HMU_JO_MB_OFFSET)
#define hmu_is_jo_marked(hmu) GETBIT ((hmu)->header, HMU_JO_MB_OFFSET)
#define HMU_SIZE_SIZE 27
#define HMU_SIZE_OFFSET 0
#define HMU_VO_FB_OFFSET 28
#define hmu_is_vo_freed(hmu) GETBIT ((hmu)->header, HMU_VO_FB_OFFSET)
#define hmu_unfree_vo(hmu) CLRBIT ((hmu)->header, HMU_VO_FB_OFFSET)
#define hmu_get_size(hmu) GETBITS ((hmu)->header, HMU_SIZE_OFFSET, HMU_SIZE_SIZE)
#define hmu_set_size(hmu, size) SETBITS ((hmu)->header, HMU_SIZE_OFFSET, HMU_SIZE_SIZE, size)
/*////// HMU free chunk management*/
#define HMU_NORMAL_NODE_CNT 32
#define HMU_FC_NORMAL_MAX_SIZE ((HMU_NORMAL_NODE_CNT - 1) << 3)
#define HMU_IS_FC_NORMAL(size) ((size) < HMU_FC_NORMAL_MAX_SIZE)
#if HMU_FC_NORMAL_MAX_SIZE >= GC_MAX_HEAP_SIZE
#error "Too small GC_MAX_HEAP_SIZE"
#endif
typedef struct _hmu_normal_node
{
hmu_t hmu_header;
struct _hmu_normal_node *next;
}hmu_normal_node_t;
typedef struct _hmu_tree_node
{
hmu_t hmu_header;
gc_size_t size;
struct _hmu_tree_node *left;
struct _hmu_tree_node *right;
struct _hmu_tree_node *parent;
}hmu_tree_node_t;
typedef struct _gc_heap_struct
{
gc_handle_t heap_id; /* for double checking*/
gc_uint8 *base_addr;
gc_size_t current_size;
gc_size_t max_size;
korp_mutex lock;
hmu_normal_node_t kfc_normal_list[HMU_NORMAL_NODE_CNT];
/* order in kfc_tree is: size[left] <= size[cur] < size[right]*/
hmu_tree_node_t kfc_tree_root;
/* for rootset enumeration of private heap*/
void *root_set;
/* whether the fast mode of marking process that requires
additional memory fails. When the fast mode fails, the
marking process can still be done in the slow mode, which
doesn't need additional memory (by walking through all
blocks and marking sucessors of marked nodes until no new
node is marked). TODO: slow mode is not implemented. */
unsigned is_fast_marking_failed : 1;
#if GC_STAT_DATA != 0
gc_size_t highmark_size;
gc_size_t init_size;
gc_size_t total_gc_count;
gc_size_t total_free_size;
gc_size_t gc_threshold;
gc_size_t gc_threshold_factor;
gc_int64 total_gc_time;
#endif
}gc_heap_t;
/*////// MISC internal used APIs*/
extern void gci_add_fc(gc_heap_t *heap, hmu_t *hmu, gc_size_t size);
extern int gci_is_heap_valid(gc_heap_t *heap);
#ifdef GC_DEBUG
extern void gci_verify_heap(gc_heap_t *heap);
extern void gci_dump(char* buf, gc_heap_t *heap);
#endif
#if GC_STAT_DATA != 0
/* the default GC threshold size is free_size * GC_DEFAULT_THRESHOLD_FACTOR / 1000 */
#define GC_DEFAULT_THRESHOLD_FACTOR 400
static inline void gc_update_threshold(gc_heap_t *heap)
{
heap->gc_threshold = heap->total_free_size * heap->gc_threshold_factor / 1000;
}
#endif
/*////// MISC data structures*/
#define MARK_NODE_OBJ_CNT 256
/* mark node is used for gc marker*/
typedef struct _mark_node_struct
{
/* number of to-expand objects can be saved in this node*/
gc_size_t cnt;
/* the first unused index*/
int idx;
/* next node on the node list*/
struct _mark_node_struct *next;
/* the actual to-expand objects list*/
gc_object_t set[MARK_NODE_OBJ_CNT];
}mark_node_t;
/*////// Imported APIs wrappers under TEST mode*/
#ifdef GC_TEST
extern int (*gct_vm_get_java_object_ref_list)(
gc_object_t obj,
int *is_compact_mode, /* can be set to GC_TRUE, or GC_FALSE */
gc_size_t *ref_num,
gc_uint16 **ref_list,
gc_uint32 *ref_start_offset);
extern int (*gct_vm_mutex_init)(korp_mutex *mutex);
extern int (*gct_vm_mutex_destroy)(korp_mutex *mutex);
extern int (*gct_vm_mutex_lock)(korp_mutex *mutex);
extern int (*gct_vm_mutex_unlock)(korp_mutex *mutex);
extern gc_handle_t (*gct_vm_get_gc_handle_for_current_instance)(void);
extern int (*gct_vm_begin_rootset_enumeration)(void* heap);
extern int (*gct_vm_gc_finished)(void);
#else
#define gct_vm_get_java_object_ref_list bh_get_java_object_ref_list
#define gct_vm_mutex_init vm_mutex_init
#define gct_vm_mutex_destroy vm_mutex_destroy
#define gct_vm_mutex_lock vm_mutex_lock
#define gct_vm_mutex_unlock vm_mutex_unlock
#define gct_vm_get_gc_handle_for_current_instance app_manager_get_cur_applet_heap
#define gct_vm_begin_rootset_enumeration vm_begin_rootset_enumeration
#define gct_vm_gc_finished jeff_runtime_gc_finished
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,87 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "ems_gc_internal.h"
#if defined(GC_VERIFY)
/* Set default value to prefix and suffix*/
/* @hmu should not be NULL and it should have been correctly initilized (except for prefix and suffix part)*/
/* @tot_size is offered here because hmu_get_size can not be used till now. @tot_size should not be smaller than OBJ_EXTRA_SIZE.*/
/* For VO, @tot_size should be equal to object total size.*/
void hmu_init_prefix_and_suffix(hmu_t *hmu, gc_size_t tot_size, const char *file_name, int line_no)
{
gc_object_prefix_t *prefix = NULL;
gc_object_suffix_t *suffix = NULL;
gc_uint32 i = 0;
bh_assert(hmu);
bh_assert(hmu_get_ut(hmu) == HMU_JO || hmu_get_ut(hmu) == HMU_VO);
bh_assert(tot_size >= OBJ_EXTRA_SIZE);
bh_assert(!(tot_size & 7));
bh_assert(hmu_get_ut(hmu) != HMU_VO || hmu_get_size(hmu) >= tot_size);
prefix = (gc_object_prefix_t *)(hmu + 1);
suffix = (gc_object_suffix_t *)((gc_uint8*)hmu + tot_size - OBJ_SUFFIX_SIZE);
prefix->file_name = file_name;
prefix->line_no = line_no;
prefix->size = tot_size;
for(i = 0;i < GC_OBJECT_PREFIX_PADDING_CNT;i++)
{
prefix->padding[i] = GC_OBJECT_PADDING_VALUE;
}
for(i = 0;i < GC_OBJECT_SUFFIX_PADDING_CNT;i++)
{
suffix->padding[i] = GC_OBJECT_PADDING_VALUE;
}
}
void hmu_verify(hmu_t *hmu)
{
gc_object_prefix_t *prefix = NULL;
gc_object_suffix_t *suffix = NULL;
gc_uint32 i = 0;
hmu_type_t ut;
gc_size_t size = 0;
int is_padding_ok = 1;
bh_assert(hmu);
ut = hmu_get_ut(hmu);
bh_assert(hmu_is_ut_valid(ut));
prefix = (gc_object_prefix_t *)(hmu + 1);
size = prefix->size;
suffix = (gc_object_suffix_t *)((gc_uint8*)hmu + size - OBJ_SUFFIX_SIZE);
if(ut == HMU_VO || ut == HMU_JO)
{
/* check padding*/
for(i = 0;i < GC_OBJECT_PREFIX_PADDING_CNT;i++)
{
if(prefix->padding[i] != GC_OBJECT_PADDING_VALUE)
{
is_padding_ok = 0;
break;
}
}
for(i = 0;i < GC_OBJECT_SUFFIX_PADDING_CNT;i++)
{
if(suffix->padding[i] != GC_OBJECT_PADDING_VALUE)
{
is_padding_ok = 0;
break;
}
}
if(!is_padding_ok)
{
printf("Invalid padding for object created at %s:%d",
(prefix->file_name ? prefix->file_name : ""), prefix->line_no);
}
bh_assert(is_padding_ok);
}
}
#endif

View File

@ -0,0 +1,182 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "ems_gc_internal.h"
#define HEAP_INC_FACTOR 1
/* Check if current platform is compatible with current GC design*/
/* Return GC_ERROR if not;*/
/* Return GC_SUCCESS otherwise.*/
int gci_check_platform()
{
#define CHECK(x, y) do { \
if((x) != (y)) { \
bh_printf("Platform checking failed on LINE %d at FILE %s.",\
__LINE__, __FILE__); \
return GC_ERROR; \
} \
} while(0)
CHECK(8, sizeof(gc_int64));
CHECK(4, sizeof(gc_uint32));
CHECK(4, sizeof(gc_int32));
CHECK(2, sizeof(gc_uint16));
CHECK(2, sizeof(gc_int16));
CHECK(1, sizeof(gc_int8));
CHECK(1, sizeof(gc_uint8));
CHECK(4, sizeof(gc_size_t));
/*CHECK(4, sizeof(void *));*/
return GC_SUCCESS;
}
gc_handle_t gc_init_with_pool(char *buf, gc_size_t buf_size)
{
char *buf_end = buf + buf_size;
char *buf_aligned = (char*) (((uintptr_t) buf + 7) & (uintptr_t)~7);
char *base_addr = buf_aligned + sizeof(gc_heap_t);
gc_heap_t *heap = (gc_heap_t*) buf_aligned;
gc_size_t heap_max_size;
hmu_normal_node_t *p = NULL;
hmu_tree_node_t *root = NULL, *q = NULL;
int i = 0, ret;
/* check system compatibility*/
if (gci_check_platform() == GC_ERROR) {
bh_printf("Check platform compatibility failed");
return NULL;
}
if (buf_size < 1024) {
bh_printf("[GC_ERROR]heap_init_size(%d) < 1024", buf_size);
return NULL;
}
base_addr = (char*) (((uintptr_t) base_addr + 7) & (uintptr_t)~7) + GC_HEAD_PADDING;
heap_max_size = (uint32)(buf_end - base_addr) & (uint32)~7;
memset(heap, 0, sizeof *heap);
memset(base_addr, 0, heap_max_size);
ret = gct_vm_mutex_init(&heap->lock);
if (ret != BHT_OK) {
bh_printf("[GC_ERROR]failed to init lock ");
return NULL;
}
#ifdef BH_FOOTPRINT
bh_printf("\nINIT HEAP 0x%08x %d\n", base_addr, heap_max_size);
#endif
/* init all data structures*/
heap->max_size = heap_max_size;
heap->current_size = heap_max_size;
heap->base_addr = (gc_uint8*) base_addr;
heap->heap_id = (gc_handle_t) heap;
#if GC_STAT_DATA != 0
heap->total_free_size = heap->current_size;
heap->highmark_size = 0;
heap->total_gc_count = 0;
heap->total_gc_time = 0;
heap->gc_threshold_factor = GC_DEFAULT_THRESHOLD_FACTOR;
gc_update_threshold(heap);
#endif
for (i = 0; i < HMU_NORMAL_NODE_CNT; i++) {
/* make normal node look like a FC*/
p = &heap->kfc_normal_list[i];
memset(p, 0, sizeof *p);
hmu_set_ut(&p->hmu_header, HMU_FC);
hmu_set_size(&p->hmu_header, sizeof *p);
}
root = &heap->kfc_tree_root;
memset(root, 0, sizeof *root);
root->size = sizeof *root;
hmu_set_ut(&root->hmu_header, HMU_FC);
hmu_set_size(&root->hmu_header, sizeof *root);
q = (hmu_tree_node_t *) heap->base_addr;
memset(q, 0, sizeof *q);
hmu_set_ut(&q->hmu_header, HMU_FC);
hmu_set_size(&q->hmu_header, heap->current_size);
hmu_mark_pinuse(&q->hmu_header);
root->right = q;
q->parent = root;
q->size = heap->current_size;
bh_assert(
root->size <= HMU_FC_NORMAL_MAX_SIZE
&& HMU_FC_NORMAL_MAX_SIZE < q->size); /*@NOTIFY*/
#if BH_ENABLE_MEMORY_PROFILING != 0
bh_printf("heap is successfully initialized with max_size=%u.",
heap_max_size);
#endif
return heap;
}
int gc_destroy_with_pool(gc_handle_t handle)
{
gc_heap_t *heap = (gc_heap_t *) handle;
gct_vm_mutex_destroy(&heap->lock);
memset(heap->base_addr, 0, heap->max_size);
memset(heap, 0, sizeof(gc_heap_t));
return GC_SUCCESS;
}
#if defined(GC_VERIFY)
/* Verify heap integrity*/
/* @heap should not be NULL and it should be a valid heap*/
void gci_verify_heap(gc_heap_t *heap)
{
hmu_t *cur = NULL, *end = NULL;
bh_assert(heap && gci_is_heap_valid(heap));
cur = (hmu_t *)heap->base_addr;
end = (hmu_t *)(heap->base_addr + heap->current_size);
while(cur < end)
{
hmu_verify(cur);
cur = (hmu_t *)((gc_uint8*)cur + hmu_get_size(cur));
}
bh_assert(cur == end);
}
#endif
void* gc_heap_stats(void *heap_arg, uint32* stats, int size, gc_mm_t mmt)
{
(void) mmt;
int i;
gc_heap_t *heap = (gc_heap_t *) heap_arg;
for (i = 0; i < size; i++) {
switch (i) {
case GC_STAT_TOTAL:
stats[i] = heap->current_size;
break;
case GC_STAT_FREE:
stats[i] = heap->total_free_size;
break;
case GC_STAT_HIGHMARK:
stats[i] = heap->highmark_size;
break;
case GC_STAT_COUNT:
stats[i] = heap->total_gc_count;
break;
case GC_STAT_TIME:
stats[i] = (uint32)heap->total_gc_time;
break;
default:
break;
}
}
return heap;
}

View File

@ -0,0 +1,125 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "mem_alloc.h"
#include "config.h"
#if DEFAULT_MEM_ALLOCATOR == MEM_ALLOCATOR_EMS
#include "ems/ems_gc.h"
mem_allocator_t mem_allocator_create(void *mem, uint32_t size)
{
return gc_init_with_pool((char *) mem, size);
}
void mem_allocator_destroy(mem_allocator_t allocator)
{
gc_destroy_with_pool((gc_handle_t) allocator);
}
void *
mem_allocator_malloc(mem_allocator_t allocator, uint32_t size)
{
return gc_alloc_vo_h((gc_handle_t) allocator, size);
}
void mem_allocator_free(mem_allocator_t allocator, void *ptr)
{
if (ptr)
gc_free_h((gc_handle_t) allocator, ptr);
}
#else /* else of DEFAULT_MEM_ALLOCATOR */
#include "tlsf/tlsf.h"
#include "bh_thread.h"
typedef struct mem_allocator_tlsf {
tlsf_t tlsf;
korp_mutex lock;
}mem_allocator_tlsf;
mem_allocator_t
mem_allocator_create(void *mem, uint32_t size)
{
mem_allocator_tlsf *allocator_tlsf;
tlsf_t tlsf;
char *mem_aligned = (char*)(((uintptr_t)mem + 3) & ~3);
if (size < 1024) {
printf("Create mem allocator failed: pool size must be "
"at least 1024 bytes.\n");
return NULL;
}
size -= mem_aligned - (char*)mem;
mem = (void*)mem_aligned;
tlsf = tlsf_create_with_pool(mem, size);
if (!tlsf) {
printf("Create mem allocator failed: tlsf_create_with_pool failed.\n");
return NULL;
}
allocator_tlsf = tlsf_malloc(tlsf, sizeof(mem_allocator_tlsf));
if (!allocator_tlsf) {
printf("Create mem allocator failed: tlsf_malloc failed.\n");
tlsf_destroy(tlsf);
return NULL;
}
allocator_tlsf->tlsf = tlsf;
if (vm_mutex_init(&allocator_tlsf->lock)) {
printf("Create mem allocator failed: tlsf_malloc failed.\n");
tlsf_free(tlsf, allocator_tlsf);
tlsf_destroy(tlsf);
return NULL;
}
return allocator_tlsf;
}
void
mem_allocator_destroy(mem_allocator_t allocator)
{
mem_allocator_tlsf *allocator_tlsf = (mem_allocator_tlsf *)allocator;
tlsf_t tlsf = allocator_tlsf->tlsf;
vm_mutex_destroy(&allocator_tlsf->lock);
tlsf_free(tlsf, allocator_tlsf);
tlsf_destroy(tlsf);
}
void *
mem_allocator_malloc(mem_allocator_t allocator, uint32_t size)
{
void *ret;
mem_allocator_tlsf *allocator_tlsf = (mem_allocator_tlsf *)allocator;
if (size == 0)
/* tlsf doesn't allow to allocate 0 byte */
size = 1;
vm_mutex_lock(&allocator_tlsf->lock);
ret = tlsf_malloc(allocator_tlsf->tlsf, size);
vm_mutex_unlock(&allocator_tlsf->lock);
return ret;
}
void
mem_allocator_free(mem_allocator_t allocator, void *ptr)
{
if (ptr) {
mem_allocator_tlsf *allocator_tlsf = (mem_allocator_tlsf *)allocator;
vm_mutex_lock(&allocator_tlsf->lock);
tlsf_free(allocator_tlsf->tlsf, ptr);
vm_mutex_unlock(&allocator_tlsf->lock);
}
}
#endif /* end of DEFAULT_MEM_ALLOCATOR */

View File

@ -0,0 +1,16 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
set (MEM_ALLOC_DIR ${CMAKE_CURRENT_LIST_DIR})
include_directories(${MEM_ALLOC_DIR})
file (GLOB_RECURSE source_all
${MEM_ALLOC_DIR}/ems/*.c
${MEM_ALLOC_DIR}/tlsf/*.c
${MEM_ALLOC_DIR}/mem_alloc.c
${MEM_ALLOC_DIR}/bh_memory.c)
set (MEM_ALLOC_SHARED_SOURCE ${source_all})

View File

@ -0,0 +1,20 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
include_directories (./include ../include ./${WAMR_BUILD_PLATFORM})
add_definitions (-D__POSIX__ -D_XOPEN_SOURCE=600 -D_POSIX_C_SOURCE=200809L -D_BSD_SOURCE)
file (GLOB_RECURSE source_all ${WAMR_BUILD_PLATFORM}/*.c)
add_library (supportlib ${source_all})
target_link_libraries (supportlib -pthread -lrt)
if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
add_library (supportlib_ut ${source_all})
set_target_properties (supportlib_ut PROPERTIES COMPILE_DEFINITIONS BH_TEST=1)
target_link_libraries (supportlib_ut -pthread -lrt)
endif ()

View File

@ -0,0 +1,4 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
obj-y += zephyr/

View File

@ -0,0 +1,126 @@
# $FreeBSD$
# @(#)COPYRIGHT 8.2 (Berkeley) 3/21/94
The compilation of software known as FreeBSD is distributed under the
following terms:
Copyright (c) 1992-2019 The FreeBSD Project.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
The 4.4BSD and 4.4BSD-Lite software is distributed under the following
terms:
All of the documentation and software included in the 4.4BSD and 4.4BSD-Lite
Releases is copyrighted by The Regents of the University of California.
Copyright 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994
The Regents of the University of California. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. All advertising materials mentioning features or use of this software
must display the following acknowledgement:
This product includes software developed by the University of
California, Berkeley and its contributors.
4. Neither the name of the University nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
The Institute of Electrical and Electronics Engineers and the American
National Standards Committee X3, on Information Processing Systems have
given us permission to reprint portions of their documentation.
In the following statement, the phrase ``this text'' refers to portions
of the system documentation.
Portions of this text are reprinted and reproduced in electronic form in
the second BSD Networking Software Release, from IEEE Std 1003.1-1988, IEEE
Standard Portable Operating System Interface for Computer Environments
(POSIX), copyright C 1988 by the Institute of Electrical and Electronics
Engineers, Inc. In the event of any discrepancy between these versions
and the original IEEE Standard, the original IEEE Standard is the referee
document.
In the following statement, the phrase ``This material'' refers to portions
of the system documentation.
This material is reproduced with permission from American National
Standards Committee X3, on Information Processing Systems. Computer and
Business Equipment Manufacturers Association (CBEMA), 311 First St., NW,
Suite 500, Washington, DC 20001-2178. The developmental work of
Programming Language C was completed by the X3J11 Technical Committee.
The views and conclusions contained in the software and documentation are
those of the authors and should not be interpreted as representing official
policies, either expressed or implied, of the Regents of the University
of California.
NOTE: The copyright of UC Berkeley's Berkeley Software Distribution ("BSD")
source has been updated. The copyright addendum may be found at
ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change and is
included below.
July 22, 1999
To All Licensees, Distributors of Any Version of BSD:
As you know, certain of the Berkeley Software Distribution ("BSD") source
code files require that further distributions of products containing all or
portions of the software, acknowledge within their advertising materials
that such products contain software developed by UC Berkeley and its
contributors.
Specifically, the provision reads:
" * 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors."
Effective immediately, licensees and distributors are no longer required to
include the acknowledgement within advertising materials. Accordingly, the
foregoing paragraph of those BSD Unix files containing it is hereby deleted
in its entirety.
William Hoskins
Director, Office of Technology Licensing
University of California, Berkeley

View File

@ -0,0 +1,52 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_platform.h"
#include "bh_assert.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef BH_TEST
#include <setjmp.h>
#endif
#ifdef BH_TEST
/* for exception throwing */
jmp_buf bh_test_jb;
#endif
void bh_assert_internal(int v, const char *file_name, int line_number, const char *expr_string)
{
if(v) return;
if(!file_name) file_name = "NULL FILENAME";
if(!expr_string) expr_string = "NULL EXPR_STRING";
printf("\nASSERTION FAILED: %s, at FILE=%s, LINE=%d\n", expr_string, file_name, line_number);
#ifdef BH_TEST
longjmp(bh_test_jb, 1);
#endif
aos_reboot();
}
void bh_debug_internal(const char *file_name, int line_number, const char *fmt, ...)
{
#ifndef JEFF_TEST_VERIFIER
va_list args;
va_start(args, fmt);
bh_assert(file_name);
printf("\nDebug info FILE=%s, LINE=%d: ", file_name, line_number);
vprintf(fmt, args);
va_end(args);
printf("\n");
#endif
}

View File

@ -0,0 +1,53 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_platform.h"
#define RSIZE_MAX 0x7FFFFFFF
int b_memcpy_s(void * s1, unsigned int s1max,
const void * s2, unsigned int n)
{
char *dest = (char*)s1;
char *src = (char*)s2;
if (n == 0) {
return 0;
}
if (s1 == NULL || s1max > RSIZE_MAX) {
return -1;
}
if (s2 == NULL || n > s1max) {
memset(dest, 0, s1max);
return -1;
}
memcpy(dest, src, n);
return 0;
}
int b_strcat_s(char * s1, size_t s1max, const char * s2)
{
if (NULL == s1 || NULL == s2
|| s1max < (strlen(s1) + strlen(s2) + 1)
|| s1max > RSIZE_MAX) {
return -1;
}
strcat(s1, s2);
return 0;
}
int b_strcpy_s(char * s1, size_t s1max, const char * s2)
{
if (NULL == s1 || NULL == s2
|| s1max < (strlen(s2) + 1)
|| s1max > RSIZE_MAX) {
return -1;
}
strcpy(s1, s2);
return 0;
}

View File

@ -0,0 +1,861 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include "bh_platform.h"
#define __FDLIBM_STDC__
typedef uint32_t u_int32_t;
typedef uint64_t u_int64_t;
typedef union u32double_tag {
int *pint;
double *pdouble;
} U32DOUBLE;
static inline int *
pdouble2pint(double *pdouble)
{
U32DOUBLE u;
u.pdouble = pdouble;
return u.pint;
}
typedef union
{
double value;
struct
{
u_int32_t lsw;
u_int32_t msw;
} parts;
struct
{
u_int64_t w;
} xparts;
} ieee_double_shape_type_little;
typedef union
{
double value;
struct
{
u_int32_t msw;
u_int32_t lsw;
} parts;
struct
{
u_int64_t w;
} xparts;
} ieee_double_shape_type_big;
typedef union {
double d;
struct {
unsigned int manl :32;
unsigned int manh :20;
unsigned int exp :11;
unsigned int sign :1;
} bits;
} IEEEd2bits_L;
typedef union {
double d;
struct {
unsigned int sign :1;
unsigned int exp :11;
unsigned int manh :20;
unsigned int manl :32;
} bits;
} IEEEd2bits_B;
typedef union {
float f;
struct {
unsigned int man :23;
unsigned int exp :8;
unsigned int sign :1;
} bits;
} IEEEf2bits_L;
typedef union {
float f;
struct {
unsigned int sign :1;
unsigned int exp :8;
unsigned int man :23;
} bits;
} IEEEf2bits_B;
static union {
int a;
char b;
} __ue = { .a = 1 };
#define is_little_endian() (__ue.b == 1)
#define __HIL(x) *(1+pdouble2pint(&x))
#define __LOL(x) *(pdouble2pint(&x))
#define __HIB(x) *(int*)&x
#define __LOB(x) *(1+(int*)&x)
/* Get two 32 bit ints from a double. */
#define EXTRACT_WORDS_L(ix0,ix1,d) \
do { \
ieee_double_shape_type_little ew_u; \
ew_u.value = (d); \
(ix0) = ew_u.parts.msw; \
(ix1) = ew_u.parts.lsw; \
} while (0)
/* Set a double from two 32 bit ints. */
#define INSERT_WORDS_L(d,ix0,ix1) \
do { \
ieee_double_shape_type_little iw_u; \
iw_u.parts.msw = (ix0); \
iw_u.parts.lsw = (ix1); \
(d) = iw_u.value; \
} while (0)
/* Get two 32 bit ints from a double. */
#define EXTRACT_WORDS_B(ix0,ix1,d) \
do { \
ieee_double_shape_type_big ew_u; \
ew_u.value = (d); \
(ix0) = ew_u.parts.msw; \
(ix1) = ew_u.parts.lsw; \
} while (0)
/* Set a double from two 32 bit ints. */
#define INSERT_WORDS_B(d,ix0,ix1) \
do { \
ieee_double_shape_type_big iw_u; \
iw_u.parts.msw = (ix0); \
iw_u.parts.lsw = (ix1); \
(d) = iw_u.value; \
} while (0)
/* Get the more significant 32 bit int from a double. */
#define GET_HIGH_WORD_L(i,d) \
do { \
ieee_double_shape_type_little gh_u; \
gh_u.value = (d); \
(i) = gh_u.parts.msw; \
} while (0)
/* Get the more significant 32 bit int from a double. */
#define GET_HIGH_WORD_B(i,d) \
do { \
ieee_double_shape_type_big gh_u; \
gh_u.value = (d); \
(i) = gh_u.parts.msw; \
} while (0)
/* Set the more significant 32 bits of a double from an int. */
#define SET_HIGH_WORD_L(d,v) \
do { \
ieee_double_shape_type_little sh_u; \
sh_u.value = (d); \
sh_u.parts.msw = (v); \
(d) = sh_u.value; \
} while (0)
/* Set the more significant 32 bits of a double from an int. */
#define SET_HIGH_WORD_B(d,v) \
do { \
ieee_double_shape_type_big sh_u; \
sh_u.value = (d); \
sh_u.parts.msw = (v); \
(d) = sh_u.value; \
} while (0)
/*
* A union which permits us to convert between a float and a 32 bit
* int.
*/
typedef union
{
float value;
/* FIXME: Assumes 32 bit int. */
unsigned int word;
} ieee_float_shape_type;
/* Get a 32 bit int from a float. */
#define GET_FLOAT_WORD(i,d) \
do { \
ieee_float_shape_type gf_u; \
gf_u.value = (d); \
(i) = gf_u.word; \
} while (0)
/* Set a float from a 32 bit int. */
#define SET_FLOAT_WORD(d,i) \
do { \
ieee_float_shape_type sf_u; \
sf_u.word = (i); \
(d) = sf_u.value; \
} while (0)
/* Macro wrappers. */
#define EXTRACT_WORDS(ix0,ix1,d) do { \
if (is_little_endian()) \
EXTRACT_WORDS_L(ix0,ix1,d); \
else \
EXTRACT_WORDS_B(ix0,ix1,d); \
} while (0)
#define INSERT_WORDS(d,ix0,ix1) do { \
if (is_little_endian()) \
INSERT_WORDS_L(d,ix0,ix1); \
else \
INSERT_WORDS_B(d,ix0,ix1); \
} while (0)
#define GET_HIGH_WORD(i,d) \
do { \
if (is_little_endian()) \
GET_HIGH_WORD_L(i,d); \
else \
GET_HIGH_WORD_B(i,d); \
} while (0)
#define SET_HIGH_WORD(d,v) \
do { \
if (is_little_endian()) \
SET_HIGH_WORD_L(d,v); \
else \
SET_HIGH_WORD_B(d,v); \
} while (0)
#define __HI(x) (is_little_endian() ? __HIL(x) : __HIB(x))
#define __LO(x) (is_little_endian() ? __LOL(x) : __LOB(x))
/*
* Attempt to get strict C99 semantics for assignment with non-C99 compilers.
*/
#if FLT_EVAL_METHOD == 0 || __GNUC__ == 0
#define STRICT_ASSIGN(type, lval, rval) ((lval) = (rval))
#else
#define STRICT_ASSIGN(type, lval, rval) do { \
volatile type __lval; \
\
if (sizeof(type) >= sizeof(long double)) \
(lval) = (rval); \
else { \
__lval = (rval); \
(lval) = __lval; \
} \
} while (0)
#endif
#ifdef __FDLIBM_STDC__
static const double huge = 1.0e300;
#else
static double huge = 1.0e300;
#endif
#ifdef __STDC__
static const double
#else
static double
#endif
tiny = 1.0e-300;
#ifdef __STDC__
static const double
#else
static double
#endif
one= 1.00000000000000000000e+00; /* 0x3FF00000, 0x00000000 */
#ifdef __STDC__
static const double
#else
static double
#endif
TWO52[2]={
4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
-4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */
};
static double freebsd_sqrt(double x);
static double freebsd_floor(double x);
static double freebsd_ceil(double x);
static double freebsd_fabs(double x);
static double freebsd_rint(double x);
static int freebsd_isnan(double x);
static double freebsd_sqrt(double x) /* wrapper sqrt */
{
double z;
int32_t sign = (int)0x80000000;
int32_t ix0,s0,q,m,t,i;
u_int32_t r,t1,s1,ix1,q1;
EXTRACT_WORDS(ix0,ix1,x);
/* take care of Inf and NaN */
if((ix0&0x7ff00000)==0x7ff00000) {
return x*x+x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf
sqrt(-inf)=sNaN */
}
/* take care of zero */
if(ix0<=0) {
if(((ix0&(~sign))|ix1)==0) return x;/* sqrt(+-0) = +-0 */
else if(ix0<0)
return (x-x)/(x-x); /* sqrt(-ve) = sNaN */
}
/* normalize x */
m = (ix0>>20);
if(m==0) { /* subnormal x */
while(ix0==0) {
m -= 21;
ix0 |= (ix1>>11); ix1 <<= 21;
}
for(i=0;(ix0&0x00100000)==0;i++) ix0<<=1;
m -= i-1;
ix0 |= (ix1>>(32-i));
ix1 <<= i;
}
m -= 1023; /* unbias exponent */
ix0 = (ix0&0x000fffff)|0x00100000;
if(m&1){ /* odd m, double x to make it even */
ix0 += ix0 + ((ix1&sign)>>31);
ix1 += ix1;
}
m >>= 1; /* m = [m/2] */
/* generate sqrt(x) bit by bit */
ix0 += ix0 + ((ix1&sign)>>31);
ix1 += ix1;
q = q1 = s0 = s1 = 0; /* [q,q1] = sqrt(x) */
r = 0x00200000; /* r = moving bit from right to left */
while(r!=0) {
t = s0+r;
if(t<=ix0) {
s0 = t+r;
ix0 -= t;
q += r;
}
ix0 += ix0 + ((ix1&sign)>>31);
ix1 += ix1;
r>>=1;
}
r = sign;
while(r!=0) {
t1 = s1+r;
t = s0;
if((t<ix0)||((t==ix0)&&(t1<=ix1))) {
s1 = t1+r;
if(((t1&sign)==sign)&&(s1&sign)==0) s0 += 1;
ix0 -= t;
if (ix1 < t1) ix0 -= 1;
ix1 -= t1;
q1 += r;
}
ix0 += ix0 + ((ix1&sign)>>31);
ix1 += ix1;
r>>=1;
}
/* use floating add to find out rounding direction */
if((ix0|ix1)!=0) {
z = one-tiny; /* trigger inexact flag */
if (z>=one) {
z = one+tiny;
if (q1==(u_int32_t)0xffffffff) { q1=0; q += 1;}
else if (z>one) {
if (q1==(u_int32_t)0xfffffffe) q+=1;
q1+=2;
} else
q1 += (q1&1);
}
}
ix0 = (q>>1)+0x3fe00000;
ix1 = q1>>1;
if ((q&1)==1) ix1 |= sign;
ix0 += (m <<20);
INSERT_WORDS(z,ix0,ix1);
return z;
}
static double freebsd_floor(double x)
{
int32_t i0,i1,j0;
u_int32_t i,j;
EXTRACT_WORDS(i0,i1,x);
j0 = ((i0>>20)&0x7ff)-0x3ff;
if(j0<20) {
if(j0<0) { /* raise inexact if x != 0 */
if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */
if(i0>=0) {i0=i1=0;}
else if(((i0&0x7fffffff)|i1)!=0)
{ i0=0xbff00000;i1=0;}
}
} else {
i = (0x000fffff)>>j0;
if(((i0&i)|i1)==0) return x; /* x is integral */
if(huge+x>0.0) { /* raise inexact flag */
if(i0<0) i0 += (0x00100000)>>j0;
i0 &= (~i); i1=0;
}
}
} else if (j0>51) {
if(j0==0x400) return x+x; /* inf or NaN */
else return x; /* x is integral */
} else {
i = ((u_int32_t)(0xffffffff))>>(j0-20);
if((i1&i)==0) return x; /* x is integral */
if(huge+x>0.0) { /* raise inexact flag */
if(i0<0) {
if(j0==20) i0+=1;
else {
j = i1+(1<<(52-j0));
if(j<i1) i0 +=1 ; /* got a carry */
i1=j;
}
}
i1 &= (~i);
}
}
INSERT_WORDS(x,i0,i1);
return x;
}
static double freebsd_ceil(double x)
{
int32_t i0,i1,j0;
u_int32_t i,j;
EXTRACT_WORDS(i0,i1,x);
j0 = ((i0>>20)&0x7ff)-0x3ff;
if(j0<20) {
if(j0<0) { /* raise inexact if x != 0 */
if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */
if(i0<0) {i0=0x80000000;i1=0;}
else if((i0|i1)!=0) { i0=0x3ff00000;i1=0;}
}
} else {
i = (0x000fffff)>>j0;
if(((i0&i)|i1)==0) return x; /* x is integral */
if(huge+x>0.0) { /* raise inexact flag */
if(i0>0) i0 += (0x00100000)>>j0;
i0 &= (~i); i1=0;
}
}
} else if (j0>51) {
if(j0==0x400) return x+x; /* inf or NaN */
else return x; /* x is integral */
} else {
i = ((u_int32_t)(0xffffffff))>>(j0-20);
if((i1&i)==0) return x; /* x is integral */
if(huge+x>0.0) { /* raise inexact flag */
if(i0>0) {
if(j0==20) i0+=1;
else {
j = i1 + (1<<(52-j0));
if(j<i1) i0+=1; /* got a carry */
i1 = j;
}
}
i1 &= (~i);
}
}
INSERT_WORDS(x,i0,i1);
return x;
}
static double freebsd_rint(double x)
{
int32_t i0,j0,sx;
u_int32_t i,i1;
double w,t;
EXTRACT_WORDS(i0,i1,x);
sx = (i0>>31)&1;
j0 = ((i0>>20)&0x7ff)-0x3ff;
if(j0<20) {
if(j0<0) {
if(((i0&0x7fffffff)|i1)==0) return x;
i1 |= (i0&0x0fffff);
i0 &= 0xfffe0000;
i0 |= ((i1|-i1)>>12)&0x80000;
SET_HIGH_WORD(x,i0);
STRICT_ASSIGN(double,w,TWO52[sx]+x);
t = w-TWO52[sx];
GET_HIGH_WORD(i0,t);
SET_HIGH_WORD(t,(i0&0x7fffffff)|(sx<<31));
return t;
} else {
i = (0x000fffff)>>j0;
if(((i0&i)|i1)==0) return x; /* x is integral */
i>>=1;
if(((i0&i)|i1)!=0) {
/*
* Some bit is set after the 0.5 bit. To avoid the
* possibility of errors from double rounding in
* w = TWO52[sx]+x, adjust the 0.25 bit to a lower
* guard bit. We do this for all j0<=51. The
* adjustment is trickiest for j0==18 and j0==19
* since then it spans the word boundary.
*/
if(j0==19) i1 = 0x40000000; else
if(j0==18) i1 = 0x80000000; else
i0 = (i0&(~i))|((0x20000)>>j0);
}
}
} else if (j0>51) {
if(j0==0x400) return x+x; /* inf or NaN */
else return x; /* x is integral */
} else {
i = ((u_int32_t)(0xffffffff))>>(j0-20);
if((i1&i)==0) return x; /* x is integral */
i>>=1;
if((i1&i)!=0) i1 = (i1&(~i))|((0x40000000)>>(j0-20));
}
INSERT_WORDS(x,i0,i1);
STRICT_ASSIGN(double,w,TWO52[sx]+x);
return w-TWO52[sx];
}
static int freebsd_isnan(double d)
{
if (is_little_endian()) {
IEEEd2bits_L u;
u.d = d;
return (u.bits.exp == 2047 && (u.bits.manl != 0 || u.bits.manh != 0));
}
else {
IEEEd2bits_B u;
u.d = d;
return (u.bits.exp == 2047 && (u.bits.manl != 0 || u.bits.manh != 0));
}
}
static double freebsd_fabs(double x)
{
u_int32_t high;
GET_HIGH_WORD(high,x);
SET_HIGH_WORD(x,high&0x7fffffff);
return x;
}
static const float huge_f = 1.0e30F;
static const float
TWO23[2]={
8.3886080000e+06, /* 0x4b000000 */
-8.3886080000e+06, /* 0xcb000000 */
};
static float
freebsd_truncf(float x)
{
int32_t i0,j0;
u_int32_t i;
GET_FLOAT_WORD(i0,x);
j0 = ((i0>>23)&0xff)-0x7f;
if(j0<23) {
if(j0<0) { /* raise inexact if x != 0 */
if(huge_f+x>0.0F) /* |x|<1, so return 0*sign(x) */
i0 &= 0x80000000;
} else {
i = (0x007fffff)>>j0;
if((i0&i)==0) return x; /* x is integral */
if(huge_f+x>0.0F) /* raise inexact flag */
i0 &= (~i);
}
} else {
if(j0==0x80) return x+x; /* inf or NaN */
else return x; /* x is integral */
}
SET_FLOAT_WORD(x,i0);
return x;
}
static float
freebsd_rintf(float x)
{
int32_t i0,j0,sx;
float w,t;
GET_FLOAT_WORD(i0,x);
sx = (i0>>31)&1;
j0 = ((i0>>23)&0xff)-0x7f;
if(j0<23) {
if(j0<0) {
if((i0&0x7fffffff)==0) return x;
STRICT_ASSIGN(float,w,TWO23[sx]+x);
t = w-TWO23[sx];
GET_FLOAT_WORD(i0,t);
SET_FLOAT_WORD(t,(i0&0x7fffffff)|(sx<<31));
return t;
}
STRICT_ASSIGN(float,w,TWO23[sx]+x);
return w-TWO23[sx];
}
if(j0==0x80) return x+x; /* inf or NaN */
else return x; /* x is integral */
}
static float
freebsd_ceilf(float x)
{
int32_t i0,j0;
u_int32_t i;
GET_FLOAT_WORD(i0,x);
j0 = ((i0>>23)&0xff)-0x7f;
if(j0<23) {
if(j0<0) { /* raise inexact if x != 0 */
if(huge_f+x>(float)0.0) {/* return 0*sign(x) if |x|<1 */
if(i0<0) {i0=0x80000000;}
else if(i0!=0) { i0=0x3f800000;}
}
} else {
i = (0x007fffff)>>j0;
if((i0&i)==0) return x; /* x is integral */
if(huge_f+x>(float)0.0) { /* raise inexact flag */
if(i0>0) i0 += (0x00800000)>>j0;
i0 &= (~i);
}
}
} else {
if(j0==0x80) return x+x; /* inf or NaN */
else return x; /* x is integral */
}
SET_FLOAT_WORD(x,i0);
return x;
}
static float
freebsd_floorf(float x)
{
int32_t i0,j0;
u_int32_t i;
GET_FLOAT_WORD(i0,x);
j0 = ((i0>>23)&0xff)-0x7f;
if(j0<23) {
if(j0<0) { /* raise inexact if x != 0 */
if(huge_f+x>(float)0.0) {/* return 0*sign(x) if |x|<1 */
if(i0>=0) {i0=0;}
else if((i0&0x7fffffff)!=0)
{ i0=0xbf800000;}
}
} else {
i = (0x007fffff)>>j0;
if((i0&i)==0) return x; /* x is integral */
if(huge_f+x>(float)0.0) { /* raise inexact flag */
if(i0<0) i0 += (0x00800000)>>j0;
i0 &= (~i);
}
}
} else {
if(j0==0x80) return x+x; /* inf or NaN */
else return x; /* x is integral */
}
SET_FLOAT_WORD(x,i0);
return x;
}
static float
freebsd_fminf(float x, float y)
{
if (is_little_endian()) {
IEEEf2bits_L u[2];
u[0].f = x;
u[1].f = y;
/* Check for NaNs to avoid raising spurious exceptions. */
if (u[0].bits.exp == 255 && u[0].bits.man != 0)
return (y);
if (u[1].bits.exp == 255 && u[1].bits.man != 0)
return (x);
/* Handle comparisons of signed zeroes. */
if (u[0].bits.sign != u[1].bits.sign)
return (u[u[1].bits.sign].f);
}
else {
IEEEf2bits_B u[2];
u[0].f = x;
u[1].f = y;
/* Check for NaNs to avoid raising spurious exceptions. */
if (u[0].bits.exp == 255 && u[0].bits.man != 0)
return (y);
if (u[1].bits.exp == 255 && u[1].bits.man != 0)
return (x);
/* Handle comparisons of signed zeroes. */
if (u[0].bits.sign != u[1].bits.sign)
return (u[u[1].bits.sign].f);
}
return (x < y ? x : y);
}
static float
freebsd_fmaxf(float x, float y)
{
if (is_little_endian()) {
IEEEf2bits_L u[2];
u[0].f = x;
u[1].f = y;
/* Check for NaNs to avoid raising spurious exceptions. */
if (u[0].bits.exp == 255 && u[0].bits.man != 0)
return (y);
if (u[1].bits.exp == 255 && u[1].bits.man != 0)
return (x);
/* Handle comparisons of signed zeroes. */
if (u[0].bits.sign != u[1].bits.sign)
return (u[u[0].bits.sign].f);
}
else {
IEEEf2bits_B u[2];
u[0].f = x;
u[1].f = y;
/* Check for NaNs to avoid raising spurious exceptions. */
if (u[0].bits.exp == 255 && u[0].bits.man != 0)
return (y);
if (u[1].bits.exp == 255 && u[1].bits.man != 0)
return (x);
/* Handle comparisons of signed zeroes. */
if (u[0].bits.sign != u[1].bits.sign)
return (u[u[0].bits.sign].f);
}
return (x > y ? x : y);
}
double sqrt(double x)
{
return freebsd_sqrt(x);
}
double floor(double x)
{
return freebsd_floor(x);
}
double ceil(double x)
{
return freebsd_ceil(x);
}
double fmin(double x, double y)
{
return x < y ? x : y;
}
double fmax(double x, double y)
{
return x > y ? x : y;
}
double rint(double x)
{
return freebsd_rint(x);
}
double fabs(double x)
{
return freebsd_fabs(x);
}
int isnan(double x)
{
return freebsd_isnan(x);
}
double trunc(double x)
{
return (x > 0) ? freebsd_floor(x) : freebsd_ceil(x);
}
int signbit(double x)
{
return ((__HI(x) & 0x80000000) >> 31);
}
float
truncf(float x)
{
return freebsd_truncf(x);
}
float
rintf(float x)
{
return freebsd_rintf(x);
}
float
ceilf(float x)
{
return freebsd_ceilf(x);
}
float
floorf(float x)
{
return freebsd_floorf(x);
}
float
fminf(float x, float y)
{
return freebsd_fminf(x, y);
}
float
fmaxf(float x, float y)
{
return freebsd_fmaxf(x, y);
}

View File

@ -0,0 +1,47 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_platform.h"
#include "bh_memory.h"
#include "bh_common.h"
#include <stdlib.h>
#include <string.h>
char *bh_strdup(const char *s)
{
uint32 size;
char *s1 = NULL;
if (s) {
size = (uint32)(strlen(s) + 1);
if ((s1 = bh_malloc(size)))
bh_memcpy_s(s1, size, s, size);
}
return s1;
}
int bh_platform_init()
{
return 0;
}
void *
bh_mmap(void *hint, unsigned int size, int prot, int flags)
{
return bh_malloc(size);
}
void
bh_munmap(void *addr, uint32 size)
{
return bh_free(addr);
}
int
bh_mprotect(void *addr, uint32 size, int prot)
{
return 0;
}

View File

@ -0,0 +1,135 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _BH_PLATFORM_H
#define _BH_PLATFORM_H
#include "bh_config.h"
#include "bh_types.h"
#include "bh_memory.h"
#include <aos/kernel.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdarg.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef BH_PLATFORM_ALIOS_THINGS
#define BH_PLATFORM_ALIOS_THINGS
#endif
#define BH_APPLET_PRESERVED_STACK_SIZE (2 * BH_KB)
/* Default thread priority */
#define BH_THREAD_DEFAULT_PRIORITY 30
#define BH_ROUTINE_MODIFIER
/* Invalid thread tid */
#define INVALID_THREAD_ID NULL
#define BH_WAIT_FOREVER AOS_WAIT_FOREVER
typedef uint64_t uint64;
typedef int64_t int64;
#define wa_malloc bh_malloc
#define wa_free bh_free
#define wa_strdup bh_strdup
typedef aos_task_t korp_thread;
typedef korp_thread *korp_tid;
typedef aos_task_t *aos_tid_t;
typedef aos_mutex_t korp_mutex;
typedef aos_sem_t korp_sem;
struct bh_thread_wait_node;
typedef struct bh_thread_wait_node *bh_thread_wait_list;
typedef struct korp_cond {
aos_mutex_t wait_list_lock;
bh_thread_wait_list thread_wait_list;
} korp_cond;
typedef void* (*thread_start_routine_t)(void*);
/* Unit test framework is based on C++, where the declaration of
snprintf is different. */
#ifndef __cplusplus
int snprintf(char *buffer, size_t count, const char *format, ...);
#endif
#ifndef NULL
#define NULL ((void*)0)
#endif
/**
* Return the offset of the given field in the given type.
*
* @param Type the type containing the filed
* @param field the field in the type
*
* @return the offset of field in Type
*/
#ifndef offsetof
#define offsetof(Type, field) ((size_t)(&((Type *)0)->field))
#endif
#define bh_printf printf
extern void bh_assert_internal(int v, const char *file_name, int line_number, const char *expr_string);
#define bh_assert(expr) bh_assert_internal((int)(expr), __FILE__, __LINE__, # expr)
extern int b_memcpy_s(void * s1, unsigned int s1max, const void * s2, unsigned int n);
extern int b_strcat_s(char * s1, size_t s1max, const char * s2);
extern int b_strcpy_s(char * s1, size_t s1max, const char * s2);
/* math functions */
double sqrt(double x);
double floor(double x);
double ceil(double x);
double fmin(double x, double y);
double fmax(double x, double y);
double rint(double x);
double fabs(double x);
double trunc(double x);
float floorf(float x);
float ceilf(float x);
float fminf(float x, float y);
float fmaxf(float x, float y);
float rintf(float x);
float truncf(float x);
int signbit(double x);
int isnan(double x);
int bh_platform_init();
/* MMAP mode */
enum {
MMAP_PROT_NONE = 0,
MMAP_PROT_READ = 1,
MMAP_PROT_WRITE = 2,
MMAP_PROT_EXEC = 4
};
/* MMAP flags */
enum {
MMAP_MAP_NONE = 0,
/* Put the mapping into 0 to 2 G, supported only on x86_64 */
MMAP_MAP_32BIT = 1,
/* Don't interpret addr as a hint: place the mapping at exactly
that address. */
MMAP_MAP_FIXED = 2
};
void *bh_mmap(void *hint, unsigned int size, int prot, int flags);
void bh_munmap(void *addr, uint32 size);
int bh_mprotect(void *addr, uint32 size, int prot);
#endif /* end of _BH_PLATFORM_H */

View File

@ -0,0 +1,33 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_platform.h"
#include <stdio.h>
void bh_log_emit(const char *fmt, va_list ap)
{
vprintf(fmt, ap);
}
int bh_fprintf(FILE *stream, const char *fmt, ...)
{
(void)stream;
va_list ap;
int ret;
va_start(ap, fmt);
ret = vprintf(fmt, ap);
va_end(ap);
return ret;
}
int bh_fflush(void *stream)
{
(void)stream;
return 0;
}

View File

@ -0,0 +1,436 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_thread.h"
#include "bh_assert.h"
#include "bh_log.h"
#include "bh_memory.h"
#include <stdio.h>
#include <stdlib.h>
struct bh_thread_data;
typedef struct bh_thread_wait_node {
aos_sem_t sem;
bh_thread_wait_list next;
} bh_thread_wait_node;
typedef struct bh_thread_data {
/* Thread body */
aos_task_t thread;
/* Thread start routine */
thread_start_routine_t start_routine;
/* Thread start routine argument */
void *arg;
/* Thread local root */
void *tlr;
/* Wait node of current thread */
bh_thread_wait_node wait_node;
/* Lock for waiting list */
aos_mutex_t wait_list_lock;
/* Waiting list of other threads who are joining this thread */
bh_thread_wait_list thread_wait_list;
} bh_thread_data;
static bool is_thread_sys_inited = false;
/* Thread data of supervisor thread */
static bh_thread_data supervisor_thread_data;
/* Thread data key */
static aos_task_key_t thread_data_key;
/* Thread name index */
static int thread_name_index;
int
_vm_thread_sys_init()
{
if (is_thread_sys_inited)
return BHT_OK;
if (aos_task_key_create(&thread_data_key) != 0)
return BHT_ERROR;
/* Initialize supervisor thread data */
memset(&supervisor_thread_data, 0, sizeof(supervisor_thread_data));
if (aos_sem_new(&supervisor_thread_data.wait_node.sem, 1) != 0) {
aos_task_key_delete(thread_data_key);
return BHT_ERROR;
}
if (aos_task_setspecific(thread_data_key, &supervisor_thread_data)) {
aos_sem_free(&supervisor_thread_data.wait_node.sem);
aos_task_key_delete(thread_data_key);
return BHT_ERROR;
}
is_thread_sys_inited = true;
return BHT_OK;
}
void
vm_thread_sys_destroy()
{
if (is_thread_sys_inited) {
aos_task_key_delete(thread_data_key);
aos_sem_free(&supervisor_thread_data.wait_node.sem);
is_thread_sys_inited = false;
}
}
static bh_thread_data *
thread_data_current()
{
return aos_task_getspecific(thread_data_key);
}
static void
vm_thread_cleanup(void)
{
bh_thread_data *thread_data = thread_data_current();
bh_thread_wait_list thread_wait_list;
aos_mutex_t *wait_list_lock;
aos_sem_t *wait_node_sem;
bh_assert(thread_data != NULL);
wait_list_lock = &thread_data->wait_list_lock;
thread_wait_list = thread_data->thread_wait_list;
wait_node_sem = &thread_data->wait_node.sem;
/* Free thread data firstly */
bh_free(thread_data);
aos_mutex_lock(wait_list_lock, AOS_WAIT_FOREVER);
if (thread_wait_list) {
/* Signal each joining thread */
bh_thread_wait_list head = thread_wait_list;
while (head) {
bh_thread_wait_list next = head->next;
aos_sem_signal(&head->sem);
head = next;
}
}
aos_mutex_unlock(wait_list_lock);
/* Free sem and lock */
aos_sem_free(wait_node_sem);
aos_mutex_free(wait_list_lock);
}
static void
vm_thread_wrapper(void *arg)
{
bh_thread_data *thread_data = arg;
/* Set thread custom data */
if (!aos_task_setspecific(thread_data_key, thread_data))
thread_data->start_routine(thread_data->arg);
vm_thread_cleanup();
}
int
_vm_thread_create(korp_tid *p_tid, thread_start_routine_t start,
void *arg, unsigned int stack_size)
{
return _vm_thread_create_with_prio(p_tid, start, arg, stack_size,
BH_THREAD_DEFAULT_PRIORITY);
}
int
_vm_thread_create_with_prio(korp_tid *p_tid, thread_start_routine_t start,
void *arg, unsigned int stack_size, int prio)
{
bh_thread_data *thread_data;
char thread_name[32];
if (!p_tid || !stack_size)
return BHT_ERROR;
/* Create and initialize thread data */
if (!(thread_data = bh_malloc(sizeof(bh_thread_data))))
return BHT_ERROR;
memset(thread_data, 0, sizeof(bh_thread_data));
thread_data->start_routine = start;
thread_data->arg = arg;
if (aos_sem_new(&thread_data->wait_node.sem, 1) != 0)
goto fail1;
if (aos_mutex_new(&thread_data->wait_list_lock))
goto fail2;
snprintf(thread_name, sizeof(thread_name), "%s%d",
"wasm-thread-", ++thread_name_index);
/* Create the thread */
if (aos_task_new_ext((aos_task_t*)thread_data, thread_name,
vm_thread_wrapper, thread_data,
stack_size, prio))
goto fail3;
aos_msleep(10);
*p_tid = (korp_tid)thread_data;
return BHT_OK;
fail3:
aos_mutex_free(&thread_data->wait_list_lock);
fail2:
aos_sem_free(&thread_data->wait_node.sem);
fail1:
bh_free(thread_data);
return BHT_ERROR;
}
korp_tid
_vm_self_thread()
{
return (korp_tid)aos_task_getspecific(thread_data_key);
}
void
vm_thread_exit(void * code)
{
vm_thread_cleanup();
aos_task_exit((int)(intptr_t)code);
}
int
_vm_thread_cancel (korp_tid thread)
{
/* TODO */
return 0;
}
int
_vm_thread_join (korp_tid thread, void **value_ptr, int mills)
{
(void)value_ptr;
bh_thread_data *thread_data, *curr_thread_data;
/* Get thread data of current thread */
curr_thread_data = thread_data_current();
curr_thread_data->wait_node.next = NULL;
/* Get thread data */
thread_data = (bh_thread_data*)thread;
aos_mutex_lock(&thread_data->wait_list_lock, AOS_WAIT_FOREVER);
if (!thread_data->thread_wait_list)
thread_data->thread_wait_list = &curr_thread_data->wait_node;
else {
/* Add to end of waiting list */
bh_thread_wait_node *p = thread_data->thread_wait_list;
while (p->next)
p = p->next;
p->next = &curr_thread_data->wait_node;
}
aos_mutex_unlock(&thread_data->wait_list_lock);
/* Wait the sem */
aos_sem_wait(&curr_thread_data->wait_node.sem, mills);
return BHT_OK;
}
int
_vm_thread_detach (korp_tid thread)
{
(void)thread;
return BHT_OK;
}
void *
_vm_tls_get(unsigned idx)
{
(void)idx;
bh_thread_data *thread_data;
bh_assert (idx == 0);
thread_data = thread_data_current();
return thread_data ? thread_data->tlr : NULL;
}
int
_vm_tls_put(unsigned idx, void * tls)
{
bh_thread_data *thread_data;
(void)idx;
bh_assert (idx == 0);
thread_data = thread_data_current();
bh_assert (thread_data != NULL);
thread_data->tlr = tls;
return BHT_OK;
}
int
_vm_mutex_init(korp_mutex *mutex)
{
return aos_mutex_new(mutex) == 0 ? BHT_OK : BHT_ERROR;
}
int
_vm_recursive_mutex_init(korp_mutex *mutex)
{
return aos_mutex_new(mutex) == 0 ? BHT_OK : BHT_ERROR;
}
int
_vm_mutex_destroy(korp_mutex *mutex)
{
aos_mutex_free(mutex);
return BHT_OK;
}
void
vm_mutex_lock(korp_mutex *mutex)
{
aos_mutex_lock(mutex, AOS_WAIT_FOREVER);
}
int
vm_mutex_trylock(korp_mutex *mutex)
{
return aos_mutex_lock(mutex, AOS_NO_WAIT);
}
void vm_mutex_unlock(korp_mutex *mutex)
{
aos_mutex_unlock(mutex);
}
int _vm_sem_init(korp_sem* sem, unsigned int c)
{
return aos_sem_new(sem, c) == 0 ? BHT_OK : BHT_ERROR;
}
int _vm_sem_destroy(korp_sem *sem)
{
aos_sem_free(sem);
return BHT_OK;
}
int _vm_sem_wait(korp_sem *sem)
{
return aos_sem_wait(sem, AOS_WAIT_FOREVER);
}
int _vm_sem_reltimedwait(korp_sem *sem, int mills)
{
return aos_sem_wait(sem, mills);
}
int _vm_sem_post(korp_sem *sem)
{
aos_sem_signal(sem);
return BHT_OK;
}
int
_vm_cond_init(korp_cond *cond)
{
if (aos_mutex_new(&cond->wait_list_lock) != 0)
return BHT_ERROR;
cond->thread_wait_list = NULL;
return BHT_OK;
}
int
_vm_cond_destroy(korp_cond *cond)
{
aos_mutex_free(&cond->wait_list_lock);
return BHT_OK;
}
static int
vm_cond_wait_internal(korp_cond *cond, korp_mutex *mutex,
bool timed, int mills)
{
bh_thread_wait_node *node = &thread_data_current()->wait_node;
node->next = NULL;
aos_mutex_lock(&cond->wait_list_lock, AOS_WAIT_FOREVER);
if (!cond->thread_wait_list)
cond->thread_wait_list = node;
else {
/* Add to end of wait list */
bh_thread_wait_node *p = cond->thread_wait_list;
while (p->next)
p = p->next;
p->next = node;
}
aos_mutex_unlock(&cond->wait_list_lock);
/* Unlock mutex, wait sem and lock mutex again */
aos_mutex_unlock(mutex);
aos_sem_wait(&node->sem, timed ? mills : AOS_WAIT_FOREVER);
aos_mutex_lock(mutex, AOS_WAIT_FOREVER);
/* Remove wait node from wait list */
aos_mutex_lock(&cond->wait_list_lock, AOS_WAIT_FOREVER);
if (cond->thread_wait_list == node)
cond->thread_wait_list = node->next;
else {
/* Remove from the wait list */
bh_thread_wait_node *p = cond->thread_wait_list;
while (p->next != node)
p = p->next;
p->next = node->next;
}
aos_mutex_unlock(&cond->wait_list_lock);
return BHT_OK;
}
int
_vm_cond_wait(korp_cond *cond, korp_mutex *mutex)
{
return vm_cond_wait_internal(cond, mutex, false, 0);
}
int
_vm_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, int mills)
{
return vm_cond_wait_internal(cond, mutex, true, mills);
}
int
_vm_cond_signal(korp_cond *cond)
{
/* Signal the head wait node of wait list */
aos_mutex_lock(&cond->wait_list_lock, AOS_WAIT_FOREVER);
if (cond->thread_wait_list)
aos_sem_signal(&cond->thread_wait_list->sem);
aos_mutex_unlock(&cond->wait_list_lock);
return BHT_OK;
}
int
_vm_cond_broadcast (korp_cond *cond)
{
/* Signal each wait node of wait list */
aos_mutex_lock(&cond->wait_list_lock, AOS_WAIT_FOREVER);
if (cond->thread_wait_list) {
bh_thread_wait_node *p = cond->thread_wait_list;
while (p) {
aos_sem_signal(&p->sem);
p = p->next;
}
}
aos_mutex_unlock(&cond->wait_list_lock);
return BHT_OK;
}

View File

@ -0,0 +1,37 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_time.h"
/*
* This function returns milliseconds per tick.
* @return milliseconds per tick.
*/
uint64 _bh_time_get_tick_millisecond()
{
return aos_get_hz() / 1000;
}
/*
* This function returns milliseconds after boot.
* @return milliseconds after boot.
*/
uint64 _bh_time_get_boot_millisecond()
{
return (uint64)aos_now_ms();
}
uint64 _bh_time_get_millisecond_from_1970()
{
return (uint64)aos_now_ms();
}
size_t
_bh_time_strftime (char *str, size_t max, const char *format, int64 time)
{
str = aos_now_time_str(str, max);
return str ? strlen(str) + 1 : 0;
}

View File

@ -0,0 +1,13 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
set (PLATFORM_SHARED_DIR ${CMAKE_CURRENT_LIST_DIR})
include_directories(${PLATFORM_SHARED_DIR})
include_directories(${PLATFORM_SHARED_DIR}/../include)
file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c)
set (PLATFORM_SHARED_SOURCE ${source_all})

View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_platform.h"
#include "bh_assert.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef BH_TEST
#include <setjmp.h>
#endif
#ifdef BH_TEST
/* for exception throwing */
jmp_buf bh_test_jb;
#endif
void bh_assert_internal(int v, const char *file_name, int line_number,
const char *expr_string)
{
if (v)
return;
if (!file_name)
file_name = "NULL FILENAME";
if (!expr_string)
expr_string = "NULL EXPR_STRING";
printf("\nASSERTION FAILED: %s, at FILE=%s, LINE=%d\n", expr_string,
file_name, line_number);
#ifdef BH_TEST
longjmp(bh_test_jb, 1);
#endif
abort();
}
void bh_debug_internal(const char *file_name, int line_number, const char *fmt,
...)
{
#ifndef JEFF_TEST_VERIFIER
va_list args;
va_start(args, fmt);
bh_assert(file_name);
printf("\nDebug info FILE=%s, LINE=%d: ", file_name, line_number);
vprintf(fmt, args);
va_end(args);
printf("\n");
#endif
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_platform.h"
#define RSIZE_MAX 0x7FFFFFFF
int b_memcpy_s(void * s1, unsigned int s1max, const void * s2, unsigned int n)
{
char *dest = (char*) s1;
char *src = (char*) s2;
if (n == 0) {
return 0;
}
if (s1 == NULL || s1max > RSIZE_MAX) {
return -1;
}
if (s2 == NULL || n > s1max) {
memset(dest, 0, s1max);
return -1;
}
memcpy(dest, src, n);
return 0;
}
int b_strcat_s(char * s1, size_t s1max, const char * s2)
{
if (NULL == s1 || NULL == s2
|| s1max < (strlen(s1) + strlen(s2) + 1)
|| s1max > RSIZE_MAX) {
return -1;
}
strcat(s1, s2);
return 0;
}
int b_strcpy_s(char * s1, size_t s1max, const char * s2)
{
if (NULL == s1 || NULL == s2
|| s1max < (strlen(s2) + 1)
|| s1max > RSIZE_MAX) {
return -1;
}
strcpy(s1, s2);
return 0;
}
int fopen_s(FILE ** pFile, const char *filename, const char *mode)
{
if (NULL == pFile || NULL == filename || NULL == mode) {
return -1;
}
*pFile = fopen(filename, mode);
if (NULL == *pFile)
return -1;
return 0;
}

View File

@ -0,0 +1,176 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_platform.h"
#include "bh_common.h"
#include "bh_assert.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
char *bh_strdup(const char *s)
{
uint32 size;
char *s1 = NULL;
if (s) {
size = (uint32)(strlen(s) + 1);
if ((s1 = bh_malloc(size)))
bh_memcpy_s(s1, size, s, size);
}
return s1;
}
int bh_platform_init()
{
return 0;
}
char*
bh_read_file_to_buffer(const char *filename, uint32 *ret_size)
{
char *buffer;
int file;
uint32 file_size, read_size;
struct stat stat_buf;
if (!filename || !ret_size) {
printf("Read file to buffer failed: invalid filename or ret size.\n");
return NULL;
}
if ((file = open(filename, O_RDONLY, 0)) == -1) {
printf("Read file to buffer failed: open file %s failed.\n",
filename);
return NULL;
}
if (fstat(file, &stat_buf) != 0) {
printf("Read file to buffer failed: fstat file %s failed.\n",
filename);
close(file);
return NULL;
}
file_size = (uint32)stat_buf.st_size;
if (!(buffer = bh_malloc(file_size))) {
printf("Read file to buffer failed: alloc memory failed.\n");
close(file);
return NULL;
}
read_size = (uint32)read(file, buffer, file_size);
close(file);
if (read_size < file_size) {
printf("Read file to buffer failed: read file content failed.\n");
bh_free(buffer);
return NULL;
}
*ret_size = file_size;
return buffer;
}
void *
bh_mmap(void *hint, uint32 size, int prot, int flags)
{
int map_prot = PROT_NONE;
int map_flags = MAP_ANONYMOUS | MAP_PRIVATE;
uint64 request_size, page_size;
uint8 *addr, *addr_aligned;
uint32 i;
/* align to 2M if no less than 2M, else align to 4K */
page_size = size < 2 * 1024 * 1024 ? 4096 : 2 * 1024 * 1024;
request_size = (size + page_size - 1) & ~(page_size - 1);
request_size += page_size;
if (request_size >= UINT32_MAX)
return NULL;
if (prot & MMAP_PROT_READ)
map_prot |= PROT_READ;
if (prot & MMAP_PROT_WRITE)
map_prot |= PROT_WRITE;
if (prot & MMAP_PROT_EXEC)
map_prot |= PROT_EXEC;
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
if (flags & MMAP_MAP_32BIT)
map_flags |= MAP_32BIT;
#endif
if (flags & MMAP_MAP_FIXED)
map_flags |= MAP_FIXED;
/* try 5 times */
for (i = 0; i < 5; i ++) {
addr = mmap(hint, size, map_prot, map_flags, -1, 0);
if (addr != MAP_FAILED)
break;
}
if (addr == MAP_FAILED)
return NULL;
addr_aligned = (uint8*)(uintptr_t)
(((uint64)(uintptr_t)addr + page_size - 1) & ~(page_size - 1));
/* Unmap memory allocated before the aligned base address */
if (addr != addr_aligned) {
uint32 prefix_size = (uint32)(addr_aligned - addr);
munmap(addr, prefix_size);
request_size -= prefix_size;
}
/* Unmap memory allocated after the potentially unaligned end */
if (size != request_size) {
uint32 suffix_size = (uint32)(request_size - size);
munmap(addr_aligned + size, suffix_size);
request_size -= size;
}
if (size >= 2 * 1024 * 1024) {
/* Try to use huge page to improve performance */
if (!madvise(addr, size, MADV_HUGEPAGE))
/* make huge page become effective */
memset(addr, 0, size);
}
return addr_aligned;
}
void
bh_munmap(void *addr, uint32 size)
{
if (addr)
munmap(addr, size);
}
int
bh_mprotect(void *addr, uint32 size, int prot)
{
int map_prot = PROT_NONE;
if (!addr)
return 0;
if (prot & MMAP_PROT_READ)
map_prot |= PROT_READ;
if (prot & MMAP_PROT_WRITE)
map_prot |= PROT_WRITE;
if (prot & MMAP_PROT_EXEC)
map_prot |= PROT_EXEC;
return mprotect(addr, size, map_prot);
}

View File

@ -0,0 +1,138 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _BH_PLATFORM_H
#define _BH_PLATFORM_H
#include "bh_config.h"
#include "bh_types.h"
#include "bh_memory.h"
#include <inttypes.h>
#include <stdbool.h>
#include <assert.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdarg.h>
#include <ctype.h>
#include <pthread.h>
#include <limits.h>
#include <fcntl.h>
#include <semaphore.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef uint64_t uint64;
typedef int64_t int64;
extern void DEBUGME(void);
#define DIE do{bh_debug("Die here\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); DEBUGME(void); while(1);}while(0)
#ifndef BH_PLATFORM_DARWIN
#define BH_PLATFORM_DARWIN
#endif
/* NEED qsort */
#define _STACK_SIZE_ADJUSTMENT (32 * 1024)
/* Stack size of applet threads's native part. */
#define BH_APPLET_PRESERVED_STACK_SIZE (8 * 1024 + _STACK_SIZE_ADJUSTMENT)
/* Default thread priority */
#define BH_THREAD_DEFAULT_PRIORITY 0
#define BH_ROUTINE_MODIFIER
#define BHT_TIMEDOUT ETIMEDOUT
#define INVALID_THREAD_ID 0xFFffFFff
typedef pthread_t korp_tid;
typedef pthread_mutex_t korp_mutex;
typedef sem_t korp_sem;
typedef pthread_cond_t korp_cond;
typedef pthread_t korp_thread;
typedef void* (*thread_start_routine_t)(void*);
#define wa_malloc bh_malloc
#define wa_free bh_free
#define wa_strdup bh_strdup
#define bh_printf printf
/* int snprintf(char *buffer, size_t count, const char *format, ...); */
double fmod(double x, double y);
float fmodf(float x, float y);
double sqrt(double x);
#define BH_WAIT_FOREVER 0xFFFFFFFF
#ifndef NULL
# define NULL ((void*) 0)
#endif
/**
* Return the offset of the given field in the given type.
*
* @param Type the type containing the filed
* @param field the field in the type
*
* @return the offset of field in Type
*/
#ifndef offsetof
#define offsetof(Type, field) ((size_t)(&((Type *)0)->field))
#endif
#define bh_assert assert
int b_memcpy_s(void * s1, unsigned int s1max, const void * s2,
unsigned int n);
int b_strcat_s(char * s1, size_t s1max, const char * s2);
int b_strcpy_s(char * s1, size_t s1max, const char * s2);
int fopen_s(FILE ** pFile, const char *filename, const char *mode);
char *bh_read_file_to_buffer(const char *filename, uint32 *ret_size);
char *bh_strdup(const char *s);
int bh_platform_init();
/* MMAP mode */
enum {
MMAP_PROT_NONE = 0,
MMAP_PROT_READ = 1,
MMAP_PROT_WRITE = 2,
MMAP_PROT_EXEC = 4
};
/* MMAP flags */
enum {
MMAP_MAP_NONE = 0,
/* Put the mapping into 0 to 2 G, supported only on x86_64 */
MMAP_MAP_32BIT = 1,
/* Don't interpret addr as a hint: place the mapping at exactly
that address. */
MMAP_MAP_FIXED = 2
};
void *bh_mmap(void *hint, unsigned int size, int prot, int flags);
void bh_munmap(void *addr, uint32 size);
int bh_mprotect(void *addr, uint32 size, int prot);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,30 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_platform.h"
#include <stdio.h>
void bh_log_emit(const char *fmt, va_list ap)
{
vprintf(fmt, ap);
fflush(stdout);
}
int bh_fprintf(FILE *stream, const char *fmt, ...)
{
va_list ap;
int ret;
va_start(ap, fmt);
ret = vfprintf(stream ? stream : stdout, fmt, ap);
va_end(ap);
return ret;
}
int bh_fflush(void *stream)
{
return fflush(stream ? stream : stdout);
}

View File

@ -0,0 +1,394 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_thread.h"
#include "bh_assert.h"
#include "bh_log.h"
#include "bh_memory.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
static bool is_thread_sys_inited = false;
static korp_mutex thread_list_lock;
static pthread_key_t thread_local_storage_key[BH_MAX_TLS_NUM];
int _vm_thread_sys_init()
{
unsigned i, j;
int ret;
if (is_thread_sys_inited)
return 0;
for (i = 0; i < BH_MAX_TLS_NUM; i++) {
ret = pthread_key_create(&thread_local_storage_key[i], NULL);
if (ret)
goto fail;
}
ret = vm_mutex_init(&thread_list_lock);
if (ret)
goto fail;
is_thread_sys_inited = true;
return 0;
fail: for (j = 0; j < i; j++)
pthread_key_delete(thread_local_storage_key[j]);
return -1;
}
void vm_thread_sys_destroy(void)
{
if (is_thread_sys_inited) {
unsigned i;
for (i = 0; i < BH_MAX_TLS_NUM; i++)
pthread_key_delete(thread_local_storage_key[i]);
vm_mutex_destroy(&thread_list_lock);
is_thread_sys_inited = false;
}
}
typedef struct {
thread_start_routine_t start;
void* stack;
uint32 stack_size;
void* arg;
} thread_wrapper_arg;
static void *vm_thread_wrapper(void *arg)
{
thread_wrapper_arg * targ = arg;
LOG_VERBOSE("THREAD CREATE 0x%08x\n", &targ);
targ->stack = (void *)((uintptr_t)(&arg) & (uintptr_t)~0xfff);
_vm_tls_put(1, targ);
targ->start(targ->arg);
bh_free(targ);
_vm_tls_put(1, NULL);
return NULL;
}
int _vm_thread_create_with_prio(korp_tid *tid, thread_start_routine_t start,
void *arg, unsigned int stack_size, int prio)
{
pthread_attr_t tattr;
thread_wrapper_arg *targ;
bh_assert(stack_size > 0);
bh_assert(tid);
bh_assert(start);
*tid = INVALID_THREAD_ID;
pthread_attr_init(&tattr);
pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE);
if (pthread_attr_setstacksize(&tattr, stack_size) != 0) {
bh_debug("Invalid thread stack size %u. Min stack size on Linux = %u",
stack_size, PTHREAD_STACK_MIN);
pthread_attr_destroy(&tattr);
return BHT_ERROR;
}
targ = (thread_wrapper_arg*) bh_malloc(sizeof(*targ));
if (!targ) {
pthread_attr_destroy(&tattr);
return BHT_ERROR;
}
targ->start = start;
targ->arg = arg;
targ->stack_size = stack_size;
if (pthread_create(tid, &tattr, vm_thread_wrapper, targ) != 0) {
pthread_attr_destroy(&tattr);
bh_free(targ);
return BHT_ERROR;
}
pthread_attr_destroy(&tattr);
return BHT_OK;
}
int _vm_thread_create(korp_tid *tid, thread_start_routine_t start, void *arg,
unsigned int stack_size)
{
return _vm_thread_create_with_prio(tid, start, arg, stack_size,
BH_THREAD_DEFAULT_PRIORITY);
}
korp_tid _vm_self_thread()
{
return (korp_tid) pthread_self();
}
void vm_thread_exit(void * code)
{
bh_free(_vm_tls_get(1));
_vm_tls_put(1, NULL);
pthread_exit(code);
}
void *_vm_tls_get(unsigned idx)
{
bh_assert(idx < BH_MAX_TLS_NUM);
return pthread_getspecific(thread_local_storage_key[idx]);
}
int _vm_tls_put(unsigned idx, void * tls)
{
bh_assert(idx < BH_MAX_TLS_NUM);
pthread_setspecific(thread_local_storage_key[idx], tls);
return BHT_OK;
}
int _vm_mutex_init(korp_mutex *mutex)
{
return pthread_mutex_init(mutex, NULL) == 0 ? BHT_OK : BHT_ERROR;
}
int _vm_recursive_mutex_init(korp_mutex *mutex)
{
int ret;
pthread_mutexattr_t mattr;
bh_assert(mutex);
ret = pthread_mutexattr_init(&mattr);
if (ret)
return BHT_ERROR;
pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE);
ret = pthread_mutex_init(mutex, &mattr);
pthread_mutexattr_destroy(&mattr);
return ret == 0 ? BHT_OK : BHT_ERROR;
}
int _vm_mutex_destroy(korp_mutex *mutex)
{
int ret;
bh_assert(mutex);
ret = pthread_mutex_destroy(mutex);
return ret == 0 ? BHT_OK : BHT_ERROR;
}
/* Returned error (EINVAL, EAGAIN and EDEADLK) from
locking the mutex indicates some logic error present in
the program somewhere.
Don't try to recover error for an existing unknown error.*/
void vm_mutex_lock(korp_mutex *mutex)
{
int ret;
bh_assert(mutex);
ret = pthread_mutex_lock(mutex);
if (0 != ret) {
printf("vm mutex lock failed (ret=%d)!\n", ret);
exit(-1);
}
}
int vm_mutex_trylock(korp_mutex *mutex)
{
int ret;
bh_assert(mutex);
ret = pthread_mutex_trylock(mutex);
return ret == 0 ? BHT_OK : BHT_ERROR;
}
/* Returned error (EINVAL, EAGAIN and EPERM) from
unlocking the mutex indicates some logic error present
in the program somewhere.
Don't try to recover error for an existing unknown error.*/
void vm_mutex_unlock(korp_mutex *mutex)
{
int ret;
bh_assert(mutex);
ret = pthread_mutex_unlock(mutex);
if (0 != ret) {
printf("vm mutex unlock failed (ret=%d)!\n", ret);
exit(-1);
}
}
int _vm_sem_init(korp_sem* sem, unsigned int c)
{
int ret;
bh_assert(sem);
ret = sem_init(sem, 0, c);
return ret == 0 ? BHT_OK : BHT_ERROR;
}
int _vm_sem_destroy(korp_sem *sem)
{
int ret;
bh_assert(sem);
ret = sem_destroy(sem);
return ret == 0 ? BHT_OK : BHT_ERROR;
}
int _vm_sem_wait(korp_sem *sem)
{
int ret;
bh_assert(sem);
ret = sem_wait(sem);
return ret == 0 ? BHT_OK : BHT_ERROR;
}
/*int _vm_sem_reltimedwait(korp_sem *sem, int mills)
{
int ret = BHT_OK;
struct timespec timeout;
const int mills_per_sec = 1000;
const int mills_to_nsec = 1E6;
bh_assert(sem);
if (mills == (int)BHT_WAIT_FOREVER) {
ret = sem_wait(sem);
} else {
timeout.tv_sec = mills / mills_per_sec;
timeout.tv_nsec = (mills % mills_per_sec) * mills_to_nsec;
timeout.tv_sec += time(NULL);
ret = sem_timedwait(sem, &timeout);
}
if (ret != BHT_OK) {
if (errno == BHT_TIMEDOUT) {
ret = BHT_TIMEDOUT;
errno = 0;
} else {
bh_debug("Faliure happens when timed wait is called");
bh_assert(0);
}
}
return ret;
}
*/
int _vm_sem_post(korp_sem *sem)
{
bh_assert(sem);
return sem_post(sem) == 0 ? BHT_OK : BHT_ERROR;
}
int _vm_cond_init(korp_cond *cond)
{
bh_assert(cond);
if (pthread_cond_init(cond, NULL) != BHT_OK)
return BHT_ERROR;
return BHT_OK;
}
int _vm_cond_destroy(korp_cond *cond)
{
bh_assert(cond);
if (pthread_cond_destroy(cond) != BHT_OK)
return BHT_ERROR;
return BHT_OK;
}
int _vm_cond_wait(korp_cond *cond, korp_mutex *mutex)
{
bh_assert(cond);
bh_assert(mutex);
if (pthread_cond_wait(cond, mutex) != BHT_OK)
return BHT_ERROR;
return BHT_OK;
}
static void msec_nsec_to_abstime(struct timespec *ts, int64 msec, int32 nsec)
{
struct timeval tv;
gettimeofday(&tv, NULL);
ts->tv_sec = (long int)(tv.tv_sec + msec / 1000);
ts->tv_nsec = (long int)(tv.tv_usec * 1000 + (msec % 1000) * 1000000 + nsec);
if (ts->tv_nsec >= 1000000000L) {
ts->tv_sec++;
ts->tv_nsec -= 1000000000L;
}
}
int _vm_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, int mills)
{
int ret;
struct timespec abstime;
if (mills == (int)BHT_WAIT_FOREVER)
ret = pthread_cond_wait(cond, mutex);
else {
msec_nsec_to_abstime(&abstime, mills, 0);
ret = pthread_cond_timedwait(cond, mutex, &abstime);
}
if (ret != BHT_OK && ret != BHT_TIMEDOUT)
return BHT_ERROR;
return BHT_OK;
}
int _vm_cond_signal(korp_cond *cond)
{
bh_assert(cond);
if (pthread_cond_signal(cond) != BHT_OK)
return BHT_ERROR;
return BHT_OK;
}
int _vm_cond_broadcast(korp_cond *cond)
{
bh_assert(cond);
if (pthread_cond_broadcast(cond) != BHT_OK)
return BHT_ERROR;
return BHT_OK;
}
int _vm_thread_cancel(korp_tid thread)
{
return pthread_cancel(thread);
}
int _vm_thread_join(korp_tid thread, void **value_ptr, int mills)
{
return pthread_join(thread, value_ptr);
}
int _vm_thread_detach(korp_tid thread)
{
return pthread_detach(thread);
}

View File

@ -0,0 +1,70 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_time.h"
#include <unistd.h>
#include <stdio.h>
#include <sys/timeb.h>
#include <time.h>
/*
* This function returns milliseconds per tick.
* @return milliseconds per tick.
*/
uint64 _bh_time_get_tick_millisecond()
{
return (uint64)sysconf(_SC_CLK_TCK);
}
/*
* This function returns milliseconds after boot.
* @return milliseconds after boot.
*/
uint64 _bh_time_get_boot_millisecond()
{
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
return 0;
}
return ((uint64) ts.tv_sec) * 1000 + ((uint64)ts.tv_nsec) / (1000 * 1000);
}
uint32 bh_get_tick_sec()
{
return (uint32)(_bh_time_get_boot_millisecond() / 1000);
}
/*
* This function returns GMT time milliseconds since from 1970.1.1, AKA UNIX time.
* @return milliseconds since from 1970.1.1.
*/
uint64 _bh_time_get_millisecond_from_1970()
{
struct timeb tp;
ftime(&tp);
return ((uint64) tp.time) * 1000 + tp.millitm
- (tp.dstflag == 0 ? 0 : 60 * 60 * 1000)
+ ((uint64)tp.timezone) * 60 * 1000;
}
size_t _bh_time_strftime(char *s, size_t max, const char *format, int64 time)
{
time_t time_sec = (time_t)(time / 1000);
struct timeb tp;
struct tm *ltp;
ftime(&tp);
time_sec -= tp.timezone * 60;
ltp = localtime(&time_sec);
if (ltp == NULL) {
return 0;
}
return strftime(s, max, format, ltp);
}

View File

@ -0,0 +1,13 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
set (PLATFORM_SHARED_DIR ${CMAKE_CURRENT_LIST_DIR})
include_directories(${PLATFORM_SHARED_DIR})
include_directories(${PLATFORM_SHARED_DIR}/../include)
file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c)
set (PLATFORM_SHARED_SOURCE ${source_all})

View File

@ -0,0 +1,62 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _BH_ASSERT_H
#define _BH_ASSERT_H
#include "bh_config.h"
#include "bh_platform.h"
#ifdef BH_TEST
# ifndef BH_DEBUG
# error "BH_TEST should be defined under BH_DEBUG"
# endif
#endif
#ifdef BH_TEST
# if defined(WIN32) || defined(__linux__)
# else
# error "Test case can not run on the current platform"
# endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifdef BH_DEBUG
void bh_assert_internal(int v, const char *file_name, int line_number,
const char *expr_string);
#define bh_assert(expr) bh_assert_internal((int)(expr), __FILE__, __LINE__, #expr)
void bh_debug_internal(const char *file_name, int line_number,
const char *fmt, ...);
#if defined(WIN32)
#define bh_debug(fmt, ...) bh_debug_internal(__FILE__, __LINE__, fmt, __VA_ARGS__)
#elif defined(__linux__)
#define bh_debug bh_debug_internal(__FILE__, __LINE__, "");printf
#else
#error "Unsupported platform"
#endif
#else /* else of BH_DEBUG */
#define bh_debug if(0)printf
#endif /* end of BH_DEBUG */
#ifdef BH_TEST
#define BH_STATIC
#else
#define BH_STATIC static
#endif /* end of BH_TEST */
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,20 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
/**
* @file bh_config.h
* @date Tue Sep 13 14:53:17 2011
*
* @brief Configurations for different platforms and targets. Make
* sure all source files in Beihai project include this header file
* directly or indirectly.
*/
#ifndef BH_CONFIG
#include "config.h"
#endif /* end of BH_CONFIG */

View File

@ -0,0 +1,25 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef BH_PLATFORM_LOG
#define BH_PLATFORM_LOG
#include "bh_platform.h"
#ifdef __cplusplus
extern "C" {
#endif
void bh_log_emit(const char *fmt, va_list ap);
int bh_fprintf(void *stream, const char *fmt, ...);
int bh_fflush(void *stream);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,398 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _BH_THREAD_H
#define _BH_THREAD_H
#ifdef __cplusplus
extern "C" {
#endif
#include "bh_config.h"
#include "bh_platform.h"
#define BH_MAX_THREAD 32
#define BH_MAX_TLS_NUM 2
#define BHT_ERROR (-1)
#define BHT_TIMED_OUT (1)
#define BHT_OK (0)
#define BHT_NO_WAIT 0x00000000
#define BHT_WAIT_FOREVER 0xFFFFFFFF
/**
* vm_thread_sys_init
* initiation function for beihai thread system. Invoked at the beginning of beihai intiation.
*
* @return 0 if succuess.
*/
int _vm_thread_sys_init(void);
#ifdef _INSTRUMENT_TEST_ENABLED
int vm_thread_sys_init_instr(const char*func_name);
#define vm_thread_sys_init(void) vm_thread_sys_init_instr(__FUNCTION__)
#else
#define vm_thread_sys_init _vm_thread_sys_init
#endif
void vm_thread_sys_destroy(void);
/**
* This function creates a thread
*
* @param p_tid [OUTPUT] the pointer of tid
* @param start main routine of the thread
* @param arg argument passed to main routine
* @param stack_size bytes of stack size
*
* @return 0 if success.
*/
int _vm_thread_create(korp_tid *p_tid, thread_start_routine_t start, void *arg,
unsigned int stack_size);
#ifdef _INSTRUMENT_TEST_ENABLED
int vm_thread_create_instr(korp_tid *p_tid, thread_start_routine_t start, void *arg, unsigned int stack_size, const char*func_name);
#define vm_thread_create(p_tid, start, arg, stack_size) vm_thread_create_instr(p_tid, start, arg, stack_size, __FUNCTION__)
#else
#define vm_thread_create _vm_thread_create
#endif
/**
* This function creates a thread
*
* @param p_tid [OUTPUT] the pointer of tid
* @param start main routine of the thread
* @param arg argument passed to main routine
* @param stack_size bytes of stack size
* @param prio the priority
*
* @return 0 if success.
*/
int _vm_thread_create_with_prio(korp_tid *p_tid, thread_start_routine_t start,
void *arg, unsigned int stack_size, int prio);
#ifdef _INSTRUMENT_TEST_ENABLED
int vm_thread_create_with_prio_instr(korp_tid *p_tid, thread_start_routine_t start, void *arg, unsigned int stack_size, int prio, const char*func_name);
#define vm_thread_create_with_prio(p_tid, start, arg, stack_size) vm_thread_create_instr(p_tid, start, arg, stack_size, prio, __FUNCTION__)
#else
#define vm_thread_create_with_prio _vm_thread_create_with_prio
#endif
/**
* This function never returns.
*
* @param code not used
*/
void vm_thread_exit(void *code);
/**
* This function gets current thread id
*
* @return current thread id
*/
korp_tid _vm_self_thread(void);
#ifdef _INSTRUMENT_TEST_ENABLED
korp_tid vm_self_thread_instr(const char*func_name);
#define vm_self_thread(void) vm_self_thread_instr(__FUNCTION__)
#else
#define vm_self_thread _vm_self_thread
#endif
/**
* This function saves a pointer in thread local storage. One thread can only save one pointer.
*
* @param idx tls array index
* @param ptr pointer need save as TLS
*
* @return 0 if success
*/
int _vm_tls_put(unsigned idx, void *ptr);
#ifdef _INSTRUMENT_TEST_ENABLED
int vm_tls_put_instr(unsigned idx, void *ptr, const char*func_name);
#define vm_tls_put(idx, ptr) vm_tls_put_instr(idx, ptr, __FUNCTION__)
#else
#define vm_tls_put _vm_tls_put
#endif
/**
* This function gets a pointer saved in TLS.
*
* @param idx tls array index
*
* @return the pointer saved in TLS.
*/
void *_vm_tls_get(unsigned idx);
#ifdef _INSTRUMENT_TEST_ENABLED
void *vm_tls_get_instr(unsigned idx, const char*func_name);
#define vm_tls_get(idx) vm_tls_get_instr(idx, __FUNCTION__)
#else
#define vm_tls_get _vm_tls_get
#endif
#define vm_thread_testcancel(void)
/**
* This function creates a non-recursive mutex
*
* @param mutex [OUTPUT] pointer to mutex initialized.
*
* @return 0 if success
*/
int _vm_mutex_init(korp_mutex *mutex);
#ifdef INSTRUMENT_TEST_ENABLED
int vm_mutex_init_instr(korp_mutex *mutex, const char*func_name);
#define vm_mutex_init(mutex) vm_mutex_init_instr(mutex, __FUNCTION__)
#else
#define vm_mutex_init _vm_mutex_init
#endif
/**
* This function creates a recursive mutex
*
* @param mutex [OUTPUT] pointer to mutex initialized.
*
* @return 0 if success
*/
int _vm_recursive_mutex_init(korp_mutex *mutex);
#ifdef INSTRUMENT_TEST_ENABLED
int vm_recursive_mutex_init_instr(korp_mutex *mutex, const char*func_name);
#define vm_recursive_mutex_init(mutex) vm_recursive_mutex_init_instr(mutex, __FUNCTION__)
#else
#define vm_recursive_mutex_init _vm_recursive_mutex_init
#endif
/**
* This function destroys a mutex
*
* @param mutex pointer to mutex need destroy
*
* @return 0 if success
*/
int _vm_mutex_destroy(korp_mutex *mutex);
#ifdef _INSTRUMENT_TEST_ENABLED
int vm_mutex_destroy_instr(korp_mutex *mutex, const char*func_name);
#define vm_mutex_destroy(mutex) vm_mutex_destroy_instr(mutex, __FUNCTION__)
#else
#define vm_mutex_destroy _vm_mutex_destroy
#endif
/**
* This function locks the mutex
*
* @param mutex pointer to mutex need lock
*
* @return Void
*/
void vm_mutex_lock(korp_mutex *mutex);
/**
* This function locks the mutex without waiting
*
* @param mutex pointer to mutex need lock
*
* @return 0 if success
*/
int vm_mutex_trylock(korp_mutex *mutex);
/**
* This function unlocks the mutex
*
* @param mutex pointer to mutex need unlock
*
* @return Void
*/
void vm_mutex_unlock(korp_mutex *mutex);
/**
* This function creates a semaphone
*
* @param sem [OUTPUT] pointer to semaphone
* @param c counter of semaphone
*
* @return 0 if success
*/
int _vm_sem_init(korp_sem *sem, unsigned int c);
#ifdef _INSTRUMENT_TEST_ENABLED
int vm_sem_init_instr(korp_sem *sem, unsigned int c, const char*func_name);
#define vm_sem_init(sem, c) vm_sem_init_instr(sem, c, __FUNCTION__)
#else
#define vm_sem_init _vm_sem_init
#endif
/**
* This function destroys a semaphone
*
* @param sem pointer to semaphone need destroy
*
* @return 0 if success
*/
int _vm_sem_destroy(korp_sem *sem);
#ifdef _INSTRUMENT_TEST_ENABLED
int vm_sem_destroy_instr(korp_sem *sem, const char*func_name);
#define vm_sem_destroy(sem) vm_sem_destroy_instr(sem, __FUNCTION__)
#else
#define vm_sem_destroy _vm_sem_destroy
#endif
/**
* This function performs wait operation on semaphone
*
* @param sem pointer to semaphone need perform wait operation
*
* @return 0 if success
*/
int _vm_sem_wait(korp_sem *sem);
#ifdef _INSTRUMENT_TEST_ENABLED
int vm_sem_wait_instr(korp_sem *sem, const char*func_name);
#define vm_sem_wait(sem) vm_sem_wait_instr(sem, __FUNCTION__)
#else
#define vm_sem_wait _vm_sem_wait
#endif
/**
* This function performs wait operation on semaphone with a timeout
*
* @param sem pointer to semaphone need perform wait operation
* @param mills wait milliseconds to return
*
* @return 0 if success
* @return BH_TIMEOUT if time out
*/
int _vm_sem_reltimedwait(korp_sem *sem, int mills);
#ifdef _INSTRUMENT_TEST_ENABLED
int vm_sem_reltimedwait_instr(korp_sem *sem, int mills, const char*func_name);
#define vm_sem_reltimedwait(sem, mills) vm_sem_reltimedwait_instr(sem, mills, __FUNCTION__)
#else
#define vm_sem_reltimedwait _vm_sem_reltimedwait
#endif
/**
* This function performs post operation on semaphone
*
* @param sem pointer to semaphone need perform post operation
*
* @return 0 if success
*/
int _vm_sem_post(korp_sem *sem);
#ifdef _INSTRUMENT_TEST_ENABLED
int vm_sem_post_instr(korp_sem *sem, const char*func_name);
#define vm_sem_post(sem) vm_sem_post_instr(sem, __FUNCTION__)
#else
#define vm_sem_post _vm_sem_post
#endif
/**
* This function creates a condition variable
*
* @param cond [OUTPUT] pointer to condition variable
*
* @return 0 if success
*/
int _vm_cond_init(korp_cond *cond);
#ifdef INSTRUMENT_TEST_ENABLED
int vm_cond_init_instr(korp_cond *cond, const char*func_name);
#define vm_cond_init(cond) vm_cond_init_instr(cond, __FUNCTION__)
#else
#define vm_cond_init _vm_cond_init
#endif
/**
* This function destroys condition variable
*
* @param cond pointer to condition variable
*
* @return 0 if success
*/
int _vm_cond_destroy(korp_cond *cond);
#ifdef _INSTRUMENT_TEST_ENABLED
int vm_cond_destroy_instr(korp_cond *cond, const char*func_name);
#define vm_cond_destroy(cond) vm_cond_destroy_instr(cond, __FUNCTION__)
#else
#define vm_cond_destroy _vm_cond_destroy
#endif
/**
* This function will block on a condition varible.
*
* @param cond pointer to condition variable
* @param mutex pointer to mutex to protect the condition variable
*
* @return 0 if success
*/
int _vm_cond_wait(korp_cond *cond, korp_mutex *mutex);
#ifdef _INSTRUMENT_TEST_ENABLED
int vm_cond_wait_instr(korp_cond *cond, korp_mutex *mutex, const char*func_name);
#define vm_cond_wait(cond, mutex) vm_cond_wait_instr(cond, mutex, __FUNCTION__)
#else
#define vm_cond_wait _vm_cond_wait
#endif
/**
* This function will block on a condition varible or return if time specified passes.
*
* @param cond pointer to condition variable
* @param mutex pointer to mutex to protect the condition variable
* @param mills milliseconds to wait
*
* @return 0 if success
*/
int _vm_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, int mills);
#ifdef _INSTRUMENT_TEST_ENABLED
int vm_cond_reltimedwait_instr(korp_cond *cond, korp_mutex *mutex, int mills, const char*func_name);
#define vm_cond_reltimedwait(cond, mutex, mills) vm_cond_reltimedwait_instr(cond, mutex, mills, __FUNCTION__)
#else
#define vm_cond_reltimedwait _vm_cond_reltimedwait
#endif
/**
* This function signals the condition variable
*
* @param cond condition variable
*
* @return 0 if success
*/
int _vm_cond_signal(korp_cond *cond);
#ifdef _INSTRUMENT_TEST_ENABLED
int vm_cond_signal_instr(korp_cond *cond, const char*func_name);
#define vm_cond_signal(cond) vm_cond_signal_instr(cond, __FUNCTION__)
#else
#define vm_cond_signal _vm_cond_signal
#endif
int _vm_cond_broadcast(korp_cond *cond);
#ifdef _INSTRUMENT_TEST_ENABLED
int vm_cond_broadcast_instr(korp_cond *cond, const char*func_name);
#define vm_cond_broadcast(cond) vm_cond_broadcast_instr(cond, __FUNCTION__)
#else
#define vm_cond_broadcast _vm_cond_broadcast
#endif
int _vm_thread_cancel(korp_tid thread);
#ifdef _INSTRUMENT_TEST_ENABLED
int vm_thread_cancel_instr(korp_tid thread, const char*func_name);
#define vm_thread_cancel(thread) vm_thread_cancel_instr(thread, __FUNCTION__)
#else
#define vm_thread_cancel _vm_thread_cancel
#endif
int _vm_thread_join(korp_tid thread, void **value_ptr, int mills);
#ifdef _INSTRUMENT_TEST_ENABLED
int vm_thread_join_instr(korp_tid thread, void **value_ptr, int mills, const char*func_name);
#define vm_thread_join(thread, value_ptr, mills) vm_thread_join_instr(thread, value_ptr, mills, __FUNCTION__)
#else
#define vm_thread_join _vm_thread_join
#endif
int _vm_thread_detach(korp_tid thread);
#ifdef _INSTRUMENT_TEST_ENABLED
int vm_thread_detach_instr(korp_tid thread, const char*func_name);
#define vm_thread_detach(thread) vm_thread_detach_instr(thread, __FUNCTION__)
#else
#define vm_thread_detach _vm_thread_detach
#endif
#ifdef __cplusplus
}
#endif
#endif /* #ifndef _BH_THREAD_H */

View File

@ -0,0 +1,86 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _BH_TIME_H
#define _BH_TIME_H
#ifdef __cplusplus
extern "C" {
#endif
#include "bh_config.h"
#include "bh_types.h"
#include "bh_platform.h"
/*
* This function returns milliseconds per tick.
* @return milliseconds per tick.
*/
extern uint64 _bh_time_get_tick_millisecond(void);
#ifdef _INSTRUMENT_TEST_ENABLED
extern uint64 bh_time_get_tick_millisecond_instr(const char*func_name);
#define bh_time_get_tick_millisecond() bh_time_get_tick_millisecond_instr(__FUNCTION__)
#else
#define bh_time_get_tick_millisecond _bh_time_get_tick_millisecond
#endif
/*
* This function returns milliseconds after boot.
* @return milliseconds after boot.
*/
extern uint64 _bh_time_get_boot_millisecond(void);
#ifdef _INSTRUMENT_TEST_ENABLED
extern uint64 bh_time_get_boot_millisecond_instr(const char*func_name);
#define bh_time_get_boot_millisecond() bh_time_get_boot_millisecond_instr(__FUNCTION__)
#else
#define bh_time_get_boot_millisecond _bh_time_get_boot_millisecond
#endif
extern uint32 bh_get_tick_sec();
#define bh_get_tick_ms _bh_time_get_boot_millisecond
/*
* This function returns GMT milliseconds since from 1970.1.1, AKA UNIX time.
* @return milliseconds since from 1970.1.1.
*/
extern uint64 _bh_time_get_millisecond_from_1970(void);
#ifdef _INSTRUMENT_TEST_ENABLED
extern uint64 bh_time_get_millisecond_from_1970_instr(const char*func_name);
#define bh_time_get_millisecond_from_1970() bh_time_get_millisecond_from_1970_instr(__FUNCTION__)
#else
#define bh_time_get_millisecond_from_1970 _bh_time_get_millisecond_from_1970
#endif
/**
* This function sets timezone with specific hours.
*
* @param hours represents the deviation (in hours) of the local time from GMT (can be a positive or a negative number)
* @param half_hour if true, adds half an hour to the local time calculation. For example, if hours=(+5) then the time will be GMT +5:30; if hours=(-5) then the time will be GMT -4:30.
* @param daylight_save if true, applies the daylight saving scheme when calculating the local time (adds one hour to the local time calculation)
*/
extern void bh_set_timezone(int hours, int half_hour, int daylight_save);
/**
* This functions returns the offset in seconds which needs to be added GMT to get the local time.
*
*
* @return offset in secords which needs to be added GMT to get the local time.
*/
extern int bh_get_timezone_offset(void);
size_t bh_time_strftime(char *s, size_t max, const char *format, int64 time);
#ifdef _INSTRUMENT_TEST_ENABLED
size_t bh_time_strftime_instr(char *s, size_t max, const char *format, int64 time, const char*func_name);
#define bh_time_strftime(s, max, format, time) bh_time_strftime_instr(s, max, format, time, __FUNCTION__)
#else
#define bh_time_strftime _bh_time_strftime
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,33 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _BH_TYPES_H
#define _BH_TYPES_H
#include "bh_config.h"
typedef unsigned char uint8;
typedef char int8;
typedef unsigned short uint16;
typedef short int16;
typedef unsigned int uint32;
typedef int int32;
typedef float float32;
typedef double float64;
#include "bh_platform.h"
#ifndef NULL
#define NULL (void*)0
#endif
#ifndef __cplusplus
#define true 1
#define false 0
#define inline __inline
#endif
#endif

View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_platform.h"
#include "bh_assert.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef BH_TEST
#include <setjmp.h>
#endif
#ifdef BH_TEST
/* for exception throwing */
jmp_buf bh_test_jb;
#endif
#define FIXED_BUFFER_SIZE (1<<9)
void bh_assert_internal(int v, const char *file_name, int line_number,
const char *expr_string)
{
if (v)
return;
if (!file_name)
file_name = "NULL FILENAME";
if (!expr_string)
expr_string = "NULL EXPR_STRING";
bh_printf_sgx("\nASSERTION FAILED: %s, at FILE=%s, LINE=%d\n", expr_string,
file_name, line_number);
#ifdef BH_TEST
longjmp(bh_test_jb, 1);
#endif
abort();
}
void bh_debug_internal(const char *file_name, int line_number, const char *fmt,
...)
{
#ifndef JEFF_TEST_VERIFIER
va_list args;
char msg[FIXED_BUFFER_SIZE] = { '\0' };
va_start(args, fmt);
vsnprintf(msg, FIXED_BUFFER_SIZE, fmt, args);
va_end(args);
bh_printf_sgx("\nDebug info FILE=%s, LINE=%d: ", file_name, line_number);
bh_printf_sgx(msg);
bh_printf_sgx("\n");
#endif
}

View File

@ -0,0 +1,54 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_platform.h"
#define RSIZE_MAX 0x7FFFFFFF
int b_memcpy_s(void * s1, unsigned int s1max, const void * s2, unsigned int n)
{
char *dest = (char*) s1;
char *src = (char*) s2;
if (n == 0) {
return 0;
}
if (s1 == NULL || s1max > RSIZE_MAX) {
return -1;
}
if (s2 == NULL || n > s1max) {
memset(dest, 0, s1max);
return -1;
}
memcpy(dest, src, n);
return 0;
}
int b_strcat_s(char * s1, size_t s1max, const char * s2)
{
if (NULL == s1 || NULL == s2
|| s1max < (strlen(s1) + strlen(s2) + 1)
|| s1max > RSIZE_MAX) {
return -1;
}
strncat(s1, s2, strlen(s2));
return 0;
}
int b_strcpy_s(char * s1, size_t s1max, const char * s2)
{
if (NULL == s1 || NULL == s2
|| s1max < (strlen(s2) + 1)
|| s1max > RSIZE_MAX) {
return -1;
}
strncpy(s1, s2, s1max);
return 0;
}

View File

@ -0,0 +1,91 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_common.h"
#include "bh_platform.h"
#include <unistd.h>
#define FIXED_BUFFER_SIZE (1<<9)
static bh_print_function_t print_function = NULL;
char *bh_strdup(const char *s)
{
uint32 size;
char *s1 = NULL;
if (s) {
size = (uint32)(strlen(s) + 1);
if ((s1 = bh_malloc(size)))
bh_memcpy_s(s1, size, s, size);
}
return s1;
}
int bh_platform_init()
{
return 0;
}
int putchar(int c)
{
return 0;
}
int puts(const char *s)
{
return 0;
}
void bh_set_print_function(bh_print_function_t pf)
{
print_function = pf;
}
int bh_printf_sgx(const char *message, ...)
{
if (print_function != NULL) {
char msg[FIXED_BUFFER_SIZE] = { '\0' };
va_list ap;
va_start(ap, message);
vsnprintf(msg, FIXED_BUFFER_SIZE, message, ap);
va_end(ap);
print_function(msg);
}
return 0;
}
int bh_vprintf_sgx(const char * format, va_list arg)
{
if (print_function != NULL) {
char msg[FIXED_BUFFER_SIZE] = { '\0' };
vsnprintf(msg, FIXED_BUFFER_SIZE, format, arg);
print_function(msg);
}
return 0;
}
void *
bh_mmap(void *hint, unsigned int size, int prot, int flags)
{
/* TODO: implement bh_mmap in Linux SGX */
return NULL;
}
void
bh_munmap(void *addr, uint32 size)
{
/* TODO: implement bh_munmap in Linux SGX */
}
int
bh_mprotect(void *addr, uint32 size, int prot)
{
/* TODO: implement bh_mprotect in Linux SGX */
return -1;
}

View File

@ -0,0 +1,132 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _BH_PLATFORM_H
#define _BH_PLATFORM_H
#include "bh_config.h"
#include "bh_types.h"
#include "bh_memory.h"
#include <inttypes.h>
#include <stdbool.h>
#include <assert.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdarg.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
#include <sgx_thread.h>
#ifdef __cplusplus
extern "C" {
#endif
extern int bh_printf_sgx(const char *message, ...);
extern int bh_vprintf_sgx(const char * format, va_list arg);
typedef uint64_t uint64;
typedef int64_t int64;
#define DIE do{bh_debug("Die here\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); DEBUGME(void); while(1);}while(0)
#ifndef BH_PLATFORM_LINUX_SGX
#define BH_PLATFORM_LINUX_SGX
#endif
/* NEED qsort */
#define _STACK_SIZE_ADJUSTMENT (32 * 1024)
/* Stack size of applet threads's native part. */
#define BH_APPLET_PRESERVED_STACK_SIZE (8 * 1024 + _STACK_SIZE_ADJUSTMENT)
/* Default thread priority */
#define BH_THREAD_DEFAULT_PRIORITY 0
#define BH_ROUTINE_MODIFIER
#define BHT_TIMEDOUT ETIMEDOUT
#define INVALID_THREAD_ID 0xFFffFFff
typedef int korp_sem;
typedef void* (*thread_start_routine_t)(void*);
typedef sgx_thread_mutex_t korp_mutex;
typedef sgx_thread_t korp_tid;
typedef sgx_thread_t korp_thread;
typedef sgx_thread_cond_t korp_cond;
#define wa_malloc bh_malloc
#define wa_free bh_free
#define wa_strdup bh_strdup
#define bh_printf bh_printf_sgx
int snprintf(char *buffer, size_t count, const char *format, ...);
int strncasecmp(const char *s1, const char *s2, size_t n);
double fmod(double x, double y);
float fmodf(float x, float y);
double sqrt(double x);
#define BH_WAIT_FOREVER 0xFFFFFFFF
#ifndef NULL
# define NULL ((void*) 0)
#endif
/**
* Return the offset of the given field in the given type.
*
* @param Type the type containing the filed
* @param field the field in the type
*
* @return the offset of field in Type
*/
#ifndef offsetof
#define offsetof(Type, field) ((size_t)(&((Type *)0)->field))
#endif
#define bh_assert assert
int b_memcpy_s(void * s1, unsigned int s1max, const void * s2,
unsigned int n);
int b_strcat_s(char * s1, size_t s1max, const char * s2);
int b_strcpy_s(char * s1, size_t s1max, const char * s2);
char *bh_strdup(const char *s);
int bh_platform_init();
/* MMAP mode */
enum {
MMAP_PROT_NONE = 0,
MMAP_PROT_READ = 1,
MMAP_PROT_WRITE = 2,
MMAP_PROT_EXEC = 4
};
/* MMAP flags */
enum {
MMAP_MAP_NONE = 0,
/* Put the mapping into 0 to 2 G, supported only on x86_64 */
MMAP_MAP_32BIT = 1,
/* Don't interpret addr as a hint: place the mapping at exactly
that address. */
MMAP_MAP_FIXED = 2
};
void *bh_mmap(void *hint, unsigned int size, int prot, int flags);
void bh_munmap(void *addr, uint32 size);
int bh_mprotect(void *addr, uint32 size, int prot);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,25 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_platform.h"
#include <stdio.h>
void bh_log_emit(const char *fmt, va_list ap)
{
//TODO: stub impl
}
/*
int bh_fprintf(FILE *stream, const char *fmt, ...)
{
return 0;
}
*/
int bh_fflush(void *stream)
{
//TODO: stub impl
return 0;
}

View File

@ -0,0 +1,182 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_thread.h"
#include "bh_assert.h"
#include "bh_memory.h"
#include <stdio.h>
#include <stdlib.h>
#include <sgx_thread.h>
int _vm_thread_sys_init()
{
return 0;
}
void vm_thread_sys_destroy(void)
{
}
int _vm_thread_create_with_prio(korp_tid *tid, thread_start_routine_t start,
void *arg, unsigned int stack_size, int prio)
{
return BHT_ERROR;
// return BHT_OK;
}
int _vm_thread_create(korp_tid *tid, thread_start_routine_t start, void *arg,
unsigned int stack_size)
{
return _vm_thread_create_with_prio(tid, start, arg, stack_size,
BH_THREAD_DEFAULT_PRIORITY);
}
korp_tid _vm_self_thread()
{
return sgx_thread_self();
}
void vm_thread_exit(void * code)
{
}
// storage for one thread
static __thread void *_tls_store = NULL;
void *_vm_tls_get(unsigned idx)
{
return _tls_store;
}
int _vm_tls_put(unsigned idx, void * tls)
{
_tls_store = tls;
return BHT_OK;
//return BHT_ERROR;
}
int _vm_mutex_init(korp_mutex *mutex)
{
sgx_thread_mutex_t m = SGX_THREAD_MUTEX_INITIALIZER;
*mutex = m;
return BHT_OK;
}
int _vm_recursive_mutex_init(korp_mutex *mutex)
{
sgx_thread_mutex_t m = SGX_THREAD_RECURSIVE_MUTEX_INITIALIZER;
*mutex = m;
return BHT_OK;
}
int _vm_mutex_destroy(korp_mutex *mutex)
{
sgx_thread_mutex_destroy(mutex);
return BHT_OK;
}
/* Returned error (EINVAL, EAGAIN and EDEADLK) from
locking the mutex indicates some logic error present in
the program somewhere.
Don't try to recover error for an existing unknown error.*/
void vm_mutex_lock(korp_mutex *mutex)
{
sgx_thread_mutex_lock(mutex);
}
int vm_mutex_trylock(korp_mutex *mutex)
{
return (sgx_thread_mutex_trylock(mutex) == 0? BHT_OK: BHT_ERROR);
}
/* Returned error (EINVAL, EAGAIN and EPERM) from
unlocking the mutex indicates some logic error present
in the program somewhere.
Don't try to recover error for an existing unknown error.*/
void vm_mutex_unlock(korp_mutex *mutex)
{
sgx_thread_mutex_unlock(mutex);
}
int _vm_sem_init(korp_sem* sem, unsigned int c)
{
return BHT_OK;
//return BHT_ERROR;
}
int _vm_sem_destroy(korp_sem *sem)
{
return BHT_OK;
//return BHT_ERROR;
}
int _vm_sem_wait(korp_sem *sem)
{
return BHT_OK;
//return BHT_ERROR;
}
int _vm_sem_reltimedwait(korp_sem *sem, int mills)
{
return BHT_OK;
//return BHT_ERROR;
}
int _vm_sem_post(korp_sem *sem)
{
return BHT_OK;
//return BHT_ERROR;
}
int _vm_cond_init(korp_cond *cond)
{
return BHT_OK;
//return BHT_ERROR;
}
int _vm_cond_destroy(korp_cond *cond)
{
return BHT_OK;
//return BHT_ERROR;
}
int _vm_cond_wait(korp_cond *cond, korp_mutex *mutex)
{
return BHT_OK;
//return BHT_ERROR;
}
int _vm_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, int mills)
{
return BHT_OK;
//return BHT_ERROR;
}
int _vm_cond_signal(korp_cond *cond)
{
return BHT_OK;
//return BHT_ERROR;
}
int _vm_cond_broadcast(korp_cond *cond)
{
return BHT_OK;
//return BHT_ERROR;
}
int _vm_thread_cancel(korp_tid thread)
{
return 0;
}
int _vm_thread_join(korp_tid thread, void **value_ptr, int mills)
{
return 0;
}
int _vm_thread_detach(korp_tid thread)
{
return 0;
}

View File

@ -0,0 +1,53 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_time.h"
#include <unistd.h>
#include <stdio.h>
#include <time.h>
/*
* This function returns milliseconds per tick.
* @return milliseconds per tick.
*/
uint64 _bh_time_get_tick_millisecond()
{
//TODO:
return 0;
}
/*
* This function returns milliseconds after boot.
* @return milliseconds after boot.
*/
uint64 _bh_time_get_boot_millisecond()
{
//TODO
return 0;
}
uint32 bh_get_tick_sec()
{
//TODO
return 0;
}
/*
* This function returns GMT time milliseconds since from 1970.1.1, AKA UNIX time.
* @return milliseconds since from 1970.1.1.
*/
uint64 _bh_time_get_millisecond_from_1970()
{
//TODO
return 0;
}
size_t _bh_time_strftime(char *s, size_t max, const char *format, int64 time)
{
//TODO
return 0;
}

View File

@ -0,0 +1,13 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
set (PLATFORM_SHARED_DIR ${CMAKE_CURRENT_LIST_DIR})
include_directories(${PLATFORM_SHARED_DIR})
include_directories(${PLATFORM_SHARED_DIR}/../include)
file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c)
set (PLATFORM_SHARED_SOURCE ${source_all})

View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_platform.h"
#include "bh_assert.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef BH_TEST
#include <setjmp.h>
#endif
#ifdef BH_TEST
/* for exception throwing */
jmp_buf bh_test_jb;
#endif
void bh_assert_internal(int v, const char *file_name, int line_number,
const char *expr_string)
{
if (v)
return;
if (!file_name)
file_name = "NULL FILENAME";
if (!expr_string)
expr_string = "NULL EXPR_STRING";
printf("\nASSERTION FAILED: %s, at FILE=%s, LINE=%d\n", expr_string,
file_name, line_number);
#ifdef BH_TEST
longjmp(bh_test_jb, 1);
#endif
abort();
}
void bh_debug_internal(const char *file_name, int line_number, const char *fmt,
...)
{
#ifndef JEFF_TEST_VERIFIER
va_list args;
va_start(args, fmt);
bh_assert(file_name);
printf("\nDebug info FILE=%s, LINE=%d: ", file_name, line_number);
vprintf(fmt, args);
va_end(args);
printf("\n");
#endif
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_platform.h"
#define RSIZE_MAX 0x7FFFFFFF
int b_memcpy_s(void * s1, unsigned int s1max, const void * s2, unsigned int n)
{
char *dest = (char*) s1;
char *src = (char*) s2;
if (n == 0) {
return 0;
}
if (s1 == NULL || s1max > RSIZE_MAX) {
return -1;
}
if (s2 == NULL || n > s1max) {
memset(dest, 0, s1max);
return -1;
}
memcpy(dest, src, n);
return 0;
}
int b_strcat_s(char * s1, size_t s1max, const char * s2)
{
if (NULL == s1 || NULL == s2
|| s1max < (strlen(s1) + strlen(s2) + 1)
|| s1max > RSIZE_MAX) {
return -1;
}
strcat(s1, s2);
return 0;
}
int b_strcpy_s(char * s1, size_t s1max, const char * s2)
{
if (NULL == s1 || NULL == s2
|| s1max < (strlen(s2) + 1)
|| s1max > RSIZE_MAX) {
return -1;
}
strcpy(s1, s2);
return 0;
}
int fopen_s(FILE ** pFile, const char *filename, const char *mode)
{
if (NULL == pFile || NULL == filename || NULL == mode) {
return -1;
}
*pFile = fopen(filename, mode);
if (NULL == *pFile)
return -1;
return 0;
}

View File

@ -0,0 +1,176 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_platform.h"
#include "bh_common.h"
#include "bh_assert.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
char *bh_strdup(const char *s)
{
uint32 size;
char *s1 = NULL;
if (s) {
size = (uint32)(strlen(s) + 1);
if ((s1 = bh_malloc(size)))
bh_memcpy_s(s1, size, s, size);
}
return s1;
}
int bh_platform_init()
{
return 0;
}
char*
bh_read_file_to_buffer(const char *filename, uint32 *ret_size)
{
char *buffer;
int file;
uint32 file_size, read_size;
struct stat stat_buf;
if (!filename || !ret_size) {
printf("Read file to buffer failed: invalid filename or ret size.\n");
return NULL;
}
if ((file = open(filename, O_RDONLY, 0)) == -1) {
printf("Read file to buffer failed: open file %s failed.\n",
filename);
return NULL;
}
if (fstat(file, &stat_buf) != 0) {
printf("Read file to buffer failed: fstat file %s failed.\n",
filename);
close(file);
return NULL;
}
file_size = (uint32)stat_buf.st_size;
if (!(buffer = bh_malloc(file_size))) {
printf("Read file to buffer failed: alloc memory failed.\n");
close(file);
return NULL;
}
read_size = (uint32)read(file, buffer, file_size);
close(file);
if (read_size < file_size) {
printf("Read file to buffer failed: read file content failed.\n");
bh_free(buffer);
return NULL;
}
*ret_size = file_size;
return buffer;
}
void *
bh_mmap(void *hint, uint32 size, int prot, int flags)
{
int map_prot = PROT_NONE;
int map_flags = MAP_ANONYMOUS | MAP_PRIVATE;
uint64 request_size, page_size;
uint8 *addr, *addr_aligned;
uint32 i;
/* align to 2M if no less than 2M, else align to 4K */
page_size = size < 2 * 1024 * 1024 ? 4096 : 2 * 1024 * 1024;
request_size = (size + page_size - 1) & ~(page_size - 1);
request_size += page_size;
if (request_size >= UINT32_MAX)
return NULL;
if (prot & MMAP_PROT_READ)
map_prot |= PROT_READ;
if (prot & MMAP_PROT_WRITE)
map_prot |= PROT_WRITE;
if (prot & MMAP_PROT_EXEC)
map_prot |= PROT_EXEC;
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
if (flags & MMAP_MAP_32BIT)
map_flags |= MAP_32BIT;
#endif
if (flags & MMAP_MAP_FIXED)
map_flags |= MAP_FIXED;
/* try 5 times */
for (i = 0; i < 5; i ++) {
addr = mmap(hint, size, map_prot, map_flags, -1, 0);
if (addr != MAP_FAILED)
break;
}
if (addr == MAP_FAILED)
return NULL;
addr_aligned = (uint8*)(uintptr_t)
(((uint64)(uintptr_t)addr + page_size - 1) & ~(page_size - 1));
/* Unmap memory allocated before the aligned base address */
if (addr != addr_aligned) {
uint32 prefix_size = (uint32)(addr_aligned - addr);
munmap(addr, prefix_size);
request_size -= prefix_size;
}
/* Unmap memory allocated after the potentially unaligned end */
if (size != request_size) {
uint32 suffix_size = (uint32)(request_size - size);
munmap(addr_aligned + size, suffix_size);
request_size -= size;
}
if (size >= 2 * 1024 * 1024) {
/* Try to use huge page to improve performance */
if (!madvise(addr, size, MADV_HUGEPAGE))
/* make huge page become effective */
memset(addr, 0, size);
}
return addr_aligned;
}
void
bh_munmap(void *addr, uint32 size)
{
if (addr)
munmap(addr, size);
}
int
bh_mprotect(void *addr, uint32 size, int prot)
{
int map_prot = PROT_NONE;
if (!addr)
return 0;
if (prot & MMAP_PROT_READ)
map_prot |= PROT_READ;
if (prot & MMAP_PROT_WRITE)
map_prot |= PROT_WRITE;
if (prot & MMAP_PROT_EXEC)
map_prot |= PROT_EXEC;
return mprotect(addr, size, map_prot);
}

View File

@ -0,0 +1,139 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _BH_PLATFORM_H
#define _BH_PLATFORM_H
#include "bh_config.h"
#include "bh_types.h"
#include "bh_memory.h"
#include <inttypes.h>
#include <stdbool.h>
#include <assert.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdarg.h>
#include <ctype.h>
#include <pthread.h>
#include <semaphore.h>
#include <limits.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netinet/in.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef uint64_t uint64;
typedef int64_t int64;
extern void DEBUGME(void);
#define DIE do{bh_debug("Die here\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); DEBUGME(void); while(1);}while(0)
#ifndef BH_PLATFORM_LINUX
#define BH_PLATFORM_LINUX
#endif
/* NEED qsort */
#define _STACK_SIZE_ADJUSTMENT (32 * 1024)
/* Stack size of applet threads's native part. */
#define BH_APPLET_PRESERVED_STACK_SIZE (8 * 1024 + _STACK_SIZE_ADJUSTMENT)
/* Default thread priority */
#define BH_THREAD_DEFAULT_PRIORITY 0
#define BH_ROUTINE_MODIFIER
#define BHT_TIMEDOUT ETIMEDOUT
#define INVALID_THREAD_ID 0xFFffFFff
typedef pthread_t korp_tid;
typedef pthread_mutex_t korp_mutex;
typedef sem_t korp_sem;
typedef pthread_cond_t korp_cond;
typedef pthread_t korp_thread;
typedef void* (*thread_start_routine_t)(void*);
#define wa_malloc bh_malloc
#define wa_free bh_free
#define wa_strdup bh_strdup
#define bh_printf printf
int snprintf(char *buffer, size_t count, const char *format, ...);
double fmod(double x, double y);
float fmodf(float x, float y);
double sqrt(double x);
#define BH_WAIT_FOREVER 0xFFFFFFFF
#ifndef NULL
# define NULL ((void*) 0)
#endif
/**
* Return the offset of the given field in the given type.
*
* @param Type the type containing the filed
* @param field the field in the type
*
* @return the offset of field in Type
*/
#ifndef offsetof
#define offsetof(Type, field) ((size_t)(&((Type *)0)->field))
#endif
#define bh_assert assert
int b_memcpy_s(void * s1, unsigned int s1max, const void * s2,
unsigned int n);
int b_strcat_s(char * s1, size_t s1max, const char * s2);
int b_strcpy_s(char * s1, size_t s1max, const char * s2);
int fopen_s(FILE ** pFile, const char *filename, const char *mode);
char *bh_read_file_to_buffer(const char *filename, uint32 *ret_size);
char *bh_strdup(const char *s);
int bh_platform_init();
/* MMAP mode */
enum {
MMAP_PROT_NONE = 0,
MMAP_PROT_READ = 1,
MMAP_PROT_WRITE = 2,
MMAP_PROT_EXEC = 4
};
/* MMAP flags */
enum {
MMAP_MAP_NONE = 0,
/* Put the mapping into 0 to 2 G, supported only on x86_64 */
MMAP_MAP_32BIT = 1,
/* Don't interpret addr as a hint: place the mapping at exactly
that address. */
MMAP_MAP_FIXED = 2
};
void *bh_mmap(void *hint, unsigned int size, int prot, int flags);
void bh_munmap(void *addr, uint32 size);
int bh_mprotect(void *addr, uint32 size, int prot);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,30 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_platform.h"
#include <stdio.h>
void bh_log_emit(const char *fmt, va_list ap)
{
vprintf(fmt, ap);
fflush(stdout);
}
int bh_fprintf(FILE *stream, const char *fmt, ...)
{
va_list ap;
int ret;
va_start(ap, fmt);
ret = vfprintf(stream ? stream : stdout, fmt, ap);
va_end(ap);
return ret;
}
int bh_fflush(void *stream)
{
return fflush(stream ? stream : stdout);
}

View File

@ -0,0 +1,393 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_thread.h"
#include "bh_assert.h"
#include "bh_log.h"
#include "bh_memory.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
static bool is_thread_sys_inited = false;
static korp_mutex thread_list_lock;
static pthread_key_t thread_local_storage_key[BH_MAX_TLS_NUM];
int _vm_thread_sys_init()
{
unsigned i, j;
int ret;
if (is_thread_sys_inited)
return 0;
for (i = 0; i < BH_MAX_TLS_NUM; i++) {
ret = pthread_key_create(&thread_local_storage_key[i], NULL);
if (ret)
goto fail;
}
ret = vm_mutex_init(&thread_list_lock);
if (ret)
goto fail;
is_thread_sys_inited = true;
return 0;
fail: for (j = 0; j < i; j++)
pthread_key_delete(thread_local_storage_key[j]);
return -1;
}
void vm_thread_sys_destroy(void)
{
if (is_thread_sys_inited) {
unsigned i;
for (i = 0; i < BH_MAX_TLS_NUM; i++)
pthread_key_delete(thread_local_storage_key[i]);
vm_mutex_destroy(&thread_list_lock);
is_thread_sys_inited = false;
}
}
typedef struct {
thread_start_routine_t start;
void* stack;
uint32 stack_size;
void* arg;
} thread_wrapper_arg;
static void *vm_thread_wrapper(void *arg)
{
thread_wrapper_arg * targ = arg;
LOG_VERBOSE("THREAD CREATE 0x%08x\n", &targ);
targ->stack = (void *)((uintptr_t)(&arg) & (uintptr_t)~0xfff);
_vm_tls_put(1, targ);
targ->start(targ->arg);
bh_free(targ);
_vm_tls_put(1, NULL);
return NULL;
}
int _vm_thread_create_with_prio(korp_tid *tid, thread_start_routine_t start,
void *arg, unsigned int stack_size, int prio)
{
pthread_attr_t tattr;
thread_wrapper_arg *targ;
bh_assert(stack_size > 0);
bh_assert(tid);
bh_assert(start);
*tid = INVALID_THREAD_ID;
pthread_attr_init(&tattr);
pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE);
if (pthread_attr_setstacksize(&tattr, stack_size) != 0) {
bh_debug("Invalid thread stack size %u. Min stack size on Linux = %u",
stack_size, PTHREAD_STACK_MIN);
pthread_attr_destroy(&tattr);
return BHT_ERROR;
}
targ = (thread_wrapper_arg*) bh_malloc(sizeof(*targ));
if (!targ) {
pthread_attr_destroy(&tattr);
return BHT_ERROR;
}
targ->start = start;
targ->arg = arg;
targ->stack_size = stack_size;
if (pthread_create(tid, &tattr, vm_thread_wrapper, targ) != 0) {
pthread_attr_destroy(&tattr);
bh_free(targ);
return BHT_ERROR;
}
pthread_attr_destroy(&tattr);
return BHT_OK;
}
int _vm_thread_create(korp_tid *tid, thread_start_routine_t start, void *arg,
unsigned int stack_size)
{
return _vm_thread_create_with_prio(tid, start, arg, stack_size,
BH_THREAD_DEFAULT_PRIORITY);
}
korp_tid _vm_self_thread()
{
return (korp_tid) pthread_self();
}
void vm_thread_exit(void * code)
{
bh_free(_vm_tls_get(1));
_vm_tls_put(1, NULL);
pthread_exit(code);
}
void *_vm_tls_get(unsigned idx)
{
bh_assert(idx < BH_MAX_TLS_NUM);
return pthread_getspecific(thread_local_storage_key[idx]);
}
int _vm_tls_put(unsigned idx, void * tls)
{
bh_assert(idx < BH_MAX_TLS_NUM);
pthread_setspecific(thread_local_storage_key[idx], tls);
return BHT_OK;
}
int _vm_mutex_init(korp_mutex *mutex)
{
return pthread_mutex_init(mutex, NULL) == 0 ? BHT_OK : BHT_ERROR;
}
int _vm_recursive_mutex_init(korp_mutex *mutex)
{
int ret;
pthread_mutexattr_t mattr;
bh_assert(mutex);
ret = pthread_mutexattr_init(&mattr);
if (ret)
return BHT_ERROR;
pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE_NP);
ret = pthread_mutex_init(mutex, &mattr);
pthread_mutexattr_destroy(&mattr);
return ret == 0 ? BHT_OK : BHT_ERROR;
}
int _vm_mutex_destroy(korp_mutex *mutex)
{
int ret;
bh_assert(mutex);
ret = pthread_mutex_destroy(mutex);
return ret == 0 ? BHT_OK : BHT_ERROR;
}
/* Returned error (EINVAL, EAGAIN and EDEADLK) from
locking the mutex indicates some logic error present in
the program somewhere.
Don't try to recover error for an existing unknown error.*/
void vm_mutex_lock(korp_mutex *mutex)
{
int ret;
bh_assert(mutex);
ret = pthread_mutex_lock(mutex);
if (0 != ret) {
printf("vm mutex lock failed (ret=%d)!\n", ret);
exit(-1);
}
}
int vm_mutex_trylock(korp_mutex *mutex)
{
int ret;
bh_assert(mutex);
ret = pthread_mutex_trylock(mutex);
return ret == 0 ? BHT_OK : BHT_ERROR;
}
/* Returned error (EINVAL, EAGAIN and EPERM) from
unlocking the mutex indicates some logic error present
in the program somewhere.
Don't try to recover error for an existing unknown error.*/
void vm_mutex_unlock(korp_mutex *mutex)
{
int ret;
bh_assert(mutex);
ret = pthread_mutex_unlock(mutex);
if (0 != ret) {
printf("vm mutex unlock failed (ret=%d)!\n", ret);
exit(-1);
}
}
int _vm_sem_init(korp_sem* sem, unsigned int c)
{
int ret;
bh_assert(sem);
ret = sem_init(sem, 0, c);
return ret == 0 ? BHT_OK : BHT_ERROR;
}
int _vm_sem_destroy(korp_sem *sem)
{
int ret;
bh_assert(sem);
ret = sem_destroy(sem);
return ret == 0 ? BHT_OK : BHT_ERROR;
}
int _vm_sem_wait(korp_sem *sem)
{
int ret;
bh_assert(sem);
ret = sem_wait(sem);
return ret == 0 ? BHT_OK : BHT_ERROR;
}
int _vm_sem_reltimedwait(korp_sem *sem, int mills)
{
int ret = BHT_OK;
struct timespec timeout;
const int mills_per_sec = 1000;
const int mills_to_nsec = 1E6;
bh_assert(sem);
if (mills == (int)BHT_WAIT_FOREVER) {
ret = sem_wait(sem);
} else {
timeout.tv_sec = mills / mills_per_sec;
timeout.tv_nsec = (mills % mills_per_sec) * mills_to_nsec;
timeout.tv_sec += time(NULL);
ret = sem_timedwait(sem, &timeout);
}
if (ret != BHT_OK) {
if (errno == BHT_TIMEDOUT) {
ret = BHT_TIMEDOUT;
errno = 0;
} else {
bh_debug("Faliure happens when timed wait is called");
bh_assert(0);
}
}
return ret;
}
int _vm_sem_post(korp_sem *sem)
{
bh_assert(sem);
return sem_post(sem) == 0 ? BHT_OK : BHT_ERROR;
}
int _vm_cond_init(korp_cond *cond)
{
bh_assert(cond);
if (pthread_cond_init(cond, NULL) != BHT_OK)
return BHT_ERROR;
return BHT_OK;
}
int _vm_cond_destroy(korp_cond *cond)
{
bh_assert(cond);
if (pthread_cond_destroy(cond) != BHT_OK)
return BHT_ERROR;
return BHT_OK;
}
int _vm_cond_wait(korp_cond *cond, korp_mutex *mutex)
{
bh_assert(cond);
bh_assert(mutex);
if (pthread_cond_wait(cond, mutex) != BHT_OK)
return BHT_ERROR;
return BHT_OK;
}
static void msec_nsec_to_abstime(struct timespec *ts, int64 msec, int32 nsec)
{
struct timeval tv;
gettimeofday(&tv, NULL);
ts->tv_sec = (long int)(tv.tv_sec + msec / 1000);
ts->tv_nsec = (long int)(tv.tv_usec * 1000 + (msec % 1000) * 1000000 + nsec);
if (ts->tv_nsec >= 1000000000L) {
ts->tv_sec++;
ts->tv_nsec -= 1000000000L;
}
}
int _vm_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, int mills)
{
int ret;
struct timespec abstime;
if (mills == (int)BHT_WAIT_FOREVER)
ret = pthread_cond_wait(cond, mutex);
else {
msec_nsec_to_abstime(&abstime, mills, 0);
ret = pthread_cond_timedwait(cond, mutex, &abstime);
}
if (ret != BHT_OK && ret != BHT_TIMEDOUT)
return BHT_ERROR;
return BHT_OK;
}
int _vm_cond_signal(korp_cond *cond)
{
bh_assert(cond);
if (pthread_cond_signal(cond) != BHT_OK)
return BHT_ERROR;
return BHT_OK;
}
int _vm_cond_broadcast(korp_cond *cond)
{
bh_assert(cond);
if (pthread_cond_broadcast(cond) != BHT_OK)
return BHT_ERROR;
return BHT_OK;
}
int _vm_thread_cancel(korp_tid thread)
{
return pthread_cancel(thread);
}
int _vm_thread_join(korp_tid thread, void **value_ptr, int mills)
{
return pthread_join(thread, value_ptr);
}
int _vm_thread_detach(korp_tid thread)
{
return pthread_detach(thread);
}

View File

@ -0,0 +1,70 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_time.h"
#include <unistd.h>
#include <stdio.h>
#include <sys/timeb.h>
#include <time.h>
/*
* This function returns milliseconds per tick.
* @return milliseconds per tick.
*/
uint64 _bh_time_get_tick_millisecond()
{
return (uint64)sysconf(_SC_CLK_TCK);
}
/*
* This function returns milliseconds after boot.
* @return milliseconds after boot.
*/
uint64 _bh_time_get_boot_millisecond()
{
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
return 0;
}
return ((uint64) ts.tv_sec) * 1000 + ((uint64)ts.tv_nsec) / (1000 * 1000);
}
uint32 bh_get_tick_sec()
{
return (uint32)(_bh_time_get_boot_millisecond() / 1000);
}
/*
* This function returns GMT time milliseconds since from 1970.1.1, AKA UNIX time.
* @return milliseconds since from 1970.1.1.
*/
uint64 _bh_time_get_millisecond_from_1970()
{
struct timeb tp;
ftime(&tp);
return ((uint64) tp.time) * 1000 + tp.millitm
- (tp.dstflag == 0 ? 0 : 60 * 60 * 1000)
+ ((uint64)tp.timezone) * 60 * 1000;
}
size_t _bh_time_strftime(char *s, size_t max, const char *format, int64 time)
{
time_t time_sec = (time_t)(time / 1000);
struct timeb tp;
struct tm *ltp;
ftime(&tp);
time_sec -= tp.timezone * 60;
ltp = localtime(&time_sec);
if (ltp == NULL) {
return 0;
}
return strftime(s, max, format, ltp);
}

View File

@ -0,0 +1,17 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
set (PLATFORM_SHARED_DIR ${CMAKE_CURRENT_LIST_DIR})
include_directories(${PLATFORM_SHARED_DIR})
include_directories(${PLATFORM_SHARED_DIR}/../include)
file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c)
set (PLATFORM_SHARED_SOURCE ${source_all})
LIST (APPEND RUNTIME_LIB_HEADER_LIST "${PLATFORM_SHARED_DIR}/bh_platform.h")
file (GLOB header ${PLATFORM_SHARED_DIR}/../include/*.h)
LIST (APPEND RUNTIME_LIB_HEADER_LIST ${header})

View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_platform.h"
#include "bh_assert.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef BH_TEST
#include <setjmp.h>
#endif
#ifdef BH_TEST
/* for exception throwing */
jmp_buf bh_test_jb;
#endif
void bh_assert_internal(int v, const char *file_name, int line_number,
const char *expr_string)
{
if (v)
return;
if (!file_name)
file_name = "NULL FILENAME";
if (!expr_string)
expr_string = "NULL EXPR_STRING";
printf("\nASSERTION FAILED: %s, at FILE=%s, LINE=%d\n", expr_string,
file_name, line_number);
#ifdef BH_TEST
longjmp(bh_test_jb, 1);
#endif
abort();
}
void bh_debug_internal(const char *file_name, int line_number, const char *fmt,
...)
{
#ifndef JEFF_TEST_VERIFIER
va_list args;
va_start(args, fmt);
bh_assert(file_name);
printf("\nDebug info FILE=%s, LINE=%d: ", file_name, line_number);
vprintf(fmt, args);
va_end(args);
printf("\n");
#endif
}

View File

@ -0,0 +1,53 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_platform.h"
#define RSIZE_MAX 0x7FFFFFFF
int b_memcpy_s(void * s1, unsigned int s1max, const void * s2, unsigned int n)
{
char *dest = (char*) s1;
char *src = (char*) s2;
if (n == 0) {
return 0;
}
if (s1 == NULL || s1max > RSIZE_MAX) {
return -1;
}
if (s2 == NULL || n > s1max) {
memset(dest, 0, s1max);
return -1;
}
memcpy(dest, src, n);
return 0;
}
int b_strcat_s(char * s1, size_t s1max, const char * s2)
{
if (NULL == s1 || NULL == s2
|| s1max < (strlen(s1) + strlen(s2) + 1)
|| s1max > RSIZE_MAX) {
return -1;
}
strcat(s1, s2);
return 0;
}
int b_strcpy_s(char * s1, size_t s1max, const char * s2)
{
if (NULL == s1 || NULL == s2
|| s1max < (strlen(s2) + 1)
|| s1max > RSIZE_MAX) {
return -1;
}
strcpy(s1, s2);
return 0;
}

View File

@ -0,0 +1,181 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_platform.h"
#include "bh_common.h"
#include "bh_assert.h"
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <dlfcn.h>
#include <sys/mman.h>
char *bh_strdup(const char *s)
{
uint32 size;
char *s1 = NULL;
if (s) {
size = (uint32)(strlen(s) + 1);
if ((s1 = bh_malloc(size)))
bh_memcpy_s(s1, size, s, size);
}
return s1;
}
int bh_platform_init()
{
return 0;
}
char*
bh_read_file_to_buffer(const char *filename, uint32 *ret_size)
{
char *buffer;
int file;
uint32 file_size, read_size;
struct stat stat_buf;
if (!filename || !ret_size) {
printf("Read file to buffer failed: invalid filename or ret size.\n");
return NULL;
}
if ((file = open(filename, O_RDONLY, 0)) == -1) {
printf("Read file to buffer failed: open file %s failed.\n",
filename);
return NULL;
}
if (fstat(file, &stat_buf) != 0) {
printf("Read file to buffer failed: fstat file %s failed.\n",
filename);
close(file);
return NULL;
}
file_size = (uint32)stat_buf.st_size;
if (!(buffer = bh_malloc(file_size))) {
printf("Read file to buffer failed: alloc memory failed.\n");
close(file);
return NULL;
}
read_size = (uint32)read(file, buffer, file_size);
close(file);
if (read_size < file_size) {
printf("Read file to buffer failed: read file content failed.\n");
bh_free(buffer);
return NULL;
}
*ret_size = file_size;
return buffer;
}
void *
bh_mmap(void *hint, uint32 size, int prot, int flags)
{
int map_prot = PROT_NONE;
int map_flags = MAP_ANONYMOUS | MAP_PRIVATE;
uint64 request_size, page_size;
uint8 *addr, *addr_aligned;
uint32 i;
/* align to 2M if no less than 2M, else align to 4K */
page_size = size < 2 * 1024 * 1024 ? 4096 : 2 * 1024 * 1024;
request_size = (size + page_size - 1) & ~(page_size - 1);
request_size += page_size;
if (request_size >= UINT32_MAX)
return NULL;
if (prot & MMAP_PROT_READ)
map_prot |= PROT_READ;
if (prot & MMAP_PROT_WRITE)
map_prot |= PROT_WRITE;
if (prot & MMAP_PROT_EXEC)
map_prot |= PROT_EXEC;
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
if (flags & MMAP_MAP_32BIT)
map_flags |= MAP_32BIT;
#endif
if (flags & MMAP_MAP_FIXED)
map_flags |= MAP_FIXED;
/* try 5 times */
for (i = 0; i < 5; i ++) {
addr = mmap(hint, size, map_prot, map_flags, -1, 0);
if (addr != MAP_FAILED)
break;
}
if (addr == MAP_FAILED)
return NULL;
addr_aligned = (uint8*)(uintptr_t)
(((uint64)(uintptr_t)addr + page_size - 1) & ~(page_size - 1));
/* Unmap memory allocated before the aligned base address */
if (addr != addr_aligned) {
uint32 prefix_size = (uint32)(addr_aligned - addr);
munmap(addr, prefix_size);
request_size -= prefix_size;
}
/* Unmap memory allocated after the potentially unaligned end */
if (size != request_size) {
uint32 suffix_size = (uint32)(request_size - size);
munmap(addr_aligned + size, suffix_size);
request_size -= size;
}
if (size >= 2 * 1024 * 1024) {
/* Try to use huge page to improve performance */
if (!madvise(addr, size, MADV_HUGEPAGE))
/* make huge page become effective */
memset(addr, 0, size);
}
return addr_aligned;
}
void
bh_munmap(void *addr, uint32 size)
{
if (addr)
munmap(addr, size);
}
int
bh_mprotect(void *addr, uint32 size, int prot)
{
int map_prot = PROT_NONE;
if (!addr)
return 0;
if (prot & MMAP_PROT_READ)
map_prot |= PROT_READ;
if (prot & MMAP_PROT_WRITE)
map_prot |= PROT_WRITE;
if (prot & MMAP_PROT_EXEC)
map_prot |= PROT_EXEC;
return mprotect(addr, size, map_prot);
}

View File

@ -0,0 +1,136 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _BH_PLATFORM_H
#define _BH_PLATFORM_H
#include "bh_config.h"
#include "bh_types.h"
#include "bh_memory.h"
#include <inttypes.h>
#include <stdbool.h>
#include <assert.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <assert.h>
#include <stdarg.h>
#include <ctype.h>
#include <pthread.h>
#include <limits.h>
#include <fcntl.h>
#include <semaphore.h>
#include <errno.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef uint64_t uint64;
typedef int64_t int64;
extern void DEBUGME(void);
#define DIE do{bh_debug("Die here\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); DEBUGME(void); while(1);}while(0)
#ifndef BH_PLATFORM_VXWORKS
#define BH_PLATFORM_VXWORKS
#endif
/* NEED qsort */
#define _STACK_SIZE_ADJUSTMENT (32 * 1024)
/* Stack size of applet threads's native part. */
#define BH_APPLET_PRESERVED_STACK_SIZE (8 * 1024 + _STACK_SIZE_ADJUSTMENT)
/* Default thread priority */
#define BH_THREAD_DEFAULT_PRIORITY 0
#define BH_ROUTINE_MODIFIER
#define BHT_TIMEDOUT ETIMEDOUT
#define INVALID_THREAD_ID 0xFFffFFff
typedef pthread_t korp_tid;
typedef pthread_mutex_t korp_mutex;
typedef sem_t korp_sem;
typedef pthread_cond_t korp_cond;
typedef pthread_t korp_thread;
typedef void* (*thread_start_routine_t)(void*);
#define wa_malloc bh_malloc
#define wa_free bh_free
#define wa_strdup bh_strdup
#define bh_printf printf
int snprintf(char *buffer, size_t count, const char *format, ...);
double fmod(double x, double y);
float fmodf(float x, float y);
double sqrt(double x);
#define BH_WAIT_FOREVER 0xFFFFFFFF
#ifndef NULL
# define NULL ((void*) 0)
#endif
/**
* Return the offset of the given field in the given type.
*
* @param Type the type containing the filed
* @param field the field in the type
*
* @return the offset of field in Type
*/
#ifndef offsetof
#define offsetof(Type, field) ((size_t)(&((Type *)0)->field))
#endif
#define bh_assert assert
int b_memcpy_s(void * s1, unsigned int s1max, const void * s2,
unsigned int n);
int b_strcat_s(char * s1, size_t s1max, const char * s2);
int b_strcpy_s(char * s1, size_t s1max, const char * s2);
char *bh_read_file_to_buffer(const char *filename, uint32 *ret_size);
char *bh_strdup(const char *s);
int bh_platform_init();
/* MMAP mode */
enum {
MMAP_PROT_NONE = 0,
MMAP_PROT_READ = 1,
MMAP_PROT_WRITE = 2,
MMAP_PROT_EXEC = 4,
};
/* MMAP flags */
enum {
MMAP_MAP_NONE = 0,
/* Put the mapping into 0 to 2 G, supported only on x86_64 */
MMAP_MAP_32BIT = 1,
/* Don't interpret addr as a hint: place the mapping at exactly
that address. */
MMAP_MAP_FIXED = 2
};
void *bh_mmap(void *hint, unsigned int size, int prot, int flags);
void bh_munmap(void *addr, uint32 size);
int bh_mprotect(void *addr, uint32 size, int prot);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,30 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_platform.h"
#include <stdio.h>
void bh_log_emit(const char *fmt, va_list ap)
{
vprintf(fmt, ap);
fflush(stdout);
}
int bh_fprintf(FILE *stream, const char *fmt, ...)
{
va_list ap;
int ret;
va_start(ap, fmt);
ret = vfprintf(stream ? stream : stdout, fmt, ap);
va_end(ap);
return ret;
}
int bh_fflush(void *stream)
{
return fflush(stream ? stream : stdout);
}

View File

@ -0,0 +1,393 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_thread.h"
#include "bh_assert.h"
#include "bh_log.h"
#include "bh_memory.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
static bool is_thread_sys_inited = false;
static korp_mutex thread_list_lock;
static pthread_key_t thread_local_storage_key[BH_MAX_TLS_NUM];
int _vm_thread_sys_init()
{
unsigned i, j;
int ret;
if (is_thread_sys_inited)
return 0;
for (i = 0; i < BH_MAX_TLS_NUM; i++) {
ret = pthread_key_create(&thread_local_storage_key[i], NULL);
if (ret)
goto fail;
}
ret = vm_mutex_init(&thread_list_lock);
if (ret)
goto fail;
is_thread_sys_inited = true;
return 0;
fail: for (j = 0; j < i; j++)
pthread_key_delete(thread_local_storage_key[j]);
return -1;
}
void vm_thread_sys_destroy(void)
{
if (is_thread_sys_inited) {
unsigned i;
for (i = 0; i < BH_MAX_TLS_NUM; i++)
pthread_key_delete(thread_local_storage_key[i]);
vm_mutex_destroy(&thread_list_lock);
is_thread_sys_inited = false;
}
}
typedef struct {
thread_start_routine_t start;
void* stack;
uint32 stack_size;
void* arg;
} thread_wrapper_arg;
static void *vm_thread_wrapper(void *arg)
{
thread_wrapper_arg * targ = arg;
LOG_VERBOSE("THREAD CREATE 0x%08x\n", &targ);
targ->stack = (void *)((uintptr_t)(&arg) & (uintptr_t)~0xfff);
_vm_tls_put(1, targ);
targ->start(targ->arg);
bh_free(targ);
_vm_tls_put(1, NULL);
return NULL;
}
int _vm_thread_create_with_prio(korp_tid *tid, thread_start_routine_t start,
void *arg, unsigned int stack_size, int prio)
{
pthread_attr_t tattr;
thread_wrapper_arg *targ;
bh_assert(stack_size > 0);
bh_assert(tid);
bh_assert(start);
*tid = INVALID_THREAD_ID;
pthread_attr_init(&tattr);
pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE);
if (pthread_attr_setstacksize(&tattr, stack_size) != 0) {
bh_debug("Invalid thread stack size %u. Min stack size on Linux = %u",
stack_size, PTHREAD_STACK_MIN);
pthread_attr_destroy(&tattr);
return BHT_ERROR;
}
targ = (thread_wrapper_arg*) bh_malloc(sizeof(*targ));
if (!targ) {
pthread_attr_destroy(&tattr);
return BHT_ERROR;
}
targ->start = start;
targ->arg = arg;
targ->stack_size = stack_size;
if (pthread_create(tid, &tattr, vm_thread_wrapper, targ) != 0) {
pthread_attr_destroy(&tattr);
bh_free(targ);
return BHT_ERROR;
}
pthread_attr_destroy(&tattr);
return BHT_OK;
}
int _vm_thread_create(korp_tid *tid, thread_start_routine_t start, void *arg,
unsigned int stack_size)
{
return _vm_thread_create_with_prio(tid, start, arg, stack_size,
BH_THREAD_DEFAULT_PRIORITY);
}
korp_tid _vm_self_thread()
{
return (korp_tid) pthread_self();
}
void vm_thread_exit(void * code)
{
bh_free(_vm_tls_get(1));
_vm_tls_put(1, NULL);
pthread_exit(code);
}
void *_vm_tls_get(unsigned idx)
{
bh_assert(idx < BH_MAX_TLS_NUM);
return pthread_getspecific(thread_local_storage_key[idx]);
}
int _vm_tls_put(unsigned idx, void * tls)
{
bh_assert(idx < BH_MAX_TLS_NUM);
pthread_setspecific(thread_local_storage_key[idx], tls);
return BHT_OK;
}
int _vm_mutex_init(korp_mutex *mutex)
{
return pthread_mutex_init(mutex, NULL) == 0 ? BHT_OK : BHT_ERROR;
}
int _vm_recursive_mutex_init(korp_mutex *mutex)
{
int ret;
pthread_mutexattr_t mattr;
bh_assert(mutex);
ret = pthread_mutexattr_init(&mattr);
if (ret)
return BHT_ERROR;
pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE);
ret = pthread_mutex_init(mutex, &mattr);
pthread_mutexattr_destroy(&mattr);
return ret == 0 ? BHT_OK : BHT_ERROR;
}
int _vm_mutex_destroy(korp_mutex *mutex)
{
int ret;
bh_assert(mutex);
ret = pthread_mutex_destroy(mutex);
return ret == 0 ? BHT_OK : BHT_ERROR;
}
/* Returned error (EINVAL, EAGAIN and EDEADLK) from
locking the mutex indicates some logic error present in
the program somewhere.
Don't try to recover error for an existing unknown error.*/
void vm_mutex_lock(korp_mutex *mutex)
{
int ret;
bh_assert(mutex);
ret = pthread_mutex_lock(mutex);
if (0 != ret) {
printf("vm mutex lock failed (ret=%d)!\n", ret);
exit(-1);
}
}
int vm_mutex_trylock(korp_mutex *mutex)
{
int ret;
bh_assert(mutex);
ret = pthread_mutex_trylock(mutex);
return ret == 0 ? BHT_OK : BHT_ERROR;
}
/* Returned error (EINVAL, EAGAIN and EPERM) from
unlocking the mutex indicates some logic error present
in the program somewhere.
Don't try to recover error for an existing unknown error.*/
void vm_mutex_unlock(korp_mutex *mutex)
{
int ret;
bh_assert(mutex);
ret = pthread_mutex_unlock(mutex);
if (0 != ret) {
printf("vm mutex unlock failed (ret=%d)!\n", ret);
exit(-1);
}
}
int _vm_sem_init(korp_sem* sem, unsigned int c)
{
int ret;
bh_assert(sem);
ret = sem_init(sem, 0, c);
return ret == 0 ? BHT_OK : BHT_ERROR;
}
int _vm_sem_destroy(korp_sem *sem)
{
int ret;
bh_assert(sem);
ret = sem_destroy(sem);
return ret == 0 ? BHT_OK : BHT_ERROR;
}
int _vm_sem_wait(korp_sem *sem)
{
int ret;
bh_assert(sem);
ret = sem_wait(sem);
return ret == 0 ? BHT_OK : BHT_ERROR;
}
int _vm_sem_reltimedwait(korp_sem *sem, int mills)
{
int ret = BHT_OK;
struct timespec timeout;
const int mills_per_sec = 1000;
const int mills_to_nsec = 1E6;
bh_assert(sem);
if (mills == (int)BHT_WAIT_FOREVER) {
ret = sem_wait(sem);
} else {
timeout.tv_sec = mills / mills_per_sec;
timeout.tv_nsec = (mills % mills_per_sec) * mills_to_nsec;
timeout.tv_sec += time(NULL);
ret = sem_timedwait(sem, &timeout);
}
if (ret != BHT_OK) {
if (errno == BHT_TIMEDOUT) {
ret = BHT_TIMEDOUT;
errno = 0;
} else {
bh_debug("Faliure happens when timed wait is called");
bh_assert(0);
}
}
return ret;
}
int _vm_sem_post(korp_sem *sem)
{
bh_assert(sem);
return sem_post(sem) == 0 ? BHT_OK : BHT_ERROR;
}
int _vm_cond_init(korp_cond *cond)
{
bh_assert(cond);
if (pthread_cond_init(cond, NULL) != BHT_OK)
return BHT_ERROR;
return BHT_OK;
}
int _vm_cond_destroy(korp_cond *cond)
{
bh_assert(cond);
if (pthread_cond_destroy(cond) != BHT_OK)
return BHT_ERROR;
return BHT_OK;
}
int _vm_cond_wait(korp_cond *cond, korp_mutex *mutex)
{
bh_assert(cond);
bh_assert(mutex);
if (pthread_cond_wait(cond, mutex) != BHT_OK)
return BHT_ERROR;
return BHT_OK;
}
static void msec_nsec_to_abstime(struct timespec *ts, int64 msec, int32 nsec)
{
struct timeval tv;
gettimeofday(&tv, NULL);
ts->tv_sec = (long int)(tv.tv_sec + msec / 1000);
ts->tv_nsec = (long int)(tv.tv_usec * 1000 + (msec % 1000) * 1000000 + nsec);
if (ts->tv_nsec >= 1000000000L) {
ts->tv_sec++;
ts->tv_nsec -= 1000000000L;
}
}
int _vm_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, int mills)
{
int ret;
struct timespec abstime;
if (mills == (int)BHT_WAIT_FOREVER)
ret = pthread_cond_wait(cond, mutex);
else {
msec_nsec_to_abstime(&abstime, mills, 0);
ret = pthread_cond_timedwait(cond, mutex, &abstime);
}
if (ret != BHT_OK && ret != BHT_TIMEDOUT)
return BHT_ERROR;
return BHT_OK;
}
int _vm_cond_signal(korp_cond *cond)
{
bh_assert(cond);
if (pthread_cond_signal(cond) != BHT_OK)
return BHT_ERROR;
return BHT_OK;
}
int _vm_cond_broadcast(korp_cond *cond)
{
bh_assert(cond);
if (pthread_cond_broadcast(cond) != BHT_OK)
return BHT_ERROR;
return BHT_OK;
}
int _vm_thread_cancel(korp_tid thread)
{
return pthread_cancel(thread);
}
int _vm_thread_join(korp_tid thread, void **value_ptr, int mills)
{
return pthread_join(thread, value_ptr);
}
int _vm_thread_detach(korp_tid thread)
{
return pthread_detach(thread);
}

View File

@ -0,0 +1,66 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_time.h"
#include <unistd.h>
#include <stdio.h>
#include <time.h>
/*
* This function returns milliseconds per tick.
* @return milliseconds per tick.
*/
uint64 _bh_time_get_tick_millisecond()
{
return (uint64)sysconf(_SC_CLK_TCK);
}
/*
* This function returns milliseconds after boot.
* @return milliseconds after boot.
*/
uint64 _bh_time_get_boot_millisecond()
{
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
return 0;
}
return ((uint64) ts.tv_sec) * 1000 + ((uint64)ts.tv_nsec) / (1000 * 1000);
}
uint32 bh_get_tick_sec()
{
return (uint32)(_bh_time_get_boot_millisecond() / 1000);
}
/*
* This function returns GMT time milliseconds since from 1970.1.1, AKA UNIX time.
* @return milliseconds since from 1970.1.1.
*/
uint64 _bh_time_get_millisecond_from_1970()
{
struct timespec ts;
if (clock_gettime(CLOCK_REALTIME, &ts) != 0) {
return 0;
}
return ((uint64) ts.tv_sec) * 1000 + ((uint64)ts.tv_nsec) / (1000 * 1000);
}
size_t _bh_time_strftime(char *s, size_t max, const char *format, int64 time)
{
time_t time_sec = (time_t)(time / 1000);
struct tm *ltp;
ltp = localtime(&time_sec);
if (ltp == NULL) {
return 0;
}
return strftime(s, max, format, ltp);
}

View File

@ -0,0 +1,13 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
set (PLATFORM_SHARED_DIR ${CMAKE_CURRENT_LIST_DIR})
include_directories(${PLATFORM_SHARED_DIR})
include_directories(${PLATFORM_SHARED_DIR}/../include)
file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c)
set (PLATFORM_SHARED_SOURCE ${source_all})

View File

@ -0,0 +1,126 @@
# $FreeBSD$
# @(#)COPYRIGHT 8.2 (Berkeley) 3/21/94
The compilation of software known as FreeBSD is distributed under the
following terms:
Copyright (c) 1992-2019 The FreeBSD Project.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
The 4.4BSD and 4.4BSD-Lite software is distributed under the following
terms:
All of the documentation and software included in the 4.4BSD and 4.4BSD-Lite
Releases is copyrighted by The Regents of the University of California.
Copyright 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994
The Regents of the University of California. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. All advertising materials mentioning features or use of this software
must display the following acknowledgement:
This product includes software developed by the University of
California, Berkeley and its contributors.
4. Neither the name of the University nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
The Institute of Electrical and Electronics Engineers and the American
National Standards Committee X3, on Information Processing Systems have
given us permission to reprint portions of their documentation.
In the following statement, the phrase ``this text'' refers to portions
of the system documentation.
Portions of this text are reprinted and reproduced in electronic form in
the second BSD Networking Software Release, from IEEE Std 1003.1-1988, IEEE
Standard Portable Operating System Interface for Computer Environments
(POSIX), copyright C 1988 by the Institute of Electrical and Electronics
Engineers, Inc. In the event of any discrepancy between these versions
and the original IEEE Standard, the original IEEE Standard is the referee
document.
In the following statement, the phrase ``This material'' refers to portions
of the system documentation.
This material is reproduced with permission from American National
Standards Committee X3, on Information Processing Systems. Computer and
Business Equipment Manufacturers Association (CBEMA), 311 First St., NW,
Suite 500, Washington, DC 20001-2178. The developmental work of
Programming Language C was completed by the X3J11 Technical Committee.
The views and conclusions contained in the software and documentation are
those of the authors and should not be interpreted as representing official
policies, either expressed or implied, of the Regents of the University
of California.
NOTE: The copyright of UC Berkeley's Berkeley Software Distribution ("BSD")
source has been updated. The copyright addendum may be found at
ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change and is
included below.
July 22, 1999
To All Licensees, Distributors of Any Version of BSD:
As you know, certain of the Berkeley Software Distribution ("BSD") source
code files require that further distributions of products containing all or
portions of the software, acknowledge within their advertising materials
that such products contain software developed by UC Berkeley and its
contributors.
Specifically, the provision reads:
" * 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors."
Effective immediately, licensees and distributors are no longer required to
include the acknowledgement within advertising materials. Accordingly, the
foregoing paragraph of those BSD Unix files containing it is hereby deleted
in its entirety.
William Hoskins
Director, Office of Technology Licensing
University of California, Berkeley

View File

@ -0,0 +1,4 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
obj-y += bh_assert.o bh_definition.o bh_memory.o bh_platform_log.o bh_thread.o bh_time.o

View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_platform.h"
#include "bh_assert.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef BH_TEST
#include <setjmp.h>
#endif
#ifdef BH_TEST
/* for exception throwing */
jmp_buf bh_test_jb;
#endif
extern void abort(void);
void bh_assert_internal(int v, const char *file_name, int line_number,
const char *expr_string)
{
if (v)
return;
if (!file_name)
file_name = "NULL FILENAME";
if (!expr_string)
expr_string = "NULL EXPR_STRING";
printk("\nASSERTION FAILED: %s, at FILE=%s, LINE=%d\n", expr_string,
file_name, line_number);
#ifdef BH_TEST
longjmp(bh_test_jb, 1);
#endif
abort();
}
void bh_debug_internal(const char *file_name, int line_number, const char *fmt,
...)
{
#ifndef JEFF_TEST_VERIFIER
va_list args;
va_start(args, fmt);
bh_assert(file_name);
printf("\nDebug info FILE=%s, LINE=%d: ", file_name, line_number);
vprintf(fmt, args);
va_end(args);
printf("\n");
#endif
}

View File

@ -0,0 +1,53 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_platform.h"
#define RSIZE_MAX 0x7FFFFFFF
int b_memcpy_s(void * s1, unsigned int s1max, const void * s2, unsigned int n)
{
char *dest = (char*) s1;
char *src = (char*) s2;
if (n == 0) {
return 0;
}
if (s1 == NULL || s1max > RSIZE_MAX) {
return -1;
}
if (s2 == NULL || n > s1max) {
memset(dest, 0, s1max);
return -1;
}
memcpy(dest, src, n);
return 0;
}
int b_strcat_s(char * s1, size_t s1max, const char * s2)
{
if (NULL == s1 || NULL == s2
|| s1max < (strlen(s1) + strlen(s2) + 1)
|| s1max > RSIZE_MAX) {
return -1;
}
strcat(s1, s2);
return 0;
}
int b_strcpy_s(char * s1, size_t s1max, const char * s2)
{
if (NULL == s1|| NULL == s2
|| s1max < (strlen(s2) + 1) || s1max > RSIZE_MAX) {
return -1;
}
strcpy(s1, s2);
return 0;
}

View File

@ -0,0 +1,861 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include "bh_platform.h"
#define __FDLIBM_STDC__
typedef uint32_t u_int32_t;
typedef uint64_t u_int64_t;
typedef union u32double_tag {
int *pint;
double *pdouble;
} U32DOUBLE;
static inline int *
pdouble2pint(double *pdouble)
{
U32DOUBLE u;
u.pdouble = pdouble;
return u.pint;
}
typedef union
{
double value;
struct
{
u_int32_t lsw;
u_int32_t msw;
} parts;
struct
{
u_int64_t w;
} xparts;
} ieee_double_shape_type_little;
typedef union
{
double value;
struct
{
u_int32_t msw;
u_int32_t lsw;
} parts;
struct
{
u_int64_t w;
} xparts;
} ieee_double_shape_type_big;
typedef union {
double d;
struct {
unsigned int manl :32;
unsigned int manh :20;
unsigned int exp :11;
unsigned int sign :1;
} bits;
} IEEEd2bits_L;
typedef union {
double d;
struct {
unsigned int sign :1;
unsigned int exp :11;
unsigned int manh :20;
unsigned int manl :32;
} bits;
} IEEEd2bits_B;
typedef union {
float f;
struct {
unsigned int man :23;
unsigned int exp :8;
unsigned int sign :1;
} bits;
} IEEEf2bits_L;
typedef union {
float f;
struct {
unsigned int sign :1;
unsigned int exp :8;
unsigned int man :23;
} bits;
} IEEEf2bits_B;
static union {
int a;
char b;
} __ue = { .a = 1 };
#define is_little_endian() (__ue.b == 1)
#define __HIL(x) *(1+pdouble2pint(&x))
#define __LOL(x) *(pdouble2pint(&x))
#define __HIB(x) *(int*)&x
#define __LOB(x) *(1+(int*)&x)
/* Get two 32 bit ints from a double. */
#define EXTRACT_WORDS_L(ix0,ix1,d) \
do { \
ieee_double_shape_type_little ew_u; \
ew_u.value = (d); \
(ix0) = ew_u.parts.msw; \
(ix1) = ew_u.parts.lsw; \
} while (0)
/* Set a double from two 32 bit ints. */
#define INSERT_WORDS_L(d,ix0,ix1) \
do { \
ieee_double_shape_type_little iw_u; \
iw_u.parts.msw = (ix0); \
iw_u.parts.lsw = (ix1); \
(d) = iw_u.value; \
} while (0)
/* Get two 32 bit ints from a double. */
#define EXTRACT_WORDS_B(ix0,ix1,d) \
do { \
ieee_double_shape_type_big ew_u; \
ew_u.value = (d); \
(ix0) = ew_u.parts.msw; \
(ix1) = ew_u.parts.lsw; \
} while (0)
/* Set a double from two 32 bit ints. */
#define INSERT_WORDS_B(d,ix0,ix1) \
do { \
ieee_double_shape_type_big iw_u; \
iw_u.parts.msw = (ix0); \
iw_u.parts.lsw = (ix1); \
(d) = iw_u.value; \
} while (0)
/* Get the more significant 32 bit int from a double. */
#define GET_HIGH_WORD_L(i,d) \
do { \
ieee_double_shape_type_little gh_u; \
gh_u.value = (d); \
(i) = gh_u.parts.msw; \
} while (0)
/* Get the more significant 32 bit int from a double. */
#define GET_HIGH_WORD_B(i,d) \
do { \
ieee_double_shape_type_big gh_u; \
gh_u.value = (d); \
(i) = gh_u.parts.msw; \
} while (0)
/* Set the more significant 32 bits of a double from an int. */
#define SET_HIGH_WORD_L(d,v) \
do { \
ieee_double_shape_type_little sh_u; \
sh_u.value = (d); \
sh_u.parts.msw = (v); \
(d) = sh_u.value; \
} while (0)
/* Set the more significant 32 bits of a double from an int. */
#define SET_HIGH_WORD_B(d,v) \
do { \
ieee_double_shape_type_big sh_u; \
sh_u.value = (d); \
sh_u.parts.msw = (v); \
(d) = sh_u.value; \
} while (0)
/*
* A union which permits us to convert between a float and a 32 bit
* int.
*/
typedef union
{
float value;
/* FIXME: Assumes 32 bit int. */
unsigned int word;
} ieee_float_shape_type;
/* Get a 32 bit int from a float. */
#define GET_FLOAT_WORD(i,d) \
do { \
ieee_float_shape_type gf_u; \
gf_u.value = (d); \
(i) = gf_u.word; \
} while (0)
/* Set a float from a 32 bit int. */
#define SET_FLOAT_WORD(d,i) \
do { \
ieee_float_shape_type sf_u; \
sf_u.word = (i); \
(d) = sf_u.value; \
} while (0)
/* Macro wrappers. */
#define EXTRACT_WORDS(ix0,ix1,d) do { \
if (is_little_endian()) \
EXTRACT_WORDS_L(ix0,ix1,d); \
else \
EXTRACT_WORDS_B(ix0,ix1,d); \
} while (0)
#define INSERT_WORDS(d,ix0,ix1) do { \
if (is_little_endian()) \
INSERT_WORDS_L(d,ix0,ix1); \
else \
INSERT_WORDS_B(d,ix0,ix1); \
} while (0)
#define GET_HIGH_WORD(i,d) \
do { \
if (is_little_endian()) \
GET_HIGH_WORD_L(i,d); \
else \
GET_HIGH_WORD_B(i,d); \
} while (0)
#define SET_HIGH_WORD(d,v) \
do { \
if (is_little_endian()) \
SET_HIGH_WORD_L(d,v); \
else \
SET_HIGH_WORD_B(d,v); \
} while (0)
#define __HI(x) (is_little_endian() ? __HIL(x) : __HIB(x))
#define __LO(x) (is_little_endian() ? __LOL(x) : __LOB(x))
/*
* Attempt to get strict C99 semantics for assignment with non-C99 compilers.
*/
#if FLT_EVAL_METHOD == 0 || __GNUC__ == 0
#define STRICT_ASSIGN(type, lval, rval) ((lval) = (rval))
#else
#define STRICT_ASSIGN(type, lval, rval) do { \
volatile type __lval; \
\
if (sizeof(type) >= sizeof(long double)) \
(lval) = (rval); \
else { \
__lval = (rval); \
(lval) = __lval; \
} \
} while (0)
#endif
#ifdef __FDLIBM_STDC__
static const double huge = 1.0e300;
#else
static double huge = 1.0e300;
#endif
#ifdef __STDC__
static const double
#else
static double
#endif
tiny = 1.0e-300;
#ifdef __STDC__
static const double
#else
static double
#endif
one= 1.00000000000000000000e+00; /* 0x3FF00000, 0x00000000 */
#ifdef __STDC__
static const double
#else
static double
#endif
TWO52[2]={
4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
-4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */
};
static double freebsd_sqrt(double x);
static double freebsd_floor(double x);
static double freebsd_ceil(double x);
static double freebsd_fabs(double x);
static double freebsd_rint(double x);
static int freebsd_isnan(double x);
static double freebsd_sqrt(double x) /* wrapper sqrt */
{
double z;
int32_t sign = (int)0x80000000;
int32_t ix0,s0,q,m,t,i;
u_int32_t r,t1,s1,ix1,q1;
EXTRACT_WORDS(ix0,ix1,x);
/* take care of Inf and NaN */
if((ix0&0x7ff00000)==0x7ff00000) {
return x*x+x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf
sqrt(-inf)=sNaN */
}
/* take care of zero */
if(ix0<=0) {
if(((ix0&(~sign))|ix1)==0) return x;/* sqrt(+-0) = +-0 */
else if(ix0<0)
return (x-x)/(x-x); /* sqrt(-ve) = sNaN */
}
/* normalize x */
m = (ix0>>20);
if(m==0) { /* subnormal x */
while(ix0==0) {
m -= 21;
ix0 |= (ix1>>11); ix1 <<= 21;
}
for(i=0;(ix0&0x00100000)==0;i++) ix0<<=1;
m -= i-1;
ix0 |= (ix1>>(32-i));
ix1 <<= i;
}
m -= 1023; /* unbias exponent */
ix0 = (ix0&0x000fffff)|0x00100000;
if(m&1){ /* odd m, double x to make it even */
ix0 += ix0 + ((ix1&sign)>>31);
ix1 += ix1;
}
m >>= 1; /* m = [m/2] */
/* generate sqrt(x) bit by bit */
ix0 += ix0 + ((ix1&sign)>>31);
ix1 += ix1;
q = q1 = s0 = s1 = 0; /* [q,q1] = sqrt(x) */
r = 0x00200000; /* r = moving bit from right to left */
while(r!=0) {
t = s0+r;
if(t<=ix0) {
s0 = t+r;
ix0 -= t;
q += r;
}
ix0 += ix0 + ((ix1&sign)>>31);
ix1 += ix1;
r>>=1;
}
r = sign;
while(r!=0) {
t1 = s1+r;
t = s0;
if((t<ix0)||((t==ix0)&&(t1<=ix1))) {
s1 = t1+r;
if(((t1&sign)==sign)&&(s1&sign)==0) s0 += 1;
ix0 -= t;
if (ix1 < t1) ix0 -= 1;
ix1 -= t1;
q1 += r;
}
ix0 += ix0 + ((ix1&sign)>>31);
ix1 += ix1;
r>>=1;
}
/* use floating add to find out rounding direction */
if((ix0|ix1)!=0) {
z = one-tiny; /* trigger inexact flag */
if (z>=one) {
z = one+tiny;
if (q1==(u_int32_t)0xffffffff) { q1=0; q += 1;}
else if (z>one) {
if (q1==(u_int32_t)0xfffffffe) q+=1;
q1+=2;
} else
q1 += (q1&1);
}
}
ix0 = (q>>1)+0x3fe00000;
ix1 = q1>>1;
if ((q&1)==1) ix1 |= sign;
ix0 += (m <<20);
INSERT_WORDS(z,ix0,ix1);
return z;
}
static double freebsd_floor(double x)
{
int32_t i0,i1,j0;
u_int32_t i,j;
EXTRACT_WORDS(i0,i1,x);
j0 = ((i0>>20)&0x7ff)-0x3ff;
if(j0<20) {
if(j0<0) { /* raise inexact if x != 0 */
if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */
if(i0>=0) {i0=i1=0;}
else if(((i0&0x7fffffff)|i1)!=0)
{ i0=0xbff00000;i1=0;}
}
} else {
i = (0x000fffff)>>j0;
if(((i0&i)|i1)==0) return x; /* x is integral */
if(huge+x>0.0) { /* raise inexact flag */
if(i0<0) i0 += (0x00100000)>>j0;
i0 &= (~i); i1=0;
}
}
} else if (j0>51) {
if(j0==0x400) return x+x; /* inf or NaN */
else return x; /* x is integral */
} else {
i = ((u_int32_t)(0xffffffff))>>(j0-20);
if((i1&i)==0) return x; /* x is integral */
if(huge+x>0.0) { /* raise inexact flag */
if(i0<0) {
if(j0==20) i0+=1;
else {
j = i1+(1<<(52-j0));
if(j<i1) i0 +=1 ; /* got a carry */
i1=j;
}
}
i1 &= (~i);
}
}
INSERT_WORDS(x,i0,i1);
return x;
}
static double freebsd_ceil(double x)
{
int32_t i0,i1,j0;
u_int32_t i,j;
EXTRACT_WORDS(i0,i1,x);
j0 = ((i0>>20)&0x7ff)-0x3ff;
if(j0<20) {
if(j0<0) { /* raise inexact if x != 0 */
if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */
if(i0<0) {i0=0x80000000;i1=0;}
else if((i0|i1)!=0) { i0=0x3ff00000;i1=0;}
}
} else {
i = (0x000fffff)>>j0;
if(((i0&i)|i1)==0) return x; /* x is integral */
if(huge+x>0.0) { /* raise inexact flag */
if(i0>0) i0 += (0x00100000)>>j0;
i0 &= (~i); i1=0;
}
}
} else if (j0>51) {
if(j0==0x400) return x+x; /* inf or NaN */
else return x; /* x is integral */
} else {
i = ((u_int32_t)(0xffffffff))>>(j0-20);
if((i1&i)==0) return x; /* x is integral */
if(huge+x>0.0) { /* raise inexact flag */
if(i0>0) {
if(j0==20) i0+=1;
else {
j = i1 + (1<<(52-j0));
if(j<i1) i0+=1; /* got a carry */
i1 = j;
}
}
i1 &= (~i);
}
}
INSERT_WORDS(x,i0,i1);
return x;
}
static double freebsd_rint(double x)
{
int32_t i0,j0,sx;
u_int32_t i,i1;
double w,t;
EXTRACT_WORDS(i0,i1,x);
sx = (i0>>31)&1;
j0 = ((i0>>20)&0x7ff)-0x3ff;
if(j0<20) {
if(j0<0) {
if(((i0&0x7fffffff)|i1)==0) return x;
i1 |= (i0&0x0fffff);
i0 &= 0xfffe0000;
i0 |= ((i1|-i1)>>12)&0x80000;
SET_HIGH_WORD(x,i0);
STRICT_ASSIGN(double,w,TWO52[sx]+x);
t = w-TWO52[sx];
GET_HIGH_WORD(i0,t);
SET_HIGH_WORD(t,(i0&0x7fffffff)|(sx<<31));
return t;
} else {
i = (0x000fffff)>>j0;
if(((i0&i)|i1)==0) return x; /* x is integral */
i>>=1;
if(((i0&i)|i1)!=0) {
/*
* Some bit is set after the 0.5 bit. To avoid the
* possibility of errors from double rounding in
* w = TWO52[sx]+x, adjust the 0.25 bit to a lower
* guard bit. We do this for all j0<=51. The
* adjustment is trickiest for j0==18 and j0==19
* since then it spans the word boundary.
*/
if(j0==19) i1 = 0x40000000; else
if(j0==18) i1 = 0x80000000; else
i0 = (i0&(~i))|((0x20000)>>j0);
}
}
} else if (j0>51) {
if(j0==0x400) return x+x; /* inf or NaN */
else return x; /* x is integral */
} else {
i = ((u_int32_t)(0xffffffff))>>(j0-20);
if((i1&i)==0) return x; /* x is integral */
i>>=1;
if((i1&i)!=0) i1 = (i1&(~i))|((0x40000000)>>(j0-20));
}
INSERT_WORDS(x,i0,i1);
STRICT_ASSIGN(double,w,TWO52[sx]+x);
return w-TWO52[sx];
}
static int freebsd_isnan(double d)
{
if (is_little_endian()) {
IEEEd2bits_L u;
u.d = d;
return (u.bits.exp == 2047 && (u.bits.manl != 0 || u.bits.manh != 0));
}
else {
IEEEd2bits_B u;
u.d = d;
return (u.bits.exp == 2047 && (u.bits.manl != 0 || u.bits.manh != 0));
}
}
static double freebsd_fabs(double x)
{
u_int32_t high;
GET_HIGH_WORD(high,x);
SET_HIGH_WORD(x,high&0x7fffffff);
return x;
}
static const float huge_f = 1.0e30F;
static const float
TWO23[2]={
8.3886080000e+06, /* 0x4b000000 */
-8.3886080000e+06, /* 0xcb000000 */
};
static float
freebsd_truncf(float x)
{
int32_t i0,j0;
u_int32_t i;
GET_FLOAT_WORD(i0,x);
j0 = ((i0>>23)&0xff)-0x7f;
if(j0<23) {
if(j0<0) { /* raise inexact if x != 0 */
if(huge_f+x>0.0F) /* |x|<1, so return 0*sign(x) */
i0 &= 0x80000000;
} else {
i = (0x007fffff)>>j0;
if((i0&i)==0) return x; /* x is integral */
if(huge_f+x>0.0F) /* raise inexact flag */
i0 &= (~i);
}
} else {
if(j0==0x80) return x+x; /* inf or NaN */
else return x; /* x is integral */
}
SET_FLOAT_WORD(x,i0);
return x;
}
static float
freebsd_rintf(float x)
{
int32_t i0,j0,sx;
float w,t;
GET_FLOAT_WORD(i0,x);
sx = (i0>>31)&1;
j0 = ((i0>>23)&0xff)-0x7f;
if(j0<23) {
if(j0<0) {
if((i0&0x7fffffff)==0) return x;
STRICT_ASSIGN(float,w,TWO23[sx]+x);
t = w-TWO23[sx];
GET_FLOAT_WORD(i0,t);
SET_FLOAT_WORD(t,(i0&0x7fffffff)|(sx<<31));
return t;
}
STRICT_ASSIGN(float,w,TWO23[sx]+x);
return w-TWO23[sx];
}
if(j0==0x80) return x+x; /* inf or NaN */
else return x; /* x is integral */
}
static float
freebsd_ceilf(float x)
{
int32_t i0,j0;
u_int32_t i;
GET_FLOAT_WORD(i0,x);
j0 = ((i0>>23)&0xff)-0x7f;
if(j0<23) {
if(j0<0) { /* raise inexact if x != 0 */
if(huge_f+x>(float)0.0) {/* return 0*sign(x) if |x|<1 */
if(i0<0) {i0=0x80000000;}
else if(i0!=0) { i0=0x3f800000;}
}
} else {
i = (0x007fffff)>>j0;
if((i0&i)==0) return x; /* x is integral */
if(huge_f+x>(float)0.0) { /* raise inexact flag */
if(i0>0) i0 += (0x00800000)>>j0;
i0 &= (~i);
}
}
} else {
if(j0==0x80) return x+x; /* inf or NaN */
else return x; /* x is integral */
}
SET_FLOAT_WORD(x,i0);
return x;
}
static float
freebsd_floorf(float x)
{
int32_t i0,j0;
u_int32_t i;
GET_FLOAT_WORD(i0,x);
j0 = ((i0>>23)&0xff)-0x7f;
if(j0<23) {
if(j0<0) { /* raise inexact if x != 0 */
if(huge_f+x>(float)0.0) {/* return 0*sign(x) if |x|<1 */
if(i0>=0) {i0=0;}
else if((i0&0x7fffffff)!=0)
{ i0=0xbf800000;}
}
} else {
i = (0x007fffff)>>j0;
if((i0&i)==0) return x; /* x is integral */
if(huge_f+x>(float)0.0) { /* raise inexact flag */
if(i0<0) i0 += (0x00800000)>>j0;
i0 &= (~i);
}
}
} else {
if(j0==0x80) return x+x; /* inf or NaN */
else return x; /* x is integral */
}
SET_FLOAT_WORD(x,i0);
return x;
}
static float
freebsd_fminf(float x, float y)
{
if (is_little_endian()) {
IEEEf2bits_L u[2];
u[0].f = x;
u[1].f = y;
/* Check for NaNs to avoid raising spurious exceptions. */
if (u[0].bits.exp == 255 && u[0].bits.man != 0)
return (y);
if (u[1].bits.exp == 255 && u[1].bits.man != 0)
return (x);
/* Handle comparisons of signed zeroes. */
if (u[0].bits.sign != u[1].bits.sign)
return (u[u[1].bits.sign].f);
}
else {
IEEEf2bits_B u[2];
u[0].f = x;
u[1].f = y;
/* Check for NaNs to avoid raising spurious exceptions. */
if (u[0].bits.exp == 255 && u[0].bits.man != 0)
return (y);
if (u[1].bits.exp == 255 && u[1].bits.man != 0)
return (x);
/* Handle comparisons of signed zeroes. */
if (u[0].bits.sign != u[1].bits.sign)
return (u[u[1].bits.sign].f);
}
return (x < y ? x : y);
}
static float
freebsd_fmaxf(float x, float y)
{
if (is_little_endian()) {
IEEEf2bits_L u[2];
u[0].f = x;
u[1].f = y;
/* Check for NaNs to avoid raising spurious exceptions. */
if (u[0].bits.exp == 255 && u[0].bits.man != 0)
return (y);
if (u[1].bits.exp == 255 && u[1].bits.man != 0)
return (x);
/* Handle comparisons of signed zeroes. */
if (u[0].bits.sign != u[1].bits.sign)
return (u[u[0].bits.sign].f);
}
else {
IEEEf2bits_B u[2];
u[0].f = x;
u[1].f = y;
/* Check for NaNs to avoid raising spurious exceptions. */
if (u[0].bits.exp == 255 && u[0].bits.man != 0)
return (y);
if (u[1].bits.exp == 255 && u[1].bits.man != 0)
return (x);
/* Handle comparisons of signed zeroes. */
if (u[0].bits.sign != u[1].bits.sign)
return (u[u[0].bits.sign].f);
}
return (x > y ? x : y);
}
double sqrt(double x)
{
return freebsd_sqrt(x);
}
double floor(double x)
{
return freebsd_floor(x);
}
double ceil(double x)
{
return freebsd_ceil(x);
}
double fmin(double x, double y)
{
return x < y ? x : y;
}
double fmax(double x, double y)
{
return x > y ? x : y;
}
double rint(double x)
{
return freebsd_rint(x);
}
double fabs(double x)
{
return freebsd_fabs(x);
}
int isnan(double x)
{
return freebsd_isnan(x);
}
double trunc(double x)
{
return (x > 0) ? freebsd_floor(x) : freebsd_ceil(x);
}
int signbit(double x)
{
return ((__HI(x) & 0x80000000) >> 31);
}
float
truncf(float x)
{
return freebsd_truncf(x);
}
float
rintf(float x)
{
return freebsd_rintf(x);
}
float
ceilf(float x)
{
return freebsd_ceilf(x);
}
float
floorf(float x)
{
return freebsd_floorf(x);
}
float
fminf(float x, float y)
{
return freebsd_fminf(x, y);
}
float
fmaxf(float x, float y)
{
return freebsd_fmaxf(x, y);
}

View File

@ -0,0 +1,56 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_platform.h"
#include "bh_memory.h"
#include "bh_common.h"
#include <stdlib.h>
#include <string.h>
char *bh_strdup(const char *s)
{
uint32 size;
char *s1 = NULL;
if (s) {
size = (uint32)(strlen(s) + 1);
if ((s1 = bh_malloc(size)))
bh_memcpy_s(s1, size, s, size);
}
return s1;
}
static int
_stdout_hook_iwasm(int c)
{
printk("%c", (char)c);
return 1;
}
int bh_platform_init()
{
extern void __stdout_hook_install(int (*hook)(int));
/* Enable printf() in Zephyr */
__stdout_hook_install(_stdout_hook_iwasm);
return 0;
}
void *
bh_mmap(void *hint, unsigned int size, int prot, int flags)
{
return bh_malloc(size);
}
void
bh_munmap(void *addr, uint32 size)
{
return bh_free(addr);
}
int
bh_mprotect(void *addr, uint32 size, int prot)
{
return 0;
}

View File

@ -0,0 +1,157 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _BH_PLATFORM_H
#define _BH_PLATFORM_H
#include "bh_config.h"
#include "bh_types.h"
#include "bh_memory.h"
#include <autoconf.h>
#include <zephyr.h>
#include <kernel.h>
#include <sys/printk.h>
#include <inttypes.h>
#include <stdarg.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#ifndef CONFIG_NET_BUF_USER_DATA_SIZE
#define CONFIG_NET_BUF_USER_DATA_SIZE 0
#endif
#include <net/net_pkt.h>
#include <net/net_if.h>
#include <net/net_ip.h>
#include <net/net_core.h>
#include <net/net_context.h>
#ifndef BH_PLATFORM_ZEPHYR
#define BH_PLATFORM_ZEPHYR
#endif
#define BH_APPLET_PRESERVED_STACK_SIZE (2 * BH_KB)
/* Default thread priority */
#define BH_THREAD_DEFAULT_PRIORITY 7
#define BH_ROUTINE_MODIFIER
/* Invalid thread tid */
#define INVALID_THREAD_ID NULL
#define BH_WAIT_FOREVER K_FOREVER
typedef uint64_t uint64;
typedef int64_t int64;
typedef struct k_thread korp_thread;
typedef korp_thread *korp_tid;
typedef struct k_mutex korp_mutex;
typedef struct k_sem korp_sem;
#define wa_malloc bh_malloc
#define wa_free bh_free
#define wa_strdup bh_strdup
struct bh_thread_wait_node;
typedef struct bh_thread_wait_node *bh_thread_wait_list;
typedef struct korp_cond {
struct k_mutex wait_list_lock;
bh_thread_wait_list thread_wait_list;
} korp_cond;
typedef void* (*thread_start_routine_t)(void*);
#define wa_malloc bh_malloc
#define wa_free bh_free
#define bh_printf printf
/* Unit test framework is based on C++, where the declaration of
snprintf is different. */
#ifndef __cplusplus
int snprintf(char *buffer, size_t count, const char *format, ...);
#endif
#ifndef NULL
#define NULL ((void*)0)
#endif
/**
* Return the offset of the given field in the given type.
*
* @param Type the type containing the filed
* @param field the field in the type
*
* @return the offset of field in Type
*/
#ifndef offsetof
#define offsetof(Type, field) ((size_t)(&((Type *)0)->field))
#endif
#define bh_assert(x) \
do { \
if (!(x)) { \
printk("bh_assert(%s, %d)\n", __func__, __LINE__);\
} \
} while (0)
int b_memcpy_s(void * s1, unsigned int s1max, const void * s2,
unsigned int n);
int b_strcat_s(char * s1, size_t s1max, const char * s2);
int b_strcpy_s(char * s1, size_t s1max, const char * s2);
/* math functions */
double sqrt(double x);
double floor(double x);
double ceil(double x);
double fmin(double x, double y);
double fmax(double x, double y);
double rint(double x);
double fabs(double x);
double trunc(double x);
float floorf(float x);
float ceilf(float x);
float fminf(float x, float y);
float fmaxf(float x, float y);
float rintf(float x);
float truncf(float x);
int signbit(double x);
int isnan(double x);
unsigned long long int strtoull(const char *nptr, char **endptr,
int base);
double strtod(const char *nptr, char **endptr);
float strtof(const char *nptr, char **endptr);
int bh_platform_init();
/* MMAP mode */
enum {
MMAP_PROT_NONE = 0,
MMAP_PROT_READ = 1,
MMAP_PROT_WRITE = 2,
MMAP_PROT_EXEC = 4
};
/* MMAP flags */
enum {
MMAP_MAP_NONE = 0,
/* Put the mapping into 0 to 2 G, supported only on x86_64 */
MMAP_MAP_32BIT = 1,
/* Don't interpret addr as a hint: place the mapping at exactly
that address. */
MMAP_MAP_FIXED = 2
};
void *bh_mmap(void *hint, unsigned int size, int prot, int flags);
void bh_munmap(void *addr, uint32 size);
int bh_mprotect(void *addr, uint32 size, int prot);
#endif

View File

@ -0,0 +1,57 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_platform.h"
#include <stdio.h>
struct out_context {
int count;
};
typedef int (*out_func_t)(int c, void *ctx);
extern void *__printk_get_hook(void);
static int (*_char_out)(int) = NULL;
static int char_out(int c, struct out_context *ctx)
{
ctx->count++;
if (_char_out == NULL) {
_char_out = __printk_get_hook();
}
return _char_out(c);
}
static int bh_vprintk(const char *fmt, va_list ap)
{
struct out_context ctx = { 0 };
z_vprintk((out_func_t) char_out, &ctx, fmt, ap);
return ctx.count;
}
void bh_log_emit(const char *fmt, va_list ap)
{
bh_vprintk(fmt, ap);
}
int bh_fprintf(FILE *stream, const char *fmt, ...)
{
(void) stream;
va_list ap;
int ret;
va_start(ap, fmt);
ret = bh_vprintk(fmt, ap);
va_end(ap);
return ret;
}
int bh_fflush(void *stream)
{
(void) stream;
return 0;
}

View File

@ -0,0 +1,528 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_thread.h"
#include "bh_assert.h"
#include "bh_log.h"
#include "bh_memory.h"
#include <stdio.h>
#include <stdlib.h>
typedef struct bh_thread_wait_node {
struct k_sem sem;
bh_thread_wait_list next;
} bh_thread_wait_node;
typedef struct bh_thread_data {
/* Next thread data */
struct bh_thread_data *next;
/* Zephyr thread handle */
korp_tid tid;
/* Jeff thread local root */
void *tlr;
/* Lock for waiting list */
struct k_mutex wait_list_lock;
/* Waiting list of other threads who are joining this thread */
bh_thread_wait_list thread_wait_list;
/* Thread stack size */
unsigned stack_size;
/* Thread stack */
char stack[1];
} bh_thread_data;
typedef struct bh_thread_obj {
struct k_thread thread;
/* Whether the thread is terminated and this thread object is to
be freed in the future. */
bool to_be_freed;
struct bh_thread_obj *next;
} bh_thread_obj;
static bool is_thread_sys_inited = false;
/* Thread data of supervisor thread */
static bh_thread_data supervisor_thread_data;
/* Lock for thread data list */
static struct k_mutex thread_data_lock;
/* Thread data list */
static bh_thread_data *thread_data_list = NULL;
/* Lock for thread object list */
static struct k_mutex thread_obj_lock;
/* Thread object list */
static bh_thread_obj *thread_obj_list = NULL;
static void thread_data_list_add(bh_thread_data *thread_data)
{
k_mutex_lock(&thread_data_lock, K_FOREVER);
if (!thread_data_list)
thread_data_list = thread_data;
else {
/* If already in list, just return */
bh_thread_data *p = thread_data_list;
while (p) {
if (p == thread_data) {
k_mutex_unlock(&thread_data_lock);
return;
}
p = p->next;
}
/* Set as head of list */
thread_data->next = thread_data_list;
thread_data_list = thread_data;
}
k_mutex_unlock(&thread_data_lock);
}
static void thread_data_list_remove(bh_thread_data *thread_data)
{
k_mutex_lock(&thread_data_lock, K_FOREVER);
if (thread_data_list) {
if (thread_data_list == thread_data)
thread_data_list = thread_data_list->next;
else {
/* Search and remove it from list */
bh_thread_data *p = thread_data_list;
while (p && p->next != thread_data)
p = p->next;
if (p && p->next == thread_data)
p->next = p->next->next;
}
}
k_mutex_unlock(&thread_data_lock);
}
static bh_thread_data *
thread_data_list_lookup(k_tid_t tid)
{
k_mutex_lock(&thread_data_lock, K_FOREVER);
if (thread_data_list) {
bh_thread_data *p = thread_data_list;
while (p) {
if (p->tid == tid) {
/* Found */
k_mutex_unlock(&thread_data_lock);
return p;
}
p = p->next;
}
}
k_mutex_unlock(&thread_data_lock);
return NULL;
}
static void thread_obj_list_add(bh_thread_obj *thread_obj)
{
k_mutex_lock(&thread_obj_lock, K_FOREVER);
if (!thread_obj_list)
thread_obj_list = thread_obj;
else {
/* Set as head of list */
thread_obj->next = thread_obj_list;
thread_obj_list = thread_obj;
}
k_mutex_unlock(&thread_obj_lock);
}
static void thread_obj_list_reclaim()
{
bh_thread_obj *p, *p_prev;
k_mutex_lock(&thread_obj_lock, K_FOREVER);
p_prev = NULL;
p = thread_obj_list;
while (p) {
if (p->to_be_freed) {
if (p_prev == NULL) { /* p is the head of list */
thread_obj_list = p->next;
bh_free(p);
p = thread_obj_list;
} else { /* p is not the head of list */
p_prev->next = p->next;
bh_free(p);
p = p_prev->next;
}
} else {
p_prev = p;
p = p->next;
}
}
k_mutex_unlock(&thread_obj_lock);
}
int _vm_thread_sys_init()
{
if (is_thread_sys_inited)
return BHT_OK;
k_mutex_init(&thread_data_lock);
k_mutex_init(&thread_obj_lock);
/* Initialize supervisor thread data */
memset(&supervisor_thread_data, 0, sizeof(supervisor_thread_data));
supervisor_thread_data.tid = k_current_get();
/* Set as head of thread data list */
thread_data_list = &supervisor_thread_data;
is_thread_sys_inited = true;
return BHT_OK;
}
void vm_thread_sys_destroy(void)
{
if (is_thread_sys_inited) {
is_thread_sys_inited = false;
}
}
static bh_thread_data *
thread_data_current()
{
k_tid_t tid = k_current_get();
return thread_data_list_lookup(tid);
}
static void vm_thread_cleanup(void)
{
bh_thread_data *thread_data = thread_data_current();
bh_assert(thread_data != NULL);
k_mutex_lock(&thread_data->wait_list_lock, K_FOREVER);
if (thread_data->thread_wait_list) {
/* Signal each joining thread */
bh_thread_wait_list head = thread_data->thread_wait_list;
while (head) {
bh_thread_wait_list next = head->next;
k_sem_give(&head->sem);
/* head will be freed by joining thread */
head = next;
}
thread_data->thread_wait_list = NULL;
}
k_mutex_unlock(&thread_data->wait_list_lock);
thread_data_list_remove(thread_data);
/* Set flag to true for the next thread creating to
free the thread object */
((bh_thread_obj*) thread_data->tid)->to_be_freed = true;
bh_free(thread_data);
}
static void vm_thread_wrapper(void *start, void *arg, void *thread_data)
{
/* Set thread custom data */
((bh_thread_data*) thread_data)->tid = k_current_get();
thread_data_list_add(thread_data);
((thread_start_routine_t) start)(arg);
vm_thread_cleanup();
}
int _vm_thread_create(korp_tid *p_tid, thread_start_routine_t start, void *arg,
unsigned int stack_size)
{
return _vm_thread_create_with_prio(p_tid, start, arg, stack_size,
BH_THREAD_DEFAULT_PRIORITY);
}
int _vm_thread_create_with_prio(korp_tid *p_tid, thread_start_routine_t start,
void *arg, unsigned int stack_size, int prio)
{
korp_tid tid;
bh_thread_data *thread_data;
unsigned thread_data_size;
if (!p_tid || !stack_size)
return BHT_ERROR;
/* Free the thread objects of terminated threads */
thread_obj_list_reclaim();
/* Create and initialize thread object */
if (!(tid = bh_malloc(sizeof(bh_thread_obj))))
return BHT_ERROR;
memset(tid, 0, sizeof(bh_thread_obj));
/* Create and initialize thread data */
thread_data_size = offsetof(bh_thread_data, stack) + stack_size;
if (!(thread_data = bh_malloc(thread_data_size))) {
bh_free(tid);
return BHT_ERROR;
}
memset(thread_data, 0, thread_data_size);
k_mutex_init(&thread_data->wait_list_lock);
thread_data->stack_size = stack_size;
thread_data->tid = tid;
/* Create the thread */
if (!((tid = k_thread_create(tid, (k_thread_stack_t *) thread_data->stack,
stack_size, vm_thread_wrapper, start, arg, thread_data, prio, 0,
K_NO_WAIT)))) {
bh_free(tid);
bh_free(thread_data);
return BHT_ERROR;
}
bh_assert(tid == thread_data->tid);
/* Set thread custom data */
thread_data_list_add(thread_data);
thread_obj_list_add((bh_thread_obj*) tid);
*p_tid = tid;
return BHT_OK;
}
korp_tid _vm_self_thread()
{
return (korp_tid) k_current_get();
}
void vm_thread_exit(void * code)
{
(void) code;
korp_tid self = vm_self_thread();
vm_thread_cleanup();
k_thread_abort((k_tid_t) self);
}
int _vm_thread_cancel(korp_tid thread)
{
k_thread_abort((k_tid_t) thread);
return 0;
}
int _vm_thread_join(korp_tid thread, void **value_ptr, int mills)
{
(void) value_ptr;
bh_thread_data *thread_data;
bh_thread_wait_node *node;
/* Create wait node and append it to wait list */
if (!(node = bh_malloc(sizeof(bh_thread_wait_node))))
return BHT_ERROR;
k_sem_init(&node->sem, 0, 1);
node->next = NULL;
/* Get thread data */
thread_data = thread_data_list_lookup(thread);
bh_assert(thread_data != NULL);
k_mutex_lock(&thread_data->wait_list_lock, K_FOREVER);
if (!thread_data->thread_wait_list)
thread_data->thread_wait_list = node;
else {
/* Add to end of waiting list */
bh_thread_wait_node *p = thread_data->thread_wait_list;
while (p->next)
p = p->next;
p->next = node;
}
k_mutex_unlock(&thread_data->wait_list_lock);
/* Wait the sem */
k_sem_take(&node->sem, mills);
/* Wait some time for the thread to be actually terminated */
k_sleep(100);
/* Destroy resource */
bh_free(node);
return BHT_OK;
}
int _vm_thread_detach(korp_tid thread)
{
(void) thread;
return BHT_OK;
}
void *_vm_tls_get(unsigned idx)
{
(void) idx;
bh_thread_data *thread_data;
bh_assert(idx == 0);
thread_data = thread_data_current();
return thread_data ? thread_data->tlr : NULL;
}
int _vm_tls_put(unsigned idx, void * tls)
{
bh_thread_data *thread_data;
(void) idx;
bh_assert(idx == 0);
thread_data = thread_data_current();
bh_assert(thread_data != NULL);
thread_data->tlr = tls;
return BHT_OK;
}
int _vm_mutex_init(korp_mutex *mutex)
{
(void) mutex;
k_mutex_init(mutex);
return BHT_OK;
}
int _vm_recursive_mutex_init(korp_mutex *mutex)
{
k_mutex_init(mutex);
return BHT_OK;
}
int _vm_mutex_destroy(korp_mutex *mutex)
{
(void) mutex;
return BHT_OK;
}
void vm_mutex_lock(korp_mutex *mutex)
{
k_mutex_lock(mutex, K_FOREVER);
}
int vm_mutex_trylock(korp_mutex *mutex)
{
return k_mutex_lock(mutex, K_NO_WAIT);
}
void vm_mutex_unlock(korp_mutex *mutex)
{
k_mutex_unlock(mutex);
}
int _vm_sem_init(korp_sem* sem, unsigned int c)
{
k_sem_init(sem, 0, c);
return BHT_OK;
}
int _vm_sem_destroy(korp_sem *sem)
{
(void) sem;
return BHT_OK;
}
int _vm_sem_wait(korp_sem *sem)
{
return k_sem_take(sem, K_FOREVER);
}
int _vm_sem_reltimedwait(korp_sem *sem, int mills)
{
return k_sem_take(sem, mills);
}
int _vm_sem_post(korp_sem *sem)
{
k_sem_give(sem);
return BHT_OK;
}
int _vm_cond_init(korp_cond *cond)
{
k_mutex_init(&cond->wait_list_lock);
cond->thread_wait_list = NULL;
return BHT_OK;
}
int _vm_cond_destroy(korp_cond *cond)
{
(void) cond;
return BHT_OK;
}
static int _vm_cond_wait_internal(korp_cond *cond, korp_mutex *mutex,
bool timed, int mills)
{
bh_thread_wait_node *node;
/* Create wait node and append it to wait list */
if (!(node = bh_malloc(sizeof(bh_thread_wait_node))))
return BHT_ERROR;
k_sem_init(&node->sem, 0, 1);
node->next = NULL;
k_mutex_lock(&cond->wait_list_lock, K_FOREVER);
if (!cond->thread_wait_list)
cond->thread_wait_list = node;
else {
/* Add to end of wait list */
bh_thread_wait_node *p = cond->thread_wait_list;
while (p->next)
p = p->next;
p->next = node;
}
k_mutex_unlock(&cond->wait_list_lock);
/* Unlock mutex, wait sem and lock mutex again */
k_mutex_unlock(mutex);
k_sem_take(&node->sem, timed ? mills : K_FOREVER);
k_mutex_lock(mutex, K_FOREVER);
/* Remove wait node from wait list */
k_mutex_lock(&cond->wait_list_lock, K_FOREVER);
if (cond->thread_wait_list == node)
cond->thread_wait_list = node->next;
else {
/* Remove from the wait list */
bh_thread_wait_node *p = cond->thread_wait_list;
while (p->next != node)
p = p->next;
p->next = node->next;
}
bh_free(node);
k_mutex_unlock(&cond->wait_list_lock);
return BHT_OK;
}
int _vm_cond_wait(korp_cond *cond, korp_mutex *mutex)
{
return _vm_cond_wait_internal(cond, mutex, false, 0);
}
int _vm_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, int mills)
{
return _vm_cond_wait_internal(cond, mutex, true, mills);
}
int _vm_cond_signal(korp_cond *cond)
{
/* Signal the head wait node of wait list */
k_mutex_lock(&cond->wait_list_lock, K_FOREVER);
if (cond->thread_wait_list)
k_sem_give(&cond->thread_wait_list->sem);
k_mutex_unlock(&cond->wait_list_lock);
return BHT_OK;
}
int _vm_cond_broadcast(korp_cond *cond)
{
/* Signal each wait node of wait list */
k_mutex_lock(&cond->wait_list_lock, K_FOREVER);
if (cond->thread_wait_list) {
bh_thread_wait_node *p = cond->thread_wait_list;
while (p) {
k_sem_give(&p->sem);
p = p->next;
}
}
k_mutex_unlock(&cond->wait_list_lock);
return BHT_OK;
}

View File

@ -0,0 +1,46 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_time.h"
/*
* This function returns milliseconds per tick.
* @return milliseconds per tick.
*/
uint64 _bh_time_get_tick_millisecond()
{
return k_uptime_get_32();
}
/*
* This function returns milliseconds after boot.
* @return milliseconds after boot.
*/
uint64 _bh_time_get_boot_millisecond()
{
return k_uptime_get_32();
}
uint64 _bh_time_get_millisecond_from_1970()
{
return k_uptime_get();
}
size_t _bh_time_strftime(char *str, size_t max, const char *format, int64 time)
{
(void) format;
(void) time;
uint32 t = k_uptime_get_32();
int h, m, s;
t = t % (24 * 60 * 60);
h = t / (60 * 60);
t = t % (60 * 60);
m = t / 60;
s = t % 60;
return snprintf(str, max, "%02d:%02d:%02d", h, m, s);
}

View File

@ -0,0 +1,13 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
set (PLATFORM_SHARED_DIR ${CMAKE_CURRENT_LIST_DIR})
include_directories(${PLATFORM_SHARED_DIR})
include_directories(${PLATFORM_SHARED_DIR}/../include)
file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c)
set (PLATFORM_SHARED_SOURCE ${source_all})

View File

@ -0,0 +1,10 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
include_directories (. ../include ../platform/include ../platform/${WAMR_BUILD_PLATFORM} coap/er-coap coap/extension)
file (GLOB_RECURSE source_all *.c )
add_library (vmutilslib ${source_all})

View File

@ -0,0 +1,5 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
obj-y += bh_list.o bh_log.o attr-container.o bh_queue.o
obj-y += coap/

View File

@ -0,0 +1,292 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_hashmap.h"
#include "bh_log.h"
#include "bh_thread.h"
#include "bh_memory.h"
typedef struct HashMapElem {
void *key;
void *value;
struct HashMapElem *next;
} HashMapElem;
struct HashMap {
/* size of element array */
uint32 size;
/* lock for elements */
korp_mutex *lock;
/* hash function of key */
HashFunc hash_func;
/* key equal function */
KeyEqualFunc key_equal_func;
KeyDestroyFunc key_destroy_func;
ValueDestroyFunc value_destroy_func;
HashMapElem *elements[1];
};
HashMap*
bh_hash_map_create(uint32 size, bool use_lock,
HashFunc hash_func,
KeyEqualFunc key_equal_func,
KeyDestroyFunc key_destroy_func,
ValueDestroyFunc value_destroy_func)
{
HashMap *map;
uint64 total_size;
if (size > HASH_MAP_MAX_SIZE) {
LOG_ERROR("HashMap create failed: size is too large.\n");
return NULL;
}
if (!hash_func || !key_equal_func) {
LOG_ERROR("HashMap create failed: hash function or key equal function "
" is NULL.\n");
return NULL;
}
total_size = offsetof(HashMap, elements) +
sizeof(HashMapElem) * (uint64)size +
(use_lock ? sizeof(korp_mutex) : 0);
if (total_size >= UINT32_MAX
|| !(map = bh_malloc((uint32)total_size))) {
LOG_ERROR("HashMap create failed: alloc memory failed.\n");
return NULL;
}
memset(map, 0, (uint32)total_size);
if (use_lock) {
map->lock = (korp_mutex*)
((uint8*)map + offsetof(HashMap, elements)
+ sizeof(HashMapElem) * size);
if (vm_mutex_init(map->lock)) {
LOG_ERROR("HashMap create failed: init map lock failed.\n");
bh_free(map);
return NULL;
}
}
map->size = size;
map->hash_func = hash_func;
map->key_equal_func = key_equal_func;
map->key_destroy_func = key_destroy_func;
map->value_destroy_func = value_destroy_func;
return map;
}
bool
bh_hash_map_insert(HashMap *map, void *key, void *value)
{
uint32 index;
HashMapElem *elem;
if (!map || !key) {
LOG_ERROR("HashMap insert elem failed: map or key is NULL.\n");
return false;
}
if (map->lock) {
vm_mutex_lock(map->lock);
}
index = map->hash_func(key) % map->size;
elem = map->elements[index];
while (elem) {
if (map->key_equal_func(elem->key, key)) {
LOG_ERROR("HashMap insert elem failed: duplicated key found.\n");
goto fail;
}
elem = elem->next;
}
if (!(elem = bh_malloc(sizeof(HashMapElem)))) {
LOG_ERROR("HashMap insert elem failed: alloc memory failed.\n");
goto fail;
}
elem->key = key;
elem->value = value;
elem->next = map->elements[index];
map->elements[index] = elem;
if (map->lock) {
vm_mutex_unlock(map->lock);
}
return true;
fail:
if (map->lock) {
vm_mutex_unlock(map->lock);
}
return false;
}
void*
bh_hash_map_find(HashMap *map, void *key)
{
uint32 index;
HashMapElem *elem;
void *value;
if (!map || !key) {
LOG_ERROR("HashMap find elem failed: map or key is NULL.\n");
return NULL;
}
if (map->lock) {
vm_mutex_lock(map->lock);
}
index = map->hash_func(key) % map->size;
elem = map->elements[index];
while (elem) {
if (map->key_equal_func(elem->key, key)) {
value = elem->value;
if (map->lock) {
vm_mutex_unlock(map->lock);
}
return value;
}
elem = elem->next;
}
if (map->lock) {
vm_mutex_unlock(map->lock);
}
return NULL;
}
bool
bh_hash_map_update(HashMap *map, void *key, void *value,
void **p_old_value)
{
uint32 index;
HashMapElem *elem;
if (!map || !key) {
LOG_ERROR("HashMap update elem failed: map or key is NULL.\n");
return false;
}
if (map->lock) {
vm_mutex_lock(map->lock);
}
index = map->hash_func(key) % map->size;
elem = map->elements[index];
while (elem) {
if (map->key_equal_func(elem->key, key)) {
if (p_old_value)
*p_old_value = elem->value;
elem->value = value;
if (map->lock) {
vm_mutex_unlock(map->lock);
}
return true;
}
elem = elem->next;
}
if (map->lock) {
vm_mutex_unlock(map->lock);
}
return false;
}
bool
bh_hash_map_remove(HashMap *map, void *key,
void **p_old_key, void **p_old_value)
{
uint32 index;
HashMapElem *elem, *prev;
if (!map || !key) {
LOG_ERROR("HashMap remove elem failed: map or key is NULL.\n");
return false;
}
if (map->lock) {
vm_mutex_lock(map->lock);
}
index = map->hash_func(key) % map->size;
prev = elem = map->elements[index];
while (elem) {
if (map->key_equal_func(elem->key, key)) {
if (p_old_key)
*p_old_key = elem->key;
if (p_old_value)
*p_old_value = elem->value;
if (elem == map->elements[index])
map->elements[index] = elem->next;
else
prev->next = elem->next;
bh_free(elem);
if (map->lock) {
vm_mutex_unlock(map->lock);
}
return true;
}
prev = elem;
elem = elem->next;
}
if (map->lock) {
vm_mutex_unlock(map->lock);
}
return false;
}
bool
bh_hash_map_destroy(HashMap *map)
{
uint32 index;
HashMapElem *elem, *next;
if (!map) {
LOG_ERROR("HashMap destroy failed: map is NULL.\n");
return false;
}
if (map->lock) {
vm_mutex_lock(map->lock);
}
for (index = 0; index < map->size; index++) {
elem = map->elements[index];
while (elem) {
next = elem->next;
if (map->key_destroy_func) {
map->key_destroy_func(elem->key);
}
if (map->value_destroy_func) {
map->value_destroy_func(elem->value);
}
bh_free(elem);
elem = next;
}
}
if (map->lock) {
vm_mutex_unlock(map->lock);
vm_mutex_destroy(map->lock);
}
bh_free(map);
return true;
}

103
core/shared/utils/bh_list.c Normal file
View File

@ -0,0 +1,103 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_list.h"
#include "bh_assert.h"
#ifdef BH_DEBUG
/**
* Test whehter a pointer value has exist in given list.
*
* @param list pointer to list.
* @param elem pointer to elem that will be inserted into list.
* @return <code>true</code> if the pointer has been in the list;
* <code>false</code> otherwise.
*/
BH_STATIC bool bh_list_is_elem_exist(bh_list *list, void *elem);
#endif
bh_list_status bh_list_init(bh_list *list)
{
if (!list)
return BH_LIST_ERROR;
(list->head).next = NULL;
list->len = 0;
return BH_LIST_SUCCESS;
}
bh_list_status _bh_list_insert(bh_list *list, void *elem)
{
bh_list_link *p = NULL;
if (!list || !elem)
return BH_LIST_ERROR;
#ifdef BH_DEBUG
bh_assert (!bh_list_is_elem_exist(list, elem));
#endif
p = (bh_list_link *) elem;
p->next = (list->head).next;
(list->head).next = p;
list->len++;
return BH_LIST_SUCCESS;
}
bh_list_status bh_list_remove(bh_list *list, void *elem)
{
bh_list_link *cur = NULL;
bh_list_link *prev = NULL;
if (!list || !elem)
return BH_LIST_ERROR;
cur = (list->head).next;
while (cur) {
if (cur == elem) {
if (prev)
prev->next = cur->next;
else
(list->head).next = cur->next;
list->len--;
return BH_LIST_SUCCESS;
}
prev = cur;
cur = cur->next;
}
return BH_LIST_ERROR;
}
uint32 bh_list_length(bh_list *list)
{
return (list ? list->len : 0);
}
void* bh_list_first_elem(bh_list *list)
{
return (list ? (list->head).next : NULL);
}
void* bh_list_elem_next(void *node)
{
return (node ? ((bh_list_link *) node)->next : NULL);
}
#ifdef BH_DEBUG
BH_STATIC bool bh_list_is_elem_exist(bh_list *list, void *elem)
{
bh_list_link *p = NULL;
if (!list || !elem) return false;
p = (list->head).next;
while (p && p != elem) p = p->next;
return (p != NULL);
}
#endif

202
core/shared/utils/bh_log.c Normal file
View File

@ -0,0 +1,202 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
/**
* @file bh_log.c
* @date Tue Nov 8 18:20:06 2011
*
* @brief Implementation of Beihai's log system.
*/
#include "bh_assert.h"
#include "bh_time.h"
#include "bh_thread.h"
#include "bh_log.h"
#include "bh_platform_log.h"
/**
* The verbose level of the log system. Only those verbose logs whose
* levels are less than or equal to this value are outputed.
*/
static int log_verbose_level;
/**
* The lock for protecting the global output stream of logs.
*/
static korp_mutex log_stream_lock;
/**
* The current logging thread that owns the log_stream_lock.
*/
static korp_tid cur_logging_thread = INVALID_THREAD_ID;
/**
* Whether the currently being printed log is ennabled.
*/
static bool cur_log_enabled;
int _bh_log_init()
{
log_verbose_level = 3;
return vm_mutex_init(&log_stream_lock);
}
void _bh_log_set_verbose_level(int level)
{
log_verbose_level = level;
}
void _bh_log_printf(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
_bh_log_vprintf(fmt, ap);
va_end(ap);
}
/**
* Return true if the given tag is enabled by the configuration.
*
* @param tag the tag (or prefix) of the log message.
*
* @return true if the log should be enabled.
*/
static bool is_log_enabled(const char *tag)
{
/* Print all non-verbose or verbose logs whose levels are less than
or equal to the configured verbose level. */
return tag[0] != 'V' || tag[1] - '0' <= log_verbose_level;
}
/**
* Helper function for converting "..." to va_list.
*/
static void bh_log_emit_helper(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
bh_log_emit(fmt, ap);
va_end(ap);
}
extern size_t _bh_time_strftime(char *s, size_t max, const char *format,
int64 time);
void _bh_log_vprintf(const char *fmt, va_list ap)
{
korp_tid self = vm_self_thread();
/* Try to own the log stream and start the log output. */
if (self != cur_logging_thread) {
vm_mutex_lock(&log_stream_lock);
cur_logging_thread = self;
if (fmt && (cur_log_enabled = is_log_enabled(fmt))) {
char buf[32];
bh_time_strftime(buf, 32, "%Y-%m-%d %H:%M:%S",
(int64)bh_time_get_millisecond_from_1970());
bh_log_emit_helper("\n[%s - %X]: ", buf, (int) self);
/* Strip the "Vn." prefix. */
if (fmt && strlen(fmt) >= 3 && fmt[0] == 'V' && fmt[1] && fmt[2])
fmt += 3;
}
}
if (cur_log_enabled && fmt)
bh_log_emit(fmt, ap);
}
void _bh_log_commit()
{
if (vm_self_thread() != cur_logging_thread)
/* Ignore the single commit without printing anything. */
return;
cur_logging_thread = INVALID_THREAD_ID;
vm_mutex_unlock(&log_stream_lock);
}
void _bh_log(const char *tag, const char *file, int line, const char *fmt, ...)
{
va_list ap;
if (tag)
_bh_log_printf(tag);
if (file)
_bh_log_printf("%s:%d", file, line);
va_start(ap, fmt);
_bh_log_vprintf(fmt, ap);
va_end(ap);
_bh_log_commit();
}
#if defined(BH_DEBUG)
BH_STATIC char com_switchs[LOG_COM_MAX]; /* 0: off; 1: on */
BH_STATIC char *com_names[LOG_COM_MAX] = {"app_manager", "gc", "hmc", "utils",
"verifier_jeff", "vmcore_jeff"};
BH_STATIC int com_find_name(const char **com)
{
int i;
const char *c, *name;
for (i = 0; i < LOG_COM_MAX; i++) {
c = *com;
name = com_names[i];
while (*name != '\0') {
if (*c != *name)
break;
c++;
name++;
}
if (*name == '\0') {
*com = c;
return i;
}
}
return LOG_COM_MAX;
}
void log_parse_coms(const char *coms)
{
int i;
for (i = LOG_COM_MAX; i--; )
com_switchs[i] = 0;
com_switchs[LOG_COM_UTILS] = 1; /* utils is a common part */
if (coms == NULL)
return;
while (*coms != '\0') {
i = com_find_name(&coms);
if (i == LOG_COM_MAX)
break;
com_switchs[i] = 1;
if (*coms == '\0')
return;
if (*coms != ';')
break;
/* *com == ';' */
coms++;
}
/* Log the message without aborting. */
LOG_DEBUG(LOG_COM_UTILS, "The component names for logging are not right: %s.", coms);
}
int bh_log_dcom_is_enabled(int component)
{
return com_switchs[component];
}
#endif /* defined(BH_DEBUG) */

View File

@ -0,0 +1,248 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_queue.h"
#include "bh_thread.h"
#include "bh_memory.h"
#include "bh_time.h"
#include "bh_common.h"
typedef struct _bh_queue_node {
struct _bh_queue_node * next;
struct _bh_queue_node * prev;
unsigned short tag;
unsigned int len;
void * body;
bh_msg_cleaner msg_cleaner;
} bh_queue_node;
struct bh_queue {
bh_queue_mutex queue_lock;
bh_queue_cond queue_wait_cond;
unsigned int cnt;
unsigned int max;
unsigned int drops;
bh_queue_node * head;
bh_queue_node * tail;
bool exit_loop_run;
};
char * bh_message_payload(bh_message_t message)
{
return message->body;
}
uint32 bh_message_payload_len(bh_message_t message)
{
return message->len;
}
int bh_message_type(bh_message_t message)
{
return message->tag;
}
bh_queue *
bh_queue_create()
{
int ret;
bh_queue *queue = bh_queue_malloc(sizeof(bh_queue));
if (queue) {
memset(queue, 0, sizeof(bh_queue));
queue->max = DEFAULT_QUEUE_LENGTH;
ret = bh_queue_mutex_init(&queue->queue_lock);
if (ret != 0) {
bh_queue_free(queue);
return NULL;
}
ret = bh_queue_cond_init(&queue->queue_wait_cond);
if (ret != 0) {
bh_queue_mutex_destroy(&queue->queue_lock);
bh_queue_free(queue);
return NULL;
}
}
return queue;
}
void bh_queue_destroy(bh_queue *queue)
{
bh_queue_node *node;
if (!queue)
return;
bh_queue_mutex_lock(&queue->queue_lock);
while (queue->head) {
node = queue->head;
queue->head = node->next;
bh_free_msg(node);
}
bh_queue_mutex_unlock(&queue->queue_lock);
bh_queue_cond_destroy(&queue->queue_wait_cond);
bh_queue_mutex_destroy(&queue->queue_lock);
bh_queue_free(queue);
}
bool bh_post_msg2(bh_queue *queue, bh_queue_node *msg)
{
if (queue->cnt >= queue->max) {
queue->drops++;
bh_free_msg(msg);
return false;
}
bh_queue_mutex_lock(&queue->queue_lock);
if (queue->cnt == 0) {
bh_assert(queue->head == NULL);
bh_assert(queue->tail == NULL);
queue->head = queue->tail = msg;
msg->next = msg->prev = NULL;
queue->cnt = 1;
bh_queue_cond_signal(&queue->queue_wait_cond);
} else {
msg->next = NULL;
msg->prev = queue->tail;
queue->tail->next = msg;
queue->tail = msg;
queue->cnt++;
}
bh_queue_mutex_unlock(&queue->queue_lock);
return true;
}
bool bh_post_msg(bh_queue *queue, unsigned short tag, void *body,
unsigned int len)
{
bh_queue_node *msg = bh_new_msg(tag, body, len, NULL);
if (msg == NULL) {
queue->drops++;
if (len != 0 && body)
bh_free(body);
return false;
}
if (!bh_post_msg2(queue, msg)) {
// bh_post_msg2 already freed the msg for failure
return false;
}
return true;
}
bh_queue_node * bh_new_msg(unsigned short tag, void *body, unsigned int len,
void * handler)
{
bh_queue_node *msg = (bh_queue_node*) bh_queue_malloc(
sizeof(bh_queue_node));
if (msg == NULL)
return NULL;
memset(msg, 0, sizeof(bh_queue_node));
msg->len = len;
msg->body = body;
msg->tag = tag;
msg->msg_cleaner = (bh_msg_cleaner) handler;
return msg;
}
void bh_free_msg(bh_queue_node *msg)
{
if (msg->msg_cleaner) {
msg->msg_cleaner(msg->body);
bh_queue_free(msg);
return;
}
// note: sometime we just use the payload pointer for a integer value
// len!=0 is the only indicator about the body is an allocated buffer.
if (msg->body && msg->len)
bh_queue_free(msg->body);
bh_queue_free(msg);
}
bh_message_t bh_get_msg(bh_queue *queue, int timeout)
{
bh_queue_node *msg = NULL;
bh_queue_mutex_lock(&queue->queue_lock);
if (queue->cnt == 0) {
bh_assert(queue->head == NULL);
bh_assert(queue->tail == NULL);
if (timeout == 0) {
bh_queue_mutex_unlock(&queue->queue_lock);
return NULL;
}
bh_queue_cond_timedwait(&queue->queue_wait_cond, &queue->queue_lock,
timeout);
}
if (queue->cnt == 0) {
bh_assert(queue->head == NULL);
bh_assert(queue->tail == NULL);
} else if (queue->cnt == 1) {
bh_assert(queue->head == queue->tail);
msg = queue->head;
queue->head = queue->tail = NULL;
queue->cnt = 0;
} else {
msg = queue->head;
queue->head = queue->head->next;
queue->head->prev = NULL;
queue->cnt--;
}
bh_queue_mutex_unlock(&queue->queue_lock);
return msg;
}
unsigned bh_queue_get_message_count(bh_queue *queue)
{
if (!queue)
return 0;
return queue->cnt;
}
void bh_queue_enter_loop_run(bh_queue *queue,
bh_queue_handle_msg_callback handle_cb,
void *arg)
{
if (!queue)
return;
while (!queue->exit_loop_run) {
bh_queue_node * message = bh_get_msg(queue, (int)BH_WAIT_FOREVER);
if (message) {
handle_cb(message, arg);
bh_free_msg(message);
}
}
}
void bh_queue_exit_loop_run(bh_queue *queue)
{
if (queue) {
queue->exit_loop_run = true;
bh_queue_cond_signal(&queue->queue_wait_cond);
}
}

View File

@ -0,0 +1,206 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_log.h"
#include "bh_vector.h"
#include "bh_memory.h"
static uint8*
alloc_vector_data(uint32 length, uint32 size_elem)
{
uint64 total_size = ((uint64)size_elem) * length;
uint8 *data;
if (total_size > UINT32_MAX) {
return NULL;
}
if ((data = bh_malloc((uint32)total_size))) {
memset(data, 0, (uint32)total_size);
}
return data;
}
static bool
extend_vector(Vector *vector, uint32 length)
{
uint8 *data;
if (length <= vector->max_elements)
return true;
if (length < vector->size_elem * 3 / 2)
length = vector->size_elem * 3 / 2;
if (!(data = alloc_vector_data(length, vector->size_elem))) {
return false;
}
memcpy(data, vector->data, vector->size_elem * vector->max_elements);
bh_free(vector->data);
vector->data = data;
vector->max_elements = length;
return true;
}
bool
bh_vector_init(Vector *vector, uint32 init_length, uint32 size_elem)
{
if (!vector) {
LOG_ERROR("Init vector failed: vector is NULL.\n");
return false;
}
if (init_length == 0) {
init_length = 4;
}
if (!(vector->data = alloc_vector_data(init_length, size_elem))) {
LOG_ERROR("Init vector failed: alloc memory failed.\n");
return false;
}
vector->size_elem = size_elem;
vector->max_elements = init_length;
vector->num_elements = 0;
return true;
}
bool
bh_vector_set(Vector *vector, uint32 index, const void *elem_buf)
{
if (!vector || !elem_buf) {
LOG_ERROR("Set vector elem failed: vector or elem buf is NULL.\n");
return false;
}
if (index >= vector->num_elements) {
LOG_ERROR("Set vector elem failed: invalid elem index.\n");
return false;
}
memcpy(vector->data + vector->size_elem * index,
elem_buf, vector->size_elem);
return true;
}
bool bh_vector_get(const Vector *vector, uint32 index, void *elem_buf)
{
if (!vector || !elem_buf) {
LOG_ERROR("Get vector elem failed: vector or elem buf is NULL.\n");
return false;
}
if (index >= vector->num_elements) {
LOG_ERROR("Get vector elem failed: invalid elem index.\n");
return false;
}
memcpy(elem_buf, vector->data + vector->size_elem * index,
vector->size_elem);
return true;
}
bool bh_vector_insert(Vector *vector, uint32 index, const void *elem_buf)
{
uint32 i;
uint8 *p;
if (!vector || !elem_buf) {
LOG_ERROR("Insert vector elem failed: vector or elem buf is NULL.\n");
return false;
}
if (index >= vector->num_elements) {
LOG_ERROR("Insert vector elem failed: invalid elem index.\n");
return false;
}
if (!extend_vector(vector, vector->num_elements + 1)) {
LOG_ERROR("Insert vector elem failed: extend vector failed.\n");
return false;
}
p = vector->data + vector->size_elem * vector->num_elements;
for (i = vector->num_elements - 1; i > index; i--) {
memcpy(p, p - vector->size_elem, vector->size_elem);
p -= vector->size_elem;
}
memcpy(p, elem_buf, vector->size_elem);
vector->num_elements++;
return true;
}
bool bh_vector_append(Vector *vector, const void *elem_buf)
{
if (!vector || !elem_buf) {
LOG_ERROR("Append vector elem failed: vector or elem buf is NULL.\n");
return false;
}
if (!extend_vector(vector, vector->num_elements + 1)) {
LOG_ERROR("Append ector elem failed: extend vector failed.\n");
return false;
}
memcpy(vector->data + vector->size_elem * vector->num_elements,
elem_buf, vector->size_elem);
vector->num_elements++;
return true;
}
bool
bh_vector_remove(Vector *vector, uint32 index, void *old_elem_buf)
{
uint32 i;
uint8 *p;
if (!vector) {
LOG_ERROR("Remove vector elem failed: vector is NULL.\n");
return false;
}
if (index >= vector->num_elements) {
LOG_ERROR("Remove vector elem failed: invalid elem index.\n");
return false;
}
p = vector->data + vector->size_elem * index;
if (old_elem_buf) {
memcpy(old_elem_buf, p, vector->size_elem);
}
for (i = index; i < vector->num_elements - 1; i++) {
memcpy(p, p + vector->size_elem, vector->size_elem);
p += vector->size_elem;
}
vector->num_elements--;
return true;
}
uint32
bh_vector_size(const Vector *vector)
{
return vector ? vector->num_elements : 0;
}
bool
bh_vector_destroy(Vector *vector)
{
if (!vector) {
LOG_ERROR("Destroy vector elem failed: vector is NULL.\n");
return false;
}
if (vector->data)
bh_free(vector->data);
memset(vector, 0, sizeof(Vector));
return true;
}

View File

@ -0,0 +1,428 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "runtime_timer.h"
#include "bh_thread.h"
#include "bh_time.h"
#define PRINT(...)
//#define PRINT printf
typedef struct _app_timer {
struct _app_timer * next;
uint32 id;
unsigned int interval;
uint64 expiry;
bool is_periodic;
} app_timer_t;
struct _timer_ctx {
app_timer_t * g_app_timers;
app_timer_t * idle_timers;
app_timer_t * free_timers;
unsigned int g_max_id;
int pre_allocated;
unsigned int owner;
//add mutext and conditions
korp_cond cond;
korp_mutex mutex;
timer_callback_f timer_callback;
check_timer_expiry_f refresh_checker;
};
uint32 bh_get_elpased_ms(uint32 * last_system_clock)
{
uint32 elpased_ms;
// attention: the bh_get_tick_ms() return 64 bits integer.
// but the bh_get_elpased_ms() is designed to use 32 bits clock count.
uint32 now = (uint32) bh_get_tick_ms();
// system clock overrun
if (now < *last_system_clock) {
elpased_ms = now + (0xFFFFFFFF - *last_system_clock) + 1;
} else {
elpased_ms = now - *last_system_clock;
}
*last_system_clock = now;
return elpased_ms;
}
static app_timer_t * remove_timer_from(timer_ctx_t ctx, uint32 timer_id,
bool active_list)
{
vm_mutex_lock(&ctx->mutex);
app_timer_t ** head;
if (active_list)
head = &ctx->g_app_timers;
else
head = &ctx->idle_timers;
app_timer_t * t = *head;
app_timer_t * prev = NULL;
while (t) {
if (t->id == timer_id) {
if (prev == NULL) {
*head = t->next;
PRINT("removed timer [%d] at head from list %d\n", t->id, active_list);
} else {
prev->next = t->next;
PRINT("removed timer [%d] after [%d] from list %d\n", t->id, prev->id, active_list);
}
vm_mutex_unlock(&ctx->mutex);
if (active_list && prev == NULL && ctx->refresh_checker)
ctx->refresh_checker(ctx);
return t;
} else {
prev = t;
t = t->next;
}
}
vm_mutex_unlock(&ctx->mutex);
return NULL;
}
static app_timer_t * remove_timer(timer_ctx_t ctx, uint32 timer_id,
bool * active)
{
app_timer_t* t = remove_timer_from(ctx, timer_id, true);
if (t) {
if (active)
*active = true;
return t;
}
if (active)
*active = false;
return remove_timer_from(ctx, timer_id, false);
}
static void reschedule_timer(timer_ctx_t ctx, app_timer_t * timer)
{
vm_mutex_lock(&ctx->mutex);
app_timer_t * t = ctx->g_app_timers;
app_timer_t * prev = NULL;
timer->next = NULL;
timer->expiry = bh_get_tick_ms() + timer->interval;
while (t) {
if (timer->expiry < t->expiry) {
if (prev == NULL) {
timer->next = ctx->g_app_timers;
ctx->g_app_timers = timer;
PRINT("rescheduled timer [%d] at head\n", timer->id);
} else {
timer->next = t;
prev->next = timer;
PRINT("rescheduled timer [%d] after [%d]\n", timer->id, prev->id);
}
vm_mutex_unlock(&ctx->mutex);
// ensure the refresh_checker() is called out of the lock
if (prev == NULL && ctx->refresh_checker)
ctx->refresh_checker(ctx);
return;
} else {
prev = t;
t = t->next;
}
}
if (prev) {
// insert to the list end
prev->next = timer;
PRINT("rescheduled timer [%d] at end, after [%d]\n", timer->id, prev->id);
} else {
// insert at the begin
bh_assert(ctx->g_app_timers == NULL);
ctx->g_app_timers = timer;
PRINT("rescheduled timer [%d] as first\n", timer->id);
}
vm_mutex_unlock(&ctx->mutex);
// ensure the refresh_checker() is called out of the lock
if (prev == NULL && ctx->refresh_checker)
ctx->refresh_checker(ctx);
}
static void release_timer(timer_ctx_t ctx, app_timer_t * t)
{
if (ctx->pre_allocated) {
vm_mutex_lock(&ctx->mutex);
t->next = ctx->free_timers;
ctx->free_timers = t;
PRINT("recycle timer :%d\n", t->id);
vm_mutex_unlock(&ctx->mutex);
} else {
PRINT("destroy timer :%d\n", t->id);
bh_free(t);
}
}
void release_timer_list(app_timer_t ** p_list)
{
app_timer_t *t = *p_list;
while (t) {
app_timer_t *next = t->next;
PRINT("destroy timer list:%d\n", t->id);
bh_free(t);
t = next;
}
*p_list = NULL;
}
/*
*
* API exposed
*
*/
timer_ctx_t create_timer_ctx(timer_callback_f timer_handler,
check_timer_expiry_f expiery_checker, int prealloc_num,
unsigned int owner)
{
timer_ctx_t ctx = (timer_ctx_t) bh_malloc(sizeof(struct _timer_ctx));
if (ctx == NULL)
return NULL;
memset(ctx, 0, sizeof(struct _timer_ctx));
ctx->timer_callback = timer_handler;
ctx->pre_allocated = prealloc_num;
ctx->refresh_checker = expiery_checker;
ctx->owner = owner;
while (prealloc_num > 0) {
app_timer_t *timer = (app_timer_t*) bh_malloc(sizeof(app_timer_t));
if (timer == NULL)
goto cleanup;
memset(timer, 0, sizeof(*timer));
timer->next = ctx->free_timers;
ctx->free_timers = timer;
prealloc_num--;
}
vm_cond_init(&ctx->cond);
vm_mutex_init(&ctx->mutex);
PRINT("timer ctx created. pre-alloc: %d\n", ctx->pre_allocated);
return ctx;
cleanup:
if (ctx) {
release_timer_list(&ctx->free_timers);
bh_free(ctx);
}
PRINT("timer ctx create failed\n");
return NULL;
}
void destroy_timer_ctx(timer_ctx_t ctx)
{
while (ctx->free_timers) {
void * tmp = ctx->free_timers;
ctx->free_timers = ctx->free_timers->next;
bh_free(tmp);
}
cleanup_app_timers(ctx);
vm_cond_destroy(&ctx->cond);
vm_mutex_destroy(&ctx->mutex);
bh_free(ctx);
}
unsigned int timer_ctx_get_owner(timer_ctx_t ctx)
{
return ctx->owner;
}
void add_idle_timer(timer_ctx_t ctx, app_timer_t * timer)
{
vm_mutex_lock(&ctx->mutex);
timer->next = ctx->idle_timers;
ctx->idle_timers = timer;
vm_mutex_unlock(&ctx->mutex);
}
uint32 sys_create_timer(timer_ctx_t ctx, int interval, bool is_period,
bool auto_start)
{
app_timer_t *timer;
if (ctx->pre_allocated) {
if (ctx->free_timers == NULL)
return (uint32)-1;
else {
timer = ctx->free_timers;
ctx->free_timers = timer->next;
}
} else {
timer = (app_timer_t*) bh_malloc(sizeof(app_timer_t));
if (timer == NULL)
return (uint32)-1;
}
memset(timer, 0, sizeof(*timer));
ctx->g_max_id++;
if (ctx->g_max_id == (uint32)-1)
ctx->g_max_id++;
timer->id = ctx->g_max_id;
timer->interval = (uint32)interval;
timer->is_periodic = is_period;
if (auto_start)
reschedule_timer(ctx, timer);
else
add_idle_timer(ctx, timer);
return timer->id;
}
bool sys_timer_cancel(timer_ctx_t ctx, uint32 timer_id)
{
bool from_active;
app_timer_t * t = remove_timer(ctx, timer_id, &from_active);
if (t == NULL)
return false;
add_idle_timer(ctx, t);
PRINT("sys_timer_stop called\n");
return from_active;
}
bool sys_timer_destroy(timer_ctx_t ctx, uint32 timer_id)
{
bool from_active;
app_timer_t * t = remove_timer(ctx, timer_id, &from_active);
if (t == NULL)
return false;
release_timer(ctx, t);
PRINT("sys_timer_destroy called\n");
return true;
}
bool sys_timer_restart(timer_ctx_t ctx, uint32 timer_id, int interval)
{
app_timer_t * t = remove_timer(ctx, timer_id, NULL);
if (t == NULL)
return false;
if (interval > 0)
t->interval = (uint32)interval;
reschedule_timer(ctx, t);
PRINT("sys_timer_restart called\n");
return true;
}
/*
*
*
* API called by the timer manager from another thread or the kernel timer handler
*
*
*/
// lookup the app queue by the module name
//post a timeout message to the app queue
//
static void handle_expired_timers(timer_ctx_t ctx, app_timer_t * expired)
{
while (expired) {
app_timer_t * t = expired;
ctx->timer_callback(t->id, ctx->owner);
expired = expired->next;
if (t->is_periodic) {
// if it is repeating, then reschedule it;
reschedule_timer(ctx, t);
} else {
// else move it to idle list
add_idle_timer(ctx, t);
}
}
}
int get_expiry_ms(timer_ctx_t ctx)
{
int ms_to_next_expiry;
uint64 now = bh_get_tick_ms();
vm_mutex_lock(&ctx->mutex);
if (ctx->g_app_timers == NULL)
ms_to_next_expiry = 7 * 24 * 60 * 60 * 1000; // 1 week
else if (ctx->g_app_timers->expiry >= now)
ms_to_next_expiry = (int)(ctx->g_app_timers->expiry - now);
else
ms_to_next_expiry = 0;
vm_mutex_unlock(&ctx->mutex);
return ms_to_next_expiry;
}
int check_app_timers(timer_ctx_t ctx)
{
vm_mutex_lock(&ctx->mutex);
app_timer_t * t = ctx->g_app_timers;
app_timer_t * expired = NULL;
uint64 now = bh_get_tick_ms();
while (t) {
if (now >= t->expiry) {
ctx->g_app_timers = t->next;
t->next = expired;
expired = t;
t = ctx->g_app_timers;
} else {
break;
}
}
vm_mutex_unlock(&ctx->mutex);
handle_expired_timers(ctx, expired);
return get_expiry_ms(ctx);
}
void cleanup_app_timers(timer_ctx_t ctx)
{
vm_mutex_lock(&ctx->mutex);
release_timer_list(&ctx->g_app_timers);
release_timer_list(&ctx->idle_timers);
vm_mutex_unlock(&ctx->mutex);
}

View File

@ -0,0 +1,39 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef LIB_BASE_RUNTIME_TIMER_H_
#define LIB_BASE_RUNTIME_TIMER_H_
#include "bh_platform.h"
#ifdef __cplusplus
extern "C" {
#endif
uint32 bh_get_elpased_ms(uint32 * last_system_clock);
struct _timer_ctx;
typedef struct _timer_ctx * timer_ctx_t;
typedef void (*timer_callback_f)(uint32 id, unsigned int owner);
typedef void (*check_timer_expiry_f)(timer_ctx_t ctx);
timer_ctx_t create_timer_ctx(timer_callback_f timer_handler,
check_timer_expiry_f, int prealloc_num, unsigned int owner);
void destroy_timer_ctx(timer_ctx_t);
unsigned int timer_ctx_get_owner(timer_ctx_t ctx);
uint32 sys_create_timer(timer_ctx_t ctx, int interval, bool is_period,
bool auto_start);
bool sys_timer_destroy(timer_ctx_t ctx, uint32 timer_id);
bool sys_timer_cancel(timer_ctx_t ctx, uint32 timer_id);
bool sys_timer_restart(timer_ctx_t ctx, uint32 timer_id, int interval);
void cleanup_app_timers(timer_ctx_t ctx);
int check_app_timers(timer_ctx_t ctx);
int get_expiry_ms(timer_ctx_t ctx);
#ifdef __cplusplus
}
#endif
#endif /* LIB_BASE_RUNTIME_TIMER_H_ */

View File

@ -0,0 +1,14 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
set (UTILS_SHARED_DIR ${CMAKE_CURRENT_LIST_DIR})
include_directories(${UTILS_SHARED_DIR})
include_directories(${UTILS_SHARED_DIR}/../include)
file (GLOB_RECURSE source_all ${UTILS_SHARED_DIR}/*.c)
set (UTILS_SHARED_SOURCE ${source_all})
LIST (APPEND RUNTIME_LIB_HEADER_LIST "${UTILS_SHARED_DIR}/runtime_timer.h")