1 /*
2   +----------------------------------------------------------------------+
3   | Swoole                                                               |
4   +----------------------------------------------------------------------+
5   | This source file is subject to version 2.0 of the Apache license,    |
6   | that is bundled with this package in the file LICENSE, and is        |
7   | available through the world-wide-web at the following url:           |
8   | http://www.apache.org/licenses/LICENSE-2.0.html                      |
9   | If you did not receive a copy of the Apache2.0 license and are unable|
10   | to obtain it through the world-wide-web, please send a note to       |
11   | license@swoole.com so we can mail you a copy immediately.            |
12   +----------------------------------------------------------------------+
13   | Author: Tianfeng Han  <mikan.tenny@gmail.com>                        |
14   +----------------------------------------------------------------------+
15 */
16 
17 #include "swoole.h"
18 #include "swoole_file.h"
19 #include "swoole_memory.h"
20 
21 #include <sys/mman.h>
22 
23 #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
24 #define MAP_ANONYMOUS MAP_ANON
25 #endif
26 
27 namespace swoole {
28 
29 struct SharedMemory {
30     size_t size_;
31 
32     static void *alloc(size_t size);
33     static void free(void *ptr);
34 
fetch_objectswoole::SharedMemory35     static SharedMemory *fetch_object(void *ptr) {
36         return (SharedMemory *) ((char *) ptr - sizeof(SharedMemory));
37     }
38 };
39 
alloc(size_t size)40 void *SharedMemory::alloc(size_t size) {
41     void *mem;
42     int tmpfd = -1;
43     int flags = MAP_SHARED;
44     SharedMemory object;
45 
46     size = SW_MEM_ALIGNED_SIZE(size);
47     size += sizeof(SharedMemory);
48 
49 #ifdef MAP_ANONYMOUS
50     flags |= MAP_ANONYMOUS;
51 #else
52     File zerofile("/dev/zero", O_RDWR);
53     if (!zerofile.ready()) {
54         return nullptr;
55     }
56     tmpfd = zerofile.get_fd();
57 #endif
58     mem = mmap(nullptr, size, PROT_READ | PROT_WRITE, flags, tmpfd, 0);
59 #ifdef MAP_FAILED
60     if (mem == MAP_FAILED)
61 #else
62     if (!mem)
63 #endif
64     {
65         swoole_sys_warning("mmap(%lu) failed", size);
66         return nullptr;
67     } else {
68         object.size_ = size;
69         memcpy(mem, &object, sizeof(object));
70         return (char *) mem + sizeof(object);
71     }
72 }
73 
free(void * ptr)74 void SharedMemory::free(void *ptr) {
75     SharedMemory *object = SharedMemory::fetch_object(ptr);
76     size_t size = object->size_;
77     if (munmap(object, size) < 0) {
78         swoole_sys_warning("munmap(%p, %lu) failed", object, size);
79     }
80 }
81 
82 }  // namespace swoole
83 
84 using swoole::SharedMemory;
85 
sw_shm_malloc(size_t size)86 void *sw_shm_malloc(size_t size) {
87     return SharedMemory::alloc(size);
88 }
89 
sw_shm_calloc(size_t num,size_t _size)90 void *sw_shm_calloc(size_t num, size_t _size) {
91     return SharedMemory::alloc(num * _size);
92 }
93 
sw_shm_protect(void * ptr,int flags)94 int sw_shm_protect(void *ptr, int flags) {
95     SharedMemory *object = SharedMemory::fetch_object(ptr);
96     return mprotect(object, object->size_, flags);
97 }
98 
sw_shm_free(void * ptr)99 void sw_shm_free(void *ptr) {
100     SharedMemory::free(ptr);
101 }
102 
sw_shm_realloc(void * ptr,size_t new_size)103 void *sw_shm_realloc(void *ptr, size_t new_size) {
104     SharedMemory *object = SharedMemory::fetch_object(ptr);
105     void *new_ptr = sw_shm_malloc(new_size);
106     if (new_ptr == nullptr) {
107         return nullptr;
108     }
109     memcpy(new_ptr, ptr, object->size_);
110     SharedMemory::free(ptr);
111     return new_ptr;
112 }
113