diff --git a/src/platforms/pc/mmap.c b/src/platforms/pc/mmap.c new file mode 100644 index 000000000..dad31ee93 --- /dev/null +++ b/src/platforms/pc/mmap.c @@ -0,0 +1,144 @@ +/** + * File: mmap.c + * Author: AWTK Develop Team + * Brief: mmap + * + * Copyright (c) 2018 - 2020 Guangzhou ZHIYUAN Electronics Co.,Ltd. + * + * This program is dimmapibuted in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * License file for more details. + * + */ + +/** + * History: + * ================================================================ + * 2020-12-11 Li XianJing created + * + */ + +#include "tkc/fs.h" +#include "tkc/mem.h" +#include "tkc/utils.h" +#include "tkc/mmap.h" + +#ifndef WIN32 +#include +#include +#endif /*WIN32*/ + +mmap_t* mmap_create(const char* filename, bool_t writable, bool_t shared) { +#ifdef WIN32 + wchar_t wfilename[MAX_PATH+1]; + HANDLE hFile = INVALID_HANDLE_VALUE; + HANDLE handle = INVALID_HANDLE_VALUE; + DWORD flProtect = writable ? PAGE_READWRITE : PAGE_READONLY; + DWORD dwDesiredAccess = writable ? GENERIC_WRITE : GENERIC_READ; + uint32_t size = file_get_size(filename); + return_value_if_fail(filename != NULL && size > 0, NULL); + + tk_utf8_to_utf16(filename, wfilename, MAX_PATH); + hFile = CreateFileW(wfilename, + dwDesiredAccess, + 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + return_value_if_fail(hFile != INVALID_HANDLE_VALUE, NULL); + handle = CreateFileMapping(hFile, NULL, flProtect, DWORD_HI(0), DWORD_LO(size), NULL); + goto_error_if_fail(hFile != INVALID_HANDLE_VALUE); + dwDesiredAccess = shared ? FILE_MAP_WRITE : FILE_MAP_READ; + + map->size = size; + map->fd = (void*)hFile; + map->handle = (void*)handle; + map->data = MapViewOfFile(handle, dwDesiredAccess, 0, 0, size); + + return map; +error: + if (hFile != INVALID_HANDLE_VALUE) { + CloseHandle(hFile); + } + if (map != NULL) { + TKMEM_FREE(map); + } + return NULL; +#else + int fd = 0; + int size = 0; + int flags = 0; + int protect = 0; + mmap_t* map = NULL; + return_value_if_fail(filename != NULL, NULL); + size = file_get_size(filename); + return_value_if_fail(size > 0, NULL); + + flags = writable ? O_RDWR : O_RDONLY; + protect = writable ? PROT_WRITE | PROT_READ : PROT_READ; + fd = open(filename, flags); + return_value_if_fail(fd >= 0, NULL); + + map = TKMEM_ZALLOC(mmap_t); + goto_error_if_fail(map != NULL); + + flags = MAP_FILE | (shared ? MAP_SHARED : MAP_PRIVATE); + map->data = mmap(NULL, size, protect, flags, fd, 0); + goto_error_if_fail(map->handle != MAP_FAILED); + + map->size = size; + map->fd = tk_pointer_from_int(fd); + return map; +error: + if (fd > 0) { + close(fd); + } + if (map != NULL) { + TKMEM_FREE(map); + } + return NULL; +#endif /*WIN32*/ +} + +ret_t mmap_destroy(mmap_t* map) { +#ifdef WIN32 + HANDLE fd = INVALID_HANDLE_VALUE; + HANDLE handle = INVALID_HANDLE_VALUE; + return_value_if_fail(map != NULL, RET_BAD_PARAMS); + + fd = (HANDLE)(map->fd); + handle = (HANDLE)(map->handle); + + if(fd != INVALID_HANDLE_VALUE) { + CloseHandle(fd); + } + + if(handle != INVALID_HANDLE_VALUE) { + CloseHandle(handle); + } + + if(map->data != NULL) { + UnmapViewOfFile(map->data); + } + + memset(map, 0x00, sizeof(mmap_t)); + TKMEM_FREE(map); + + return RET_OK; +#else + int fd = 0; + return_value_if_fail(map != NULL, RET_BAD_PARAMS); + fd = tk_pointer_to_int(map->fd); + if (fd >= 0) { + close(fd); + } + if (map->data != NULL) { + munmap(map->data, map->size); + } + memset(map, 0x00, sizeof(mmap_t)); + TKMEM_FREE(map); +#endif /*WIN32*/ + return RET_OK; +} diff --git a/src/tkc/mmap.h b/src/tkc/mmap.h new file mode 100644 index 000000000..9b6412bac --- /dev/null +++ b/src/tkc/mmap.h @@ -0,0 +1,78 @@ +/** + * File: mmap.h + * Author: AWTK Develop Team + * Brief: mmap + * + * Copyright (c) 2018 - 2020 Guangzhou ZHIYUAN Electronics Co.,Ltd. + * + * This program is dimmapibuted in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * License file for more details. + * + */ + +/** + * History: + * ================================================================ + * 2020-12-11 Li XianJing created + * + */ + +#ifndef TK_MMAP_H +#define TK_MMAP_H + +#include "tkc/str.h" + +BEGIN_C_DECLS + +/** + * @class mmap_t + * 把文件内容映射到内存。 + * + */ +typedef struct _mmap_t { + /** + * @property {void*} data + * @annotation ["readable"] + * 内存地址。 + */ + void* data; + + /** + * @property {uint32_t} size + * @annotation ["readable"] + * 数据长度。 + */ + uint32_t size; + /*private*/ + void* handle; + void* fd; +} mmap_t; + +/** + * @method mmap_create + * 初始化mmap对象。 + * @annotation ["constructor"] + * @param {mmap_t*} mmap mmap对象。 + * @param {const char*} filename 文件名。 + * @param {bool_t} writable 是否可写。 + * @param {bool_t} shared 是否共享。 + * + * @return {mmap_t*} mmap对象本身。 + */ +mmap_t* mmap_create(const char* filename, bool_t writable, bool_t shared); + +/** + * @method mmap_destroy + * 销毁mmap。 + * @param {mmap_t*} mmap mmap对象。 + * + * @return {ret_t} 返回RET_OK表示成功,否则表示失败。 + */ +ret_t mmap_destroy(mmap_t* mmap); + +END_C_DECLS + +#endif /*TK_MMAP_H*/ + diff --git a/tests/mmap_test.cc b/tests/mmap_test.cc new file mode 100644 index 000000000..f030e59dc --- /dev/null +++ b/tests/mmap_test.cc @@ -0,0 +1,33 @@ +#include "tkc/fs.h" +#include "tkc/mmap.h" +#include "gtest/gtest.h" + + +TEST(MMap, read) { + const char* str = "test"; + const char* filename = "test.bin"; + file_write(filename, str, strlen(str)); + mmap_t* map = mmap_create(filename, FALSE, FALSE); + ASSERT_EQ(map->size, strlen(str)); + ASSERT_EQ(memcmp(map->data, str, strlen(str)) == 0, TRUE); + mmap_destroy(map); + file_remove(filename); +} + +TEST(MMap, write) { + const char* str = "test"; + const char* filename = "test.bin"; + file_write(filename, str, strlen(str)); + mmap_t* map = mmap_create(filename, TRUE, FALSE); + ASSERT_EQ(map->size, strlen(str)); + ASSERT_EQ(memcmp(map->data, str, strlen(str)) == 0, TRUE); + memcpy(map->data, "1234", 4); + mmap_destroy(map); + + map = mmap_create(filename, TRUE, FALSE); + ASSERT_EQ(map->size, strlen(str)); + ASSERT_EQ(memcmp(map->data, str, strlen(str)) == 0, TRUE); + mmap_destroy(map); + + file_remove(filename); +}