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 "ecpgtype.h" |
8 | #include "ecpglib.h" |
9 | #include "ecpgerrno.h" |
10 | #include "ecpglib_extern.h" |
11 | |
12 | void |
13 | ecpg_free(void *ptr) |
14 | { |
15 | free(ptr); |
16 | } |
17 | |
18 | char * |
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 * |
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 * |
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 |
76 | auto_mem_destructor(void *arg) |
77 | { |
78 | (void) arg; /* keep the compiler quiet */ |
79 | ECPGfree_auto_mem(); |
80 | } |
81 | |
82 | static 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 * |
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 |
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 * |
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 |
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 |
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 |
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 | |