1 /* src/interfaces/ecpg/ecpglib/memory.c */
2 
3 #define POSTGRES_ECPG_INTERNAL
4 #include "postgres_fe.h"
5 
6 #include "ecpg-pthread-win32.h"
7 #include "ecpgerrno.h"
8 #include "ecpglib.h"
9 #include "ecpglib_extern.h"
10 #include "ecpgtype.h"
11 
12 void
ecpg_free(void * ptr)13 ecpg_free(void *ptr)
14 {
15 	free(ptr);
16 }
17 
18 char *
ecpg_alloc(long size,int lineno)19 ecpg_alloc(long size, int lineno)
20 {
21 	char	   *new = (char *) calloc(1L, size);
22 
23 	if (!new)
24 	{
25 		ecpg_raise(lineno, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
26 		return NULL;
27 	}
28 
29 	return new;
30 }
31 
32 char *
ecpg_realloc(void * ptr,long size,int lineno)33 ecpg_realloc(void *ptr, long size, int lineno)
34 {
35 	char	   *new = (char *) realloc(ptr, size);
36 
37 	if (!new)
38 	{
39 		ecpg_raise(lineno, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
40 		return NULL;
41 	}
42 
43 	return new;
44 }
45 
46 char *
ecpg_strdup(const char * string,int lineno)47 ecpg_strdup(const char *string, int lineno)
48 {
49 	char	   *new;
50 
51 	if (string == NULL)
52 		return NULL;
53 
54 	new = strdup(string);
55 	if (!new)
56 	{
57 		ecpg_raise(lineno, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
58 		return NULL;
59 	}
60 
61 	return new;
62 }
63 
64 /* keep a list of memory we allocated for the user */
65 struct auto_mem
66 {
67 	void	   *pointer;
68 	struct auto_mem *next;
69 };
70 
71 #ifdef ENABLE_THREAD_SAFETY
72 static pthread_key_t auto_mem_key;
73 static pthread_once_t auto_mem_once = PTHREAD_ONCE_INIT;
74 
75 static void
auto_mem_destructor(void * arg)76 auto_mem_destructor(void *arg)
77 {
78 	(void) arg;					/* keep the compiler quiet */
79 	ECPGfree_auto_mem();
80 }
81 
82 static void
auto_mem_key_init(void)83 auto_mem_key_init(void)
84 {
85 	pthread_key_create(&auto_mem_key, auto_mem_destructor);
86 }
87 
88 static struct auto_mem *
get_auto_allocs(void)89 get_auto_allocs(void)
90 {
91 	pthread_once(&auto_mem_once, auto_mem_key_init);
92 	return (struct auto_mem *) pthread_getspecific(auto_mem_key);
93 }
94 
95 static void
set_auto_allocs(struct auto_mem * am)96 set_auto_allocs(struct auto_mem *am)
97 {
98 	pthread_setspecific(auto_mem_key, am);
99 }
100 #else
101 static struct auto_mem *auto_allocs = NULL;
102 
103 #define get_auto_allocs()		(auto_allocs)
104 #define set_auto_allocs(am)		do { auto_allocs = (am); } while(0)
105 #endif
106 
107 char *
ecpg_auto_alloc(long size,int lineno)108 ecpg_auto_alloc(long size, int lineno)
109 {
110 	void	   *ptr = (void *) ecpg_alloc(size, lineno);
111 
112 	if (!ptr)
113 		return NULL;
114 
115 	if (!ecpg_add_mem(ptr, lineno))
116 	{
117 		ecpg_free(ptr);
118 		return NULL;
119 	}
120 	return ptr;
121 }
122 
123 bool
ecpg_add_mem(void * ptr,int lineno)124 ecpg_add_mem(void *ptr, int lineno)
125 {
126 	struct auto_mem *am = (struct auto_mem *) ecpg_alloc(sizeof(struct auto_mem), lineno);
127 
128 	if (!am)
129 		return false;
130 
131 	am->pointer = ptr;
132 	am->next = get_auto_allocs();
133 	set_auto_allocs(am);
134 	return true;
135 }
136 
137 void
ECPGfree_auto_mem(void)138 ECPGfree_auto_mem(void)
139 {
140 	struct auto_mem *am = get_auto_allocs();
141 
142 	/* free all memory we have allocated for the user */
143 	if (am)
144 	{
145 		do
146 		{
147 			struct auto_mem *act = am;
148 
149 			am = am->next;
150 			ecpg_free(act->pointer);
151 			ecpg_free(act);
152 		} while (am);
153 		set_auto_allocs(NULL);
154 	}
155 }
156 
157 void
ecpg_clear_auto_mem(void)158 ecpg_clear_auto_mem(void)
159 {
160 	struct auto_mem *am = get_auto_allocs();
161 
162 	/* only free our own structure */
163 	if (am)
164 	{
165 		do
166 		{
167 			struct auto_mem *act = am;
168 
169 			am = am->next;
170 			ecpg_free(act);
171 		} while (am);
172 		set_auto_allocs(NULL);
173 	}
174 }
175