Line data Source code
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
13 0 : ecpg_free(void *ptr)
14 : {
15 0 : free(ptr);
16 0 : }
17 :
18 : char *
19 0 : ecpg_alloc(long size, int lineno)
20 : {
21 0 : char *new = (char *) calloc(1L, size);
22 :
23 0 : if (!new)
24 : {
25 0 : ecpg_raise(lineno, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
26 0 : return NULL;
27 : }
28 :
29 0 : return new;
30 0 : }
31 :
32 : char *
33 0 : ecpg_realloc(void *ptr, long size, int lineno)
34 : {
35 0 : char *new = (char *) realloc(ptr, size);
36 :
37 0 : if (!new)
38 : {
39 0 : ecpg_raise(lineno, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
40 0 : return NULL;
41 : }
42 :
43 0 : return new;
44 0 : }
45 :
46 : /*
47 : * Wrapper for strdup(), with NULL in input treated as a correct case.
48 : *
49 : * "alloc_failed" can be optionally specified by the caller to check for
50 : * allocation failures. The caller is responsible for its initialization,
51 : * as ecpg_strdup() may be called repeatedly across multiple allocations.
52 : */
53 : char *
54 0 : ecpg_strdup(const char *string, int lineno, bool *alloc_failed)
55 : {
56 0 : char *new;
57 :
58 0 : if (string == NULL)
59 0 : return NULL;
60 :
61 0 : new = strdup(string);
62 0 : if (!new)
63 : {
64 0 : if (alloc_failed)
65 0 : *alloc_failed = true;
66 0 : ecpg_raise(lineno, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
67 0 : return NULL;
68 : }
69 :
70 0 : return new;
71 0 : }
72 :
73 : /* keep a list of memory we allocated for the user */
74 : struct auto_mem
75 : {
76 : void *pointer;
77 : struct auto_mem *next;
78 : };
79 :
80 : static pthread_key_t auto_mem_key;
81 : static pthread_once_t auto_mem_once = PTHREAD_ONCE_INIT;
82 :
83 : static void
84 0 : auto_mem_destructor(void *arg)
85 : {
86 0 : (void) arg; /* keep the compiler quiet */
87 0 : ECPGfree_auto_mem();
88 0 : }
89 :
90 : static void
91 0 : auto_mem_key_init(void)
92 : {
93 0 : pthread_key_create(&auto_mem_key, auto_mem_destructor);
94 0 : }
95 :
96 : static struct auto_mem *
97 0 : get_auto_allocs(void)
98 : {
99 0 : pthread_once(&auto_mem_once, auto_mem_key_init);
100 0 : return (struct auto_mem *) pthread_getspecific(auto_mem_key);
101 : }
102 :
103 : static void
104 0 : set_auto_allocs(struct auto_mem *am)
105 : {
106 0 : pthread_setspecific(auto_mem_key, am);
107 0 : }
108 :
109 : char *
110 0 : ecpg_auto_alloc(long size, int lineno)
111 : {
112 0 : void *ptr = ecpg_alloc(size, lineno);
113 :
114 0 : if (!ptr)
115 0 : return NULL;
116 :
117 0 : if (!ecpg_add_mem(ptr, lineno))
118 : {
119 0 : ecpg_free(ptr);
120 0 : return NULL;
121 : }
122 0 : return ptr;
123 0 : }
124 :
125 : bool
126 0 : ecpg_add_mem(void *ptr, int lineno)
127 : {
128 0 : struct auto_mem *am = (struct auto_mem *) ecpg_alloc(sizeof(struct auto_mem), lineno);
129 :
130 0 : if (!am)
131 0 : return false;
132 :
133 0 : am->pointer = ptr;
134 0 : am->next = get_auto_allocs();
135 0 : set_auto_allocs(am);
136 0 : return true;
137 0 : }
138 :
139 : void
140 0 : ECPGfree_auto_mem(void)
141 : {
142 0 : struct auto_mem *am = get_auto_allocs();
143 :
144 : /* free all memory we have allocated for the user */
145 0 : if (am)
146 : {
147 0 : do
148 : {
149 0 : struct auto_mem *act = am;
150 :
151 0 : am = am->next;
152 0 : ecpg_free(act->pointer);
153 0 : ecpg_free(act);
154 0 : } while (am);
155 0 : set_auto_allocs(NULL);
156 0 : }
157 0 : }
158 :
159 : void
160 0 : ecpg_clear_auto_mem(void)
161 : {
162 0 : struct auto_mem *am = get_auto_allocs();
163 :
164 : /* only free our own structure */
165 0 : if (am)
166 : {
167 0 : do
168 : {
169 0 : struct auto_mem *act = am;
170 :
171 0 : am = am->next;
172 0 : ecpg_free(act);
173 0 : } while (am);
174 0 : set_auto_allocs(NULL);
175 0 : }
176 0 : }
|