aboutsummaryrefslogtreecommitdiff
path: root/lib/WinRpMalloc/src/dllmain.c
blob: 58f5538605b47e78d13a8b8687474cdabeb1ac25 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
/*
* Copyright (c) 2023 Vaughn Nugent
*
* Library: VNLib
* Package: WinRpMalloc
* File: dllmain.c
*
* WinRpMalloc is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 2 of the License,
* or (at your option) any later version.
*
* WinRpMalloc is distributed 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 GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with WinRpMalloc. If not, see http://www.gnu.org/licenses/.
*/

#include "pch.h"
//Include the native heap header directly from its repo location
#include "../../NativeHeapApi/src/NativeHeapApi.h"

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
	/*
    * Taken from the malloc.c file for initializing the library.
    * and thread events
    */
    switch (ul_reason_for_call)
    {
        case DLL_PROCESS_ATTACH:
            rpmalloc_initialize();
            break;
        case DLL_THREAD_ATTACH:
            rpmalloc_thread_initialize();
            break;
        case DLL_THREAD_DETACH:
            rpmalloc_thread_finalize(1);
            break;
        case DLL_PROCESS_DETACH:
            rpmalloc_finalize();
            break;
    }
    return TRUE;
}

#define GLOBAL_HEAP_HANDLE_VALUE -10
#define GLOBAL_HEAP_INIT_CHECK if (!rpmalloc_is_thread_initialized()) { rpmalloc_thread_initialize(); }

//Define the heap methods

HEAP_METHOD_EXPORT ERRNO HEAP_METHOD_CC heapCreate(UnmanagedHeapDescriptor* flags)
{
    //Check flags
    if (flags->CreationFlags & HEAP_CREATION_IS_SHARED)
    {
        //User requested the global heap, synchronziation is not required, so we can clear the sync flag
        flags->CreationFlags &= ~(HEAP_CREATION_SERIALZE_ENABLED);

        //Set the heap pointer as the global heap value
        flags->HeapPointer = (LPVOID)GLOBAL_HEAP_HANDLE_VALUE;

        //Success
        return TRUE;
    }
    
    //Allocate a first class heap
    flags->HeapPointer = rpmalloc_heap_acquire();

    //Ignore remaining flags, zero/sync can be user optional

    //Return value greater than 0
    return flags->HeapPointer;
}


HEAP_METHOD_EXPORT ERRNO HEAP_METHOD_CC heapDestroy(LPVOID heap)
{
    //Destroy the heap
    if ((int)heap == GLOBAL_HEAP_HANDLE_VALUE) 
    {
        //Gloal heap, do nothing, and allow the entrypoint cleanup
        return TRUE;
    }

    //Free all before destroy
    rpmalloc_heap_free_all(heap);

    //Destroy the heap
    rpmalloc_heap_release(heap);

    return TRUE;
}


HEAP_METHOD_EXPORT LPVOID HEAP_METHOD_CC heapAlloc(LPVOID heap, size_t elements, size_t alignment, BOOL zero)
{
    //Multiply for element size
    size_t size = elements * alignment;

    //Check for global heap
    if ((int)heap == GLOBAL_HEAP_HANDLE_VALUE)
    {          
        /*
        * When called from the dotnet CLR the thread may not call the DLL
        * thread attach method, so we need to check and initialze the heap
        * for the current thread
        */
        GLOBAL_HEAP_INIT_CHECK

        //Allocate the block
        if (zero)
        {
            //Calloc
            return rpcalloc(elements, alignment);
        }
        else
        {
            //Alloc without zero
            return rpmalloc(size);
        }
    }
    else
    {
        //First class heap, lock is held by caller, optionally zero the block
        if (zero) 
        {
            return rpmalloc_heap_calloc(heap, alignment, elements);
        }
        else
        {
            return rpmalloc_heap_alloc(heap, size);
        }
    }
}


HEAP_METHOD_EXPORT LPVOID HEAP_METHOD_CC heapRealloc(LPVOID heap, LPVOID block, size_t elements, size_t alignment, BOOL zero)
{
    //Multiply for element size
    size_t size = elements * alignment;

    //Check for global heap
    if ((int)heap == GLOBAL_HEAP_HANDLE_VALUE)
    {
        /*
        * When called from the dotnet CLR the thread may not call the DLL
        * thread attach method, so we need to check and initialze the heap
        * for the current thread
        */
        GLOBAL_HEAP_INIT_CHECK

        //Calloc
        return rprealloc(block, size);
    }
    else
    {
        //First class heap, lock is held by caller
        return rpmalloc_heap_realloc(heap, block, size, 0);
    }
}


HEAP_METHOD_EXPORT ERRNO HEAP_METHOD_CC heapFree(LPVOID heap, LPVOID block)
{
    //Check for global heap
    if ((int)heap == GLOBAL_HEAP_HANDLE_VALUE)
    {
        /*
        * If free happens on a different thread, we must allocate the heap
        * its cheap to check 
        */

        GLOBAL_HEAP_INIT_CHECK

        //free block
        rpfree(block);
    }
    else
    {
        //First class heap, lock is held by caller
        rpmalloc_heap_free(heap, block);
    }

    return TRUE;
}