1 /*
2     Copyright (c) 2005-2020 Intel Corporation
3 
4     Licensed under the Apache License, Version 2.0 (the "License");
5     you may not use this file except in compliance with the License.
6     You may obtain a copy of the License at
7 
8         http://www.apache.org/licenses/LICENSE-2.0
9 
10     Unless required by applicable law or agreed to in writing, software
11     distributed under the License is distributed on an "AS IS" BASIS,
12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13     See the License for the specific language governing permissions and
14     limitations under the License.
15 */
16 
17 #if _USRDLL
18 
19 #include <stdlib.h>
20 #include "harness_defs.h"
21 #include "tbb/scalable_allocator.h"
22 #if __TBB_SOURCE_DIRECTLY_INCLUDED
23 #include "../tbbmalloc/tbbmalloc_internal_api.h"
24 #endif
25 
26 #define HARNESS_CUSTOM_MAIN 1
27 #define HARNESS_NO_PARSE_COMMAND_LINE 1
28 #include "harness.h"
29 #include "harness_assert.h"
30 
31 #if _WIN32||_WIN64
32 extern "C" {
33     extern __declspec(dllexport) void callDll();
34 }
35 #endif
36 
callDll()37 extern "C" void callDll()
38 {
39     static const int NUM = 20;
40     void *ptrs[NUM];
41 
42     for (int i=0; i<NUM; i++) {
43         ptrs[i] = scalable_malloc(i*1024);
44         ASSERT(ptrs[i], NULL);
45     }
46     for (int i=0; i<NUM; i++)
47         scalable_free(ptrs[i]);
48 }
49 
50 #if __TBB_SOURCE_DIRECTLY_INCLUDED
51 
52 struct RegisterProcessShutdownNotification {
~RegisterProcessShutdownNotificationRegisterProcessShutdownNotification53     ~RegisterProcessShutdownNotification() {
54         __TBB_mallocProcessShutdownNotification();
55     }
56 };
57 
58 static RegisterProcessShutdownNotification reg;
59 
60 #endif
61 
62 #else // _USRDLL
63 
64 #define __TBB_NO_IMPLICIT_LINKAGE 1
65 #include "harness_dynamic_libs.h"
66 #if __TBB_WIN8UI_SUPPORT
67 // FIXME: fix the test to support Windows* 8 Store Apps mode.
68 #define HARNESS_SKIP_TEST 1
69 #endif
70 #define HARNESS_NO_PARSE_COMMAND_LINE 1
71 #include "harness.h"
72 
73 #if !HARNESS_SKIP_TEST
74 
75 #include "harness_memory.h"
76 #include "harness_tbb_independence.h"
77 #include "harness_barrier.h"
78 
79 class UseDll {
80     Harness::FunctionAddress run;
81 public:
UseDll(Harness::FunctionAddress runPtr)82     UseDll(Harness::FunctionAddress runPtr) : run(runPtr) { }
operator ()(int) const83     void operator()( int /*id*/ ) const {
84         (*run)();
85     }
86 };
87 
LoadThreadsUnload()88 void LoadThreadsUnload()
89 {
90     Harness::LIBRARY_HANDLE lib =
91         Harness::OpenLibrary(TEST_LIBRARY_NAME("test_malloc_used_by_lib_dll"));
92     ASSERT(lib, "Can't load " TEST_LIBRARY_NAME("test_malloc_used_by_lib_dll"));
93     NativeParallelFor( 4, UseDll( Harness::GetAddress(lib, "callDll") ) );
94     Harness::CloseLibrary(lib);
95 }
96 
97 struct UnloadCallback {
98     Harness::LIBRARY_HANDLE lib;
99 
operator ()UnloadCallback100     void operator() () const {
101         Harness::CloseLibrary(lib);
102     }
103 };
104 
105 struct RunWithLoad : NoAssign {
106     static Harness::SpinBarrier startBarr, endBarr;
107     static UnloadCallback unloadCallback;
108     static Harness::FunctionAddress runPtr;
109 
operator ()RunWithLoad110     void operator()(int id) const {
111         if (!id) {
112             Harness::LIBRARY_HANDLE lib =
113                 Harness::OpenLibrary(TEST_LIBRARY_NAME("test_malloc_used_by_lib_dll"));
114             ASSERT(lib, "Can't load " TEST_LIBRARY_NAME("test_malloc_used_by_lib_dll"));
115             runPtr = Harness::GetAddress(lib, "callDll");
116             unloadCallback.lib = lib;
117         }
118         startBarr.wait();
119         (*runPtr)();
120         endBarr.wait(unloadCallback);
121     }
122 };
123 
124 Harness::SpinBarrier RunWithLoad::startBarr, RunWithLoad::endBarr;
125 UnloadCallback RunWithLoad::unloadCallback;
126 Harness::FunctionAddress RunWithLoad::runPtr;
127 
ThreadsLoadUnload()128 void ThreadsLoadUnload()
129 {
130     const int threads = 4;
131 
132     RunWithLoad::startBarr.initialize(threads);
133     RunWithLoad::endBarr.initialize(threads);
134     NativeParallelFor(threads, RunWithLoad());
135 }
136 
TestMain()137 int TestMain () {
138     const int ITERS = 20;
139     int i;
140     std::ptrdiff_t memory_leak = 0;
141 
142     GetMemoryUsage();
143 
144     for (int run = 0; run<2; run++) {
145         // expect that memory consumption stabilized after several runs
146         for (i=0; i<ITERS; i++) {
147             std::size_t memory_in_use = GetMemoryUsage();
148             if (run)
149                 LoadThreadsUnload();
150             else
151                 ThreadsLoadUnload();
152             memory_leak = GetMemoryUsage() - memory_in_use;
153             if (memory_leak == 0)  // possibly too strong?
154                 break;
155         }
156         if(i==ITERS) {
157             // not stabilized, could be leak
158             REPORT( "Error: memory leak of up to %ld bytes\n", static_cast<long>(memory_leak));
159             exit(1);
160         }
161     }
162 
163     return Harness::Done;
164 }
165 
166 #endif /* HARNESS_SKIP_TEST */
167 #endif // _USRDLL
168