1 /*
2  * %CopyrightBegin%
3  *
4  * Copyright Ericsson AB 2013-2016. All Rights Reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * %CopyrightEnd%
19  */
20 
21 
22 #ifndef __WIN32__
23 #include <sys/types.h>
24 #include <unistd.h>
25 #include <errno.h>
26 #endif
27 #include <stdio.h>
28 #include <stdarg.h>
29 #include <string.h>
30 #include "testcase_driver.h"
31 #include "allocator_test.h"
32 
33 #define FATAL_ASSERT(A)						\
34     ((void) ((A)						\
35 	     ? 1						\
36 	     : (fatal_assert_failed(#A,				\
37 				    (char *) __FILE__,		\
38 				    __LINE__),			\
39 		0)))
40 
41 static void
fatal_assert_failed(char * expr,char * file,int line)42 fatal_assert_failed(char* expr, char* file, int line)
43 {
44     fflush(stdout);
45     fprintf(stderr, "%s:%d: Assertion failed: %s\n",
46 	    file, line, expr);
47     fflush(stderr);
48     abort();
49 }
50 
51 #define TEST_NO_THREADS 10
52 #define TEST_NO_CARRIERS_PER_THREAD 100000
53 #define TEST_CARRIERS_OFFSET 5
54 
55 static Allctr_t *alloc = NULL;
56 
stop_allocator(void)57 static void stop_allocator(void)
58 {
59     if (alloc) {
60 	STOP_ALC(alloc);
61 	alloc = NULL;
62     }
63 }
64 
65 
66 void *thread_func(void *arg);
67 
68 char *
testcase_name(void)69 testcase_name(void)
70 {
71     return "cpool";
72 }
73 
74 void
testcase_cleanup(TestCaseState_t * tcs)75 testcase_cleanup(TestCaseState_t *tcs)
76 {
77     stop_allocator();
78 }
79 
80 void *
thread_func(void * arg)81 thread_func(void *arg)
82 {
83     Carrier_t *crr = (Carrier_t *) arg;
84     int i;
85 
86     for (i = 0; i < (TEST_NO_CARRIERS_PER_THREAD+TEST_CARRIERS_OFFSET); i++) {
87 	int d;
88 	if (i < TEST_NO_CARRIERS_PER_THREAD) {
89 	    (void) CPOOL_INSERT(alloc, crr[i]);
90 	    if ((i & 0x7) == 0)
91 		FATAL_ASSERT(CPOOL_IS_IN_POOL(alloc, crr[i]));
92 	}
93 	d = i-TEST_CARRIERS_OFFSET;
94 	if (d >= 0) {
95 	    (void) CPOOL_DELETE(alloc, crr[d]);
96 	    if ((d & 0x7) == 0)
97 		FATAL_ASSERT(!CPOOL_IS_IN_POOL(alloc, crr[d]));
98 	}
99     }
100     for (i = 0; i < TEST_NO_CARRIERS_PER_THREAD; i++)
101 	FATAL_ASSERT(!CPOOL_IS_IN_POOL(alloc, crr[i]));
102     return NULL;
103 }
104 
105 static struct {
106     erts_thread tid;
107     Carrier_t *crr[TEST_NO_CARRIERS_PER_THREAD];
108 } threads[TEST_NO_THREADS] = {{0}};
109 
110 void
testcase_run(TestCaseState_t * tcs)111 testcase_run(TestCaseState_t *tcs)
112 {
113     int no_threads, t, c;
114     char *block, *p;
115     Ulong zcrr_sz;
116 
117     if (!IS_SMP_ENABLED)
118 	testcase_skipped(tcs, "No SMP support");
119 
120     alloc = START_ALC("Zero carrier allocator", 1, NULL);
121 
122     zcrr_sz = ZERO_CRR_SIZE;
123 
124     block = p = ALLOC(alloc, zcrr_sz*TEST_NO_THREADS*TEST_NO_CARRIERS_PER_THREAD);
125 
126     ASSERT(tcs, block != NULL);
127 
128     for (t = 0; t < TEST_NO_THREADS; t++) {
129 	for (c = 0; c < TEST_NO_CARRIERS_PER_THREAD; c++) {
130 	    Carrier_t *crr = (Carrier_t *) p;
131 	    p += zcrr_sz;
132 	    (void) ZERO_CRR_INIT(alloc, crr);
133 	    threads[t].crr[c] = crr;
134 	}
135     }
136 
137     no_threads = 0;
138     for (t = 0; t < TEST_NO_THREADS; t++) {
139     	threads[t].tid = THR_CREATE(thread_func, (void *) threads[t].crr);
140 	if (threads[t].tid) {
141 	    testcase_printf(tcs, "Successfully created thread %d\n", t);
142 	    no_threads++;
143 	}
144 	else {
145 	    testcase_printf(tcs, "Failed to create thread %d\n", t);
146 	    break;
147 	}
148     }
149 
150     for (t = 0; t < no_threads; t++)
151 	THR_JOIN(threads[t].tid);
152 
153     FATAL_ASSERT(CPOOL_IS_EMPTY(alloc));
154 
155     FREE(alloc, block);
156 
157     ASSERT(tcs, no_threads == TEST_NO_THREADS);
158 }
159 
160 ERL_NIF_INIT(cpool, testcase_nif_funcs, testcase_nif_init,
161 	     NULL, NULL, NULL);
162