19
19
20
20
#include "fmgr.h"
21
21
#include "miscadmin.h"
22
+ #include "nodes/pg_list.h"
23
+ #include "nodes/value.h"
22
24
#include "storage/condition_variable.h"
23
25
#include "storage/dsm_registry.h"
24
26
#include "storage/ipc.h"
25
27
#include "storage/lwlock.h"
26
28
#include "storage/shmem.h"
27
29
#include "utils/builtins.h"
28
30
#include "utils/injection_point.h"
31
+ #include "utils/memutils.h"
29
32
#include "utils/wait_event.h"
30
33
31
34
PG_MODULE_MAGIC ;
32
35
33
36
/* Maximum number of waits usable in injection points at once */
34
37
#define INJ_MAX_WAIT 8
35
38
#define INJ_NAME_MAXLEN 64
36
- #define INJ_MAX_CONDITION 4
37
39
38
40
/*
39
41
* Conditions related to injection points. This tracks in shared memory the
40
- * runtime conditions under which an injection point is allowed to run.
42
+ * runtime conditions under which an injection point is allowed to run,
43
+ * stored as private_data when an injection point is attached, and passed as
44
+ * argument to the callback.
41
45
*
42
46
* If more types of runtime conditions need to be tracked, this structure
43
47
* should be expanded.
44
48
*/
49
+ typedef enum InjectionPointConditionType
50
+ {
51
+ INJ_CONDITION_ALWAYS = 0 , /* always run */
52
+ INJ_CONDITION_PID , /* PID restriction */
53
+ } InjectionPointConditionType ;
54
+
45
55
typedef struct InjectionPointCondition
46
56
{
47
- /* Name of the injection point related to this condition */
48
- char name [ INJ_NAME_MAXLEN ] ;
57
+ /* Type of the condition */
58
+ InjectionPointConditionType type ;
49
59
50
60
/* ID of the process where the injection point is allowed to run */
51
61
int pid ;
52
62
} InjectionPointCondition ;
53
63
64
+ /*
65
+ * List of injection points stored in TopMemoryContext attached
66
+ * locally to this process.
67
+ */
68
+ static List * inj_list_local = NIL ;
69
+
54
70
/* Shared state information for injection points. */
55
71
typedef struct InjectionPointSharedState
56
72
{
@@ -65,9 +81,6 @@ typedef struct InjectionPointSharedState
65
81
66
82
/* Condition variable used for waits and wakeups */
67
83
ConditionVariable wait_point ;
68
-
69
- /* Conditions to run an injection point */
70
- InjectionPointCondition conditions [INJ_MAX_CONDITION ];
71
84
} InjectionPointSharedState ;
72
85
73
86
/* Pointer to shared-memory state. */
@@ -94,7 +107,6 @@ injection_point_init_state(void *ptr)
94
107
SpinLockInit (& state -> lock );
95
108
memset (state -> wait_counts , 0 , sizeof (state -> wait_counts ));
96
109
memset (state -> name , 0 , sizeof (state -> name ));
97
- memset (state -> conditions , 0 , sizeof (state -> conditions ));
98
110
ConditionVariableInit (& state -> wait_point );
99
111
}
100
112
@@ -119,39 +131,23 @@ injection_init_shmem(void)
119
131
* Check runtime conditions associated to an injection point.
120
132
*
121
133
* Returns true if the named injection point is allowed to run, and false
122
- * otherwise. Multiple conditions can be associated to a single injection
123
- * point, so check them all.
134
+ * otherwise.
124
135
*/
125
136
static bool
126
- injection_point_allowed (const char * name )
137
+ injection_point_allowed (InjectionPointCondition * condition )
127
138
{
128
139
bool result = true;
129
140
130
- if (inj_state == NULL )
131
- injection_init_shmem ();
132
-
133
- SpinLockAcquire (& inj_state -> lock );
134
-
135
- for (int i = 0 ; i < INJ_MAX_CONDITION ; i ++ )
141
+ switch (condition -> type )
136
142
{
137
- InjectionPointCondition * condition = & inj_state -> conditions [i ];
138
-
139
- if (strcmp (condition -> name , name ) == 0 )
140
- {
141
- /*
142
- * Check if this injection point is allowed to run in this
143
- * process.
144
- */
143
+ case INJ_CONDITION_PID :
145
144
if (MyProcPid != condition -> pid )
146
- {
147
145
result = false;
148
- break ;
149
- }
150
- }
146
+ break ;
147
+ case INJ_CONDITION_ALWAYS :
148
+ break ;
151
149
}
152
150
153
- SpinLockRelease (& inj_state -> lock );
154
-
155
151
return result ;
156
152
}
157
153
@@ -162,61 +158,28 @@ injection_point_allowed(const char *name)
162
158
static void
163
159
injection_points_cleanup (int code , Datum arg )
164
160
{
165
- char names [INJ_MAX_CONDITION ][INJ_NAME_MAXLEN ] = {0 };
166
- int count = 0 ;
161
+ ListCell * lc ;
167
162
168
163
/* Leave if nothing is tracked locally */
169
164
if (!injection_point_local )
170
165
return ;
171
166
172
- /*
173
- * This is done in three steps: detect the points to detach, detach them
174
- * and release their conditions.
175
- */
176
- SpinLockAcquire (& inj_state -> lock );
177
- for (int i = 0 ; i < INJ_MAX_CONDITION ; i ++ )
178
- {
179
- InjectionPointCondition * condition = & inj_state -> conditions [i ];
180
-
181
- if (condition -> name [0 ] == '\0' )
182
- continue ;
183
-
184
- if (condition -> pid != MyProcPid )
185
- continue ;
186
-
187
- /* Extract the point name to detach */
188
- strlcpy (names [count ], condition -> name , INJ_NAME_MAXLEN );
189
- count ++ ;
190
- }
191
- SpinLockRelease (& inj_state -> lock );
192
-
193
- /* Detach, without holding the spinlock */
194
- for (int i = 0 ; i < count ; i ++ )
195
- (void ) InjectionPointDetach (names [i ]);
196
-
197
- /* Clear all the conditions */
198
- SpinLockAcquire (& inj_state -> lock );
199
- for (int i = 0 ; i < INJ_MAX_CONDITION ; i ++ )
167
+ /* Detach all the local points */
168
+ foreach (lc , inj_list_local )
200
169
{
201
- InjectionPointCondition * condition = & inj_state -> conditions [ i ] ;
170
+ char * name = strVal ( lfirst ( lc )) ;
202
171
203
- if (condition -> name [0 ] == '\0' )
204
- continue ;
205
-
206
- if (condition -> pid != MyProcPid )
207
- continue ;
208
-
209
- condition -> name [0 ] = '\0' ;
210
- condition -> pid = 0 ;
172
+ (void ) InjectionPointDetach (name );
211
173
}
212
- SpinLockRelease (& inj_state -> lock );
213
174
}
214
175
215
176
/* Set of callbacks available to be attached to an injection point. */
216
177
void
217
178
injection_error (const char * name , const void * private_data )
218
179
{
219
- if (!injection_point_allowed (name ))
180
+ InjectionPointCondition * condition = (InjectionPointCondition * ) private_data ;
181
+
182
+ if (!injection_point_allowed (condition ))
220
183
return ;
221
184
222
185
elog (ERROR , "error triggered for injection point %s" , name );
@@ -225,7 +188,9 @@ injection_error(const char *name, const void *private_data)
225
188
void
226
189
injection_notice (const char * name , const void * private_data )
227
190
{
228
- if (!injection_point_allowed (name ))
191
+ InjectionPointCondition * condition = (InjectionPointCondition * ) private_data ;
192
+
193
+ if (!injection_point_allowed (condition ))
229
194
return ;
230
195
231
196
elog (NOTICE , "notice triggered for injection point %s" , name );
@@ -238,11 +203,12 @@ injection_wait(const char *name, const void *private_data)
238
203
uint32 old_wait_counts = 0 ;
239
204
int index = -1 ;
240
205
uint32 injection_wait_event = 0 ;
206
+ InjectionPointCondition * condition = (InjectionPointCondition * ) private_data ;
241
207
242
208
if (inj_state == NULL )
243
209
injection_init_shmem ();
244
210
245
- if (!injection_point_allowed (name ))
211
+ if (!injection_point_allowed (condition ))
246
212
return ;
247
213
248
214
/*
@@ -304,6 +270,7 @@ injection_points_attach(PG_FUNCTION_ARGS)
304
270
char * name = text_to_cstring (PG_GETARG_TEXT_PP (0 ));
305
271
char * action = text_to_cstring (PG_GETARG_TEXT_PP (1 ));
306
272
char * function ;
273
+ InjectionPointCondition condition = {0 };
307
274
308
275
if (strcmp (action , "error" ) == 0 )
309
276
function = "injection_error" ;
@@ -314,37 +281,24 @@ injection_points_attach(PG_FUNCTION_ARGS)
314
281
else
315
282
elog (ERROR , "incorrect action \"%s\" for injection point creation" , action );
316
283
317
- InjectionPointAttach (name , "injection_points" , function , NULL , 0 );
318
-
319
284
if (injection_point_local )
320
285
{
321
- int index = -1 ;
286
+ condition .type = INJ_CONDITION_PID ;
287
+ condition .pid = MyProcPid ;
288
+ }
322
289
323
- /*
324
- * Register runtime condition to link this injection point to the
325
- * current process.
326
- */
327
- SpinLockAcquire (& inj_state -> lock );
328
- for (int i = 0 ; i < INJ_MAX_CONDITION ; i ++ )
329
- {
330
- InjectionPointCondition * condition = & inj_state -> conditions [i ];
331
-
332
- if (condition -> name [0 ] == '\0' )
333
- {
334
- index = i ;
335
- strlcpy (condition -> name , name , INJ_NAME_MAXLEN );
336
- condition -> pid = MyProcPid ;
337
- break ;
338
- }
339
- }
340
- SpinLockRelease (& inj_state -> lock );
290
+ InjectionPointAttach (name , "injection_points" , function , & condition ,
291
+ sizeof (InjectionPointCondition ));
341
292
342
- if (index < 0 )
343
- elog (FATAL ,
344
- "could not find free slot for condition of injection point %s" ,
345
- name );
346
- }
293
+ if (injection_point_local )
294
+ {
295
+ MemoryContext oldctx ;
347
296
297
+ /* Local injection point, so track it for automated cleanup */
298
+ oldctx = MemoryContextSwitchTo (TopMemoryContext );
299
+ inj_list_local = lappend (inj_list_local , makeString (pstrdup (name )));
300
+ MemoryContextSwitchTo (oldctx );
301
+ }
348
302
PG_RETURN_VOID ();
349
303
}
350
304
@@ -436,22 +390,15 @@ injection_points_detach(PG_FUNCTION_ARGS)
436
390
if (!InjectionPointDetach (name ))
437
391
elog (ERROR , "could not detach injection point \"%s\"" , name );
438
392
439
- if (inj_state == NULL )
440
- injection_init_shmem ();
441
-
442
- /* Clean up any conditions associated to this injection point */
443
- SpinLockAcquire (& inj_state -> lock );
444
- for (int i = 0 ; i < INJ_MAX_CONDITION ; i ++ )
393
+ /* Remove point from local list, if required */
394
+ if (inj_list_local != NIL )
445
395
{
446
- InjectionPointCondition * condition = & inj_state -> conditions [ i ] ;
396
+ MemoryContext oldctx ;
447
397
448
- if (strcmp (condition -> name , name ) == 0 )
449
- {
450
- condition -> pid = 0 ;
451
- condition -> name [0 ] = '\0' ;
452
- }
398
+ oldctx = MemoryContextSwitchTo (TopMemoryContext );
399
+ inj_list_local = list_delete (inj_list_local , makeString (name ));
400
+ MemoryContextSwitchTo (oldctx );
453
401
}
454
- SpinLockRelease (& inj_state -> lock );
455
402
456
403
PG_RETURN_VOID ();
457
404
}
0 commit comments