pg_query 1.3.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +86 -52
  3. data/README.md +72 -65
  4. data/Rakefile +82 -1
  5. data/ext/pg_query/extconf.rb +2 -39
  6. data/ext/pg_query/guc-file.c +0 -0
  7. data/ext/pg_query/pg_query.c +104 -0
  8. data/ext/pg_query/pg_query.pb-c.c +37628 -0
  9. data/ext/pg_query/pg_query_deparse.c +9953 -0
  10. data/ext/pg_query/pg_query_fingerprint.c +292 -0
  11. data/ext/pg_query/pg_query_fingerprint.h +8 -0
  12. data/ext/pg_query/pg_query_internal.h +24 -0
  13. data/ext/pg_query/pg_query_json_plpgsql.c +738 -0
  14. data/ext/pg_query/pg_query_json_plpgsql.h +9 -0
  15. data/ext/pg_query/pg_query_normalize.c +437 -0
  16. data/ext/pg_query/pg_query_outfuncs.h +10 -0
  17. data/ext/pg_query/pg_query_outfuncs_json.c +297 -0
  18. data/ext/pg_query/pg_query_outfuncs_protobuf.c +237 -0
  19. data/ext/pg_query/pg_query_parse.c +148 -0
  20. data/ext/pg_query/pg_query_parse_plpgsql.c +460 -0
  21. data/ext/pg_query/pg_query_readfuncs.h +11 -0
  22. data/ext/pg_query/pg_query_readfuncs_protobuf.c +142 -0
  23. data/ext/pg_query/pg_query_ruby.c +108 -12
  24. data/ext/pg_query/pg_query_scan.c +173 -0
  25. data/ext/pg_query/pg_query_split.c +221 -0
  26. data/ext/pg_query/protobuf-c.c +3660 -0
  27. data/ext/pg_query/src_backend_catalog_namespace.c +1051 -0
  28. data/ext/pg_query/src_backend_catalog_pg_proc.c +142 -0
  29. data/ext/pg_query/src_backend_commands_define.c +117 -0
  30. data/ext/pg_query/src_backend_libpq_pqcomm.c +651 -0
  31. data/ext/pg_query/src_backend_nodes_bitmapset.c +513 -0
  32. data/ext/pg_query/src_backend_nodes_copyfuncs.c +6013 -0
  33. data/ext/pg_query/src_backend_nodes_equalfuncs.c +4003 -0
  34. data/ext/pg_query/src_backend_nodes_extensible.c +99 -0
  35. data/ext/pg_query/src_backend_nodes_list.c +922 -0
  36. data/ext/pg_query/src_backend_nodes_makefuncs.c +417 -0
  37. data/ext/pg_query/src_backend_nodes_nodeFuncs.c +1363 -0
  38. data/ext/pg_query/src_backend_nodes_value.c +84 -0
  39. data/ext/pg_query/src_backend_parser_gram.c +47456 -0
  40. data/ext/pg_query/src_backend_parser_parse_expr.c +313 -0
  41. data/ext/pg_query/src_backend_parser_parser.c +497 -0
  42. data/ext/pg_query/src_backend_parser_scan.c +7091 -0
  43. data/ext/pg_query/src_backend_parser_scansup.c +160 -0
  44. data/ext/pg_query/src_backend_postmaster_postmaster.c +2230 -0
  45. data/ext/pg_query/src_backend_storage_ipc_ipc.c +192 -0
  46. data/ext/pg_query/src_backend_storage_lmgr_s_lock.c +370 -0
  47. data/ext/pg_query/src_backend_tcop_postgres.c +776 -0
  48. data/ext/pg_query/src_backend_utils_adt_datum.c +326 -0
  49. data/ext/pg_query/src_backend_utils_adt_expandeddatum.c +98 -0
  50. data/ext/pg_query/src_backend_utils_adt_format_type.c +136 -0
  51. data/ext/pg_query/src_backend_utils_adt_ruleutils.c +1683 -0
  52. data/ext/pg_query/src_backend_utils_error_assert.c +74 -0
  53. data/ext/pg_query/src_backend_utils_error_elog.c +1748 -0
  54. data/ext/pg_query/src_backend_utils_fmgr_fmgr.c +570 -0
  55. data/ext/pg_query/src_backend_utils_hash_dynahash.c +1086 -0
  56. data/ext/pg_query/src_backend_utils_init_globals.c +168 -0
  57. data/ext/pg_query/src_backend_utils_mb_mbutils.c +839 -0
  58. data/ext/pg_query/src_backend_utils_misc_guc.c +1831 -0
  59. data/ext/pg_query/src_backend_utils_mmgr_aset.c +1560 -0
  60. data/ext/pg_query/src_backend_utils_mmgr_mcxt.c +1006 -0
  61. data/ext/pg_query/src_common_encnames.c +158 -0
  62. data/ext/pg_query/src_common_keywords.c +39 -0
  63. data/ext/pg_query/src_common_kwlist_d.h +1081 -0
  64. data/ext/pg_query/src_common_kwlookup.c +91 -0
  65. data/ext/pg_query/src_common_psprintf.c +158 -0
  66. data/ext/pg_query/src_common_string.c +86 -0
  67. data/ext/pg_query/src_common_stringinfo.c +336 -0
  68. data/ext/pg_query/src_common_wchar.c +1651 -0
  69. data/ext/pg_query/src_pl_plpgsql_src_pl_comp.c +1133 -0
  70. data/ext/pg_query/src_pl_plpgsql_src_pl_funcs.c +877 -0
  71. data/ext/pg_query/src_pl_plpgsql_src_pl_gram.c +6533 -0
  72. data/ext/pg_query/src_pl_plpgsql_src_pl_handler.c +107 -0
  73. data/ext/pg_query/src_pl_plpgsql_src_pl_reserved_kwlist_d.h +123 -0
  74. data/ext/pg_query/src_pl_plpgsql_src_pl_scanner.c +671 -0
  75. data/ext/pg_query/src_pl_plpgsql_src_pl_unreserved_kwlist_d.h +255 -0
  76. data/ext/pg_query/src_port_erand48.c +127 -0
  77. data/ext/pg_query/src_port_pg_bitutils.c +246 -0
  78. data/ext/pg_query/src_port_pgsleep.c +69 -0
  79. data/ext/pg_query/src_port_pgstrcasecmp.c +83 -0
  80. data/ext/pg_query/src_port_qsort.c +240 -0
  81. data/ext/pg_query/src_port_random.c +31 -0
  82. data/ext/pg_query/src_port_snprintf.c +1449 -0
  83. data/ext/pg_query/src_port_strerror.c +324 -0
  84. data/ext/pg_query/src_port_strnlen.c +39 -0
  85. data/ext/pg_query/xxhash.c +43 -0
  86. data/lib/pg_query.rb +7 -4
  87. data/lib/pg_query/constants.rb +21 -0
  88. data/lib/pg_query/deparse.rb +15 -1673
  89. data/lib/pg_query/filter_columns.rb +86 -85
  90. data/lib/pg_query/fingerprint.rb +122 -87
  91. data/lib/pg_query/json_field_names.rb +1402 -0
  92. data/lib/pg_query/node.rb +31 -0
  93. data/lib/pg_query/param_refs.rb +42 -37
  94. data/lib/pg_query/parse.rb +220 -203
  95. data/lib/pg_query/parse_error.rb +1 -1
  96. data/lib/pg_query/pg_query_pb.rb +3211 -0
  97. data/lib/pg_query/scan.rb +23 -0
  98. data/lib/pg_query/treewalker.rb +24 -40
  99. data/lib/pg_query/truncate.rb +64 -43
  100. data/lib/pg_query/version.rb +2 -2
  101. metadata +101 -11
  102. data/ext/pg_query/pg_query_ruby.h +0 -10
  103. data/lib/pg_query/deep_dup.rb +0 -16
  104. data/lib/pg_query/deparse/alter_table.rb +0 -42
  105. data/lib/pg_query/deparse/interval.rb +0 -105
  106. data/lib/pg_query/deparse/keywords.rb +0 -159
  107. data/lib/pg_query/deparse/rename.rb +0 -41
  108. data/lib/pg_query/legacy_parsetree.rb +0 -109
  109. data/lib/pg_query/node_types.rb +0 -297
@@ -0,0 +1,192 @@
1
+ /*--------------------------------------------------------------------
2
+ * Symbols referenced in this file:
3
+ * - proc_exit_inprogress
4
+ * - proc_exit
5
+ *--------------------------------------------------------------------
6
+ */
7
+
8
+ /*-------------------------------------------------------------------------
9
+ *
10
+ * ipc.c
11
+ * POSTGRES inter-process communication definitions.
12
+ *
13
+ * This file is misnamed, as it no longer has much of anything directly
14
+ * to do with IPC. The functionality here is concerned with managing
15
+ * exit-time cleanup for either a postmaster or a backend.
16
+ *
17
+ *
18
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
19
+ * Portions Copyright (c) 1994, Regents of the University of California
20
+ *
21
+ *
22
+ * IDENTIFICATION
23
+ * src/backend/storage/ipc/ipc.c
24
+ *
25
+ *-------------------------------------------------------------------------
26
+ */
27
+ #include "postgres.h"
28
+
29
+ #include <signal.h>
30
+ #include <unistd.h>
31
+ #include <sys/stat.h>
32
+
33
+ #include "miscadmin.h"
34
+ #ifdef PROFILE_PID_DIR
35
+ #include "postmaster/autovacuum.h"
36
+ #endif
37
+ #include "storage/dsm.h"
38
+ #include "storage/ipc.h"
39
+ #include "tcop/tcopprot.h"
40
+
41
+
42
+ /*
43
+ * This flag is set during proc_exit() to change ereport()'s behavior,
44
+ * so that an ereport() from an on_proc_exit routine cannot get us out
45
+ * of the exit procedure. We do NOT want to go back to the idle loop...
46
+ */
47
+ __thread bool proc_exit_inprogress = false;
48
+
49
+
50
+ /*
51
+ * Set when shmem_exit() is in progress.
52
+ */
53
+
54
+
55
+ /*
56
+ * This flag tracks whether we've called atexit() in the current process
57
+ * (or in the parent postmaster).
58
+ */
59
+
60
+
61
+ /* local functions */
62
+ static void proc_exit_prepare(int code);
63
+
64
+
65
+ /* ----------------------------------------------------------------
66
+ * exit() handling stuff
67
+ *
68
+ * These functions are in generally the same spirit as atexit(),
69
+ * but provide some additional features we need --- in particular,
70
+ * we want to register callbacks to invoke when we are disconnecting
71
+ * from a broken shared-memory context but not exiting the postmaster.
72
+ *
73
+ * Callback functions can take zero, one, or two args: the first passed
74
+ * arg is the integer exitcode, the second is the Datum supplied when
75
+ * the callback was registered.
76
+ * ----------------------------------------------------------------
77
+ */
78
+
79
+ #define MAX_ON_EXITS 20
80
+
81
+ struct ONEXIT
82
+ {
83
+ pg_on_exit_callback function;
84
+ Datum arg;
85
+ };
86
+
87
+
88
+
89
+
90
+
91
+
92
+
93
+
94
+
95
+
96
+ /* ----------------------------------------------------------------
97
+ * proc_exit
98
+ *
99
+ * this function calls all the callbacks registered
100
+ * for it (to free resources) and then calls exit.
101
+ *
102
+ * This should be the only function to call exit().
103
+ * -cim 2/6/90
104
+ *
105
+ * Unfortunately, we can't really guarantee that add-on code
106
+ * obeys the rule of not calling exit() directly. So, while
107
+ * this is the preferred way out of the system, we also register
108
+ * an atexit callback that will make sure cleanup happens.
109
+ * ----------------------------------------------------------------
110
+ */
111
+ void proc_exit(int code) { printf("Terminating process due to FATAL error\n"); exit(1); }
112
+
113
+
114
+ /*
115
+ * Code shared between proc_exit and the atexit handler. Note that in
116
+ * normal exit through proc_exit, this will actually be called twice ...
117
+ * but the second call will have nothing to do.
118
+ */
119
+
120
+
121
+ /* ------------------
122
+ * Run all of the on_shmem_exit routines --- but don't actually exit.
123
+ * This is used by the postmaster to re-initialize shared memory and
124
+ * semaphores after a backend dies horribly. As with proc_exit(), we
125
+ * remove each callback from the list before calling it, to avoid
126
+ * infinite loop in case of error.
127
+ * ------------------
128
+ */
129
+
130
+
131
+ /* ----------------------------------------------------------------
132
+ * atexit_callback
133
+ *
134
+ * Backstop to ensure that direct calls of exit() don't mess us up.
135
+ *
136
+ * Somebody who was being really uncooperative could call _exit(),
137
+ * but for that case we have a "dead man switch" that will make the
138
+ * postmaster treat it as a crash --- see pmsignal.c.
139
+ * ----------------------------------------------------------------
140
+ */
141
+
142
+
143
+ /* ----------------------------------------------------------------
144
+ * on_proc_exit
145
+ *
146
+ * this function adds a callback function to the list of
147
+ * functions invoked by proc_exit(). -cim 2/6/90
148
+ * ----------------------------------------------------------------
149
+ */
150
+
151
+
152
+ /* ----------------------------------------------------------------
153
+ * before_shmem_exit
154
+ *
155
+ * Register early callback to perform user-level cleanup,
156
+ * e.g. transaction abort, before we begin shutting down
157
+ * low-level subsystems.
158
+ * ----------------------------------------------------------------
159
+ */
160
+
161
+
162
+ /* ----------------------------------------------------------------
163
+ * on_shmem_exit
164
+ *
165
+ * Register ordinary callback to perform low-level shutdown
166
+ * (e.g. releasing our PGPROC); run after before_shmem_exit
167
+ * callbacks and before on_proc_exit callbacks.
168
+ * ----------------------------------------------------------------
169
+ */
170
+
171
+
172
+ /* ----------------------------------------------------------------
173
+ * cancel_before_shmem_exit
174
+ *
175
+ * this function removes a previously-registered before_shmem_exit
176
+ * callback. For simplicity, only the latest entry can be
177
+ * removed. (We could work harder but there is no need for
178
+ * current uses.)
179
+ * ----------------------------------------------------------------
180
+ */
181
+
182
+
183
+ /* ----------------------------------------------------------------
184
+ * on_exit_reset
185
+ *
186
+ * this function clears all on_proc_exit() and on_shmem_exit()
187
+ * registered functions. This is used just after forking a backend,
188
+ * so that the backend doesn't believe it should call the postmaster's
189
+ * on-exit routines when it exits...
190
+ * ----------------------------------------------------------------
191
+ */
192
+
@@ -0,0 +1,370 @@
1
+ /*--------------------------------------------------------------------
2
+ * Symbols referenced in this file:
3
+ * - s_lock
4
+ * - perform_spin_delay
5
+ * - spins_per_delay
6
+ * - s_lock_stuck
7
+ * - finish_spin_delay
8
+ *--------------------------------------------------------------------
9
+ */
10
+
11
+ /*-------------------------------------------------------------------------
12
+ *
13
+ * s_lock.c
14
+ * Hardware-dependent implementation of spinlocks.
15
+ *
16
+ * When waiting for a contended spinlock we loop tightly for awhile, then
17
+ * delay using pg_usleep() and try again. Preferably, "awhile" should be a
18
+ * small multiple of the maximum time we expect a spinlock to be held. 100
19
+ * iterations seems about right as an initial guess. However, on a
20
+ * uniprocessor the loop is a waste of cycles, while in a multi-CPU scenario
21
+ * it's usually better to spin a bit longer than to call the kernel, so we try
22
+ * to adapt the spin loop count depending on whether we seem to be in a
23
+ * uniprocessor or multiprocessor.
24
+ *
25
+ * Note: you might think MIN_SPINS_PER_DELAY should be just 1, but you'd
26
+ * be wrong; there are platforms where that can result in a "stuck
27
+ * spinlock" failure. This has been seen particularly on Alphas; it seems
28
+ * that the first TAS after returning from kernel space will always fail
29
+ * on that hardware.
30
+ *
31
+ * Once we do decide to block, we use randomly increasing pg_usleep()
32
+ * delays. The first delay is 1 msec, then the delay randomly increases to
33
+ * about one second, after which we reset to 1 msec and start again. The
34
+ * idea here is that in the presence of heavy contention we need to
35
+ * increase the delay, else the spinlock holder may never get to run and
36
+ * release the lock. (Consider situation where spinlock holder has been
37
+ * nice'd down in priority by the scheduler --- it will not get scheduled
38
+ * until all would-be acquirers are sleeping, so if we always use a 1-msec
39
+ * sleep, there is a real possibility of starvation.) But we can't just
40
+ * clamp the delay to an upper bound, else it would take a long time to
41
+ * make a reasonable number of tries.
42
+ *
43
+ * We time out and declare error after NUM_DELAYS delays (thus, exactly
44
+ * that many tries). With the given settings, this will usually take 2 or
45
+ * so minutes. It seems better to fix the total number of tries (and thus
46
+ * the probability of unintended failure) than to fix the total time
47
+ * spent.
48
+ *
49
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
50
+ * Portions Copyright (c) 1994, Regents of the University of California
51
+ *
52
+ *
53
+ * IDENTIFICATION
54
+ * src/backend/storage/lmgr/s_lock.c
55
+ *
56
+ *-------------------------------------------------------------------------
57
+ */
58
+ #include "postgres.h"
59
+
60
+ #include <time.h>
61
+ #include <unistd.h>
62
+
63
+ #include "port/atomics.h"
64
+ #include "storage/s_lock.h"
65
+
66
+ #define MIN_SPINS_PER_DELAY 10
67
+ #define MAX_SPINS_PER_DELAY 1000
68
+ #define NUM_DELAYS 1000
69
+ #define MIN_DELAY_USEC 1000L
70
+ #define MAX_DELAY_USEC 1000000L
71
+
72
+
73
+
74
+
75
+ static __thread int spins_per_delay = DEFAULT_SPINS_PER_DELAY;
76
+
77
+
78
+
79
+ /*
80
+ * s_lock_stuck() - complain about a stuck spinlock
81
+ */
82
+ static void
83
+ s_lock_stuck(const char *file, int line, const char *func)
84
+ {
85
+ if (!func)
86
+ func = "(unknown)";
87
+ #if defined(S_LOCK_TEST)
88
+ fprintf(stderr,
89
+ "\nStuck spinlock detected at %s, %s:%d.\n",
90
+ func, file, line);
91
+ exit(1);
92
+ #else
93
+ elog(PANIC, "stuck spinlock detected at %s, %s:%d",
94
+ func, file, line);
95
+ #endif
96
+ }
97
+
98
+ /*
99
+ * s_lock(lock) - platform-independent portion of waiting for a spinlock.
100
+ */
101
+ int
102
+ s_lock(volatile slock_t *lock, const char *file, int line, const char *func)
103
+ {
104
+ SpinDelayStatus delayStatus;
105
+
106
+ init_spin_delay(&delayStatus, file, line, func);
107
+
108
+ while (TAS_SPIN(lock))
109
+ {
110
+ perform_spin_delay(&delayStatus);
111
+ }
112
+
113
+ finish_spin_delay(&delayStatus);
114
+
115
+ return delayStatus.delays;
116
+ }
117
+
118
+ #ifdef USE_DEFAULT_S_UNLOCK
119
+ void
120
+ s_unlock(volatile slock_t *lock)
121
+ {
122
+ #ifdef TAS_ACTIVE_WORD
123
+ /* HP's PA-RISC */
124
+ *TAS_ACTIVE_WORD(lock) = -1;
125
+ #else
126
+ *lock = 0;
127
+ #endif
128
+ }
129
+ #endif
130
+
131
+ /*
132
+ * Wait while spinning on a contended spinlock.
133
+ */
134
+ void
135
+ perform_spin_delay(SpinDelayStatus *status)
136
+ {
137
+ /* CPU-specific delay each time through the loop */
138
+ SPIN_DELAY();
139
+
140
+ /* Block the process every spins_per_delay tries */
141
+ if (++(status->spins) >= spins_per_delay)
142
+ {
143
+ if (++(status->delays) > NUM_DELAYS)
144
+ s_lock_stuck(status->file, status->line, status->func);
145
+
146
+ if (status->cur_delay == 0) /* first time to delay? */
147
+ status->cur_delay = MIN_DELAY_USEC;
148
+
149
+ pg_usleep(status->cur_delay);
150
+
151
+ #if defined(S_LOCK_TEST)
152
+ fprintf(stdout, "*");
153
+ fflush(stdout);
154
+ #endif
155
+
156
+ /* increase delay by a random fraction between 1X and 2X */
157
+ status->cur_delay += (int) (status->cur_delay *
158
+ ((double) random() / (double) MAX_RANDOM_VALUE) + 0.5);
159
+ /* wrap back to minimum delay when max is exceeded */
160
+ if (status->cur_delay > MAX_DELAY_USEC)
161
+ status->cur_delay = MIN_DELAY_USEC;
162
+
163
+ status->spins = 0;
164
+ }
165
+ }
166
+
167
+ /*
168
+ * After acquiring a spinlock, update estimates about how long to loop.
169
+ *
170
+ * If we were able to acquire the lock without delaying, it's a good
171
+ * indication we are in a multiprocessor. If we had to delay, it's a sign
172
+ * (but not a sure thing) that we are in a uniprocessor. Hence, we
173
+ * decrement spins_per_delay slowly when we had to delay, and increase it
174
+ * rapidly when we didn't. It's expected that spins_per_delay will
175
+ * converge to the minimum value on a uniprocessor and to the maximum
176
+ * value on a multiprocessor.
177
+ *
178
+ * Note: spins_per_delay is local within our current process. We want to
179
+ * average these observations across multiple backends, since it's
180
+ * relatively rare for this function to even get entered, and so a single
181
+ * backend might not live long enough to converge on a good value. That
182
+ * is handled by the two routines below.
183
+ */
184
+ void
185
+ finish_spin_delay(SpinDelayStatus *status)
186
+ {
187
+ if (status->cur_delay == 0)
188
+ {
189
+ /* we never had to delay */
190
+ if (spins_per_delay < MAX_SPINS_PER_DELAY)
191
+ spins_per_delay = Min(spins_per_delay + 100, MAX_SPINS_PER_DELAY);
192
+ }
193
+ else
194
+ {
195
+ if (spins_per_delay > MIN_SPINS_PER_DELAY)
196
+ spins_per_delay = Max(spins_per_delay - 1, MIN_SPINS_PER_DELAY);
197
+ }
198
+ }
199
+
200
+ /*
201
+ * Set local copy of spins_per_delay during backend startup.
202
+ *
203
+ * NB: this has to be pretty fast as it is called while holding a spinlock
204
+ */
205
+
206
+
207
+ /*
208
+ * Update shared estimate of spins_per_delay during backend exit.
209
+ *
210
+ * NB: this has to be pretty fast as it is called while holding a spinlock
211
+ */
212
+
213
+
214
+
215
+ /*
216
+ * Various TAS implementations that cannot live in s_lock.h as no inline
217
+ * definition exists (yet).
218
+ * In the future, get rid of tas.[cso] and fold it into this file.
219
+ *
220
+ * If you change something here, you will likely need to modify s_lock.h too,
221
+ * because the definitions for these are split between this file and s_lock.h.
222
+ */
223
+
224
+
225
+ #ifdef HAVE_SPINLOCKS /* skip spinlocks if requested */
226
+
227
+
228
+ #if defined(__GNUC__)
229
+
230
+ /*
231
+ * All the gcc flavors that are not inlined
232
+ */
233
+
234
+
235
+ /*
236
+ * Note: all the if-tests here probably ought to be testing gcc version
237
+ * rather than platform, but I don't have adequate info to know what to
238
+ * write. Ideally we'd flush all this in favor of the inline version.
239
+ */
240
+ #if defined(__m68k__) && !defined(__linux__)
241
+ /* really means: extern int tas(slock_t* **lock); */
242
+ static void
243
+ tas_dummy()
244
+ {
245
+ __asm__ __volatile__(
246
+ #if (defined(__NetBSD__) || defined(__OpenBSD__)) && defined(__ELF__)
247
+ /* no underscore for label and % for registers */
248
+ "\
249
+ .global tas \n\
250
+ tas: \n\
251
+ movel %sp@(0x4),%a0 \n\
252
+ tas %a0@ \n\
253
+ beq _success \n\
254
+ moveq #-128,%d0 \n\
255
+ rts \n\
256
+ _success: \n\
257
+ moveq #0,%d0 \n\
258
+ rts \n"
259
+ #else
260
+ "\
261
+ .global _tas \n\
262
+ _tas: \n\
263
+ movel sp@(0x4),a0 \n\
264
+ tas a0@ \n\
265
+ beq _success \n\
266
+ moveq #-128,d0 \n\
267
+ rts \n\
268
+ _success: \n\
269
+ moveq #0,d0 \n\
270
+ rts \n"
271
+ #endif /* (__NetBSD__ || __OpenBSD__) && __ELF__ */
272
+ );
273
+ }
274
+ #endif /* __m68k__ && !__linux__ */
275
+ #endif /* not __GNUC__ */
276
+ #endif /* HAVE_SPINLOCKS */
277
+
278
+
279
+
280
+ /*****************************************************************************/
281
+ #if defined(S_LOCK_TEST)
282
+
283
+ /*
284
+ * test program for verifying a port's spinlock support.
285
+ */
286
+
287
+ struct test_lock_struct
288
+ {
289
+ char pad1;
290
+ slock_t lock;
291
+ char pad2;
292
+ };
293
+
294
+ volatile struct test_lock_struct test_lock;
295
+
296
+ int
297
+ main()
298
+ {
299
+ srandom((unsigned int) time(NULL));
300
+
301
+ test_lock.pad1 = test_lock.pad2 = 0x44;
302
+
303
+ S_INIT_LOCK(&test_lock.lock);
304
+
305
+ if (test_lock.pad1 != 0x44 || test_lock.pad2 != 0x44)
306
+ {
307
+ printf("S_LOCK_TEST: failed, declared datatype is wrong size\n");
308
+ return 1;
309
+ }
310
+
311
+ if (!S_LOCK_FREE(&test_lock.lock))
312
+ {
313
+ printf("S_LOCK_TEST: failed, lock not initialized\n");
314
+ return 1;
315
+ }
316
+
317
+ S_LOCK(&test_lock.lock);
318
+
319
+ if (test_lock.pad1 != 0x44 || test_lock.pad2 != 0x44)
320
+ {
321
+ printf("S_LOCK_TEST: failed, declared datatype is wrong size\n");
322
+ return 1;
323
+ }
324
+
325
+ if (S_LOCK_FREE(&test_lock.lock))
326
+ {
327
+ printf("S_LOCK_TEST: failed, lock not locked\n");
328
+ return 1;
329
+ }
330
+
331
+ S_UNLOCK(&test_lock.lock);
332
+
333
+ if (test_lock.pad1 != 0x44 || test_lock.pad2 != 0x44)
334
+ {
335
+ printf("S_LOCK_TEST: failed, declared datatype is wrong size\n");
336
+ return 1;
337
+ }
338
+
339
+ if (!S_LOCK_FREE(&test_lock.lock))
340
+ {
341
+ printf("S_LOCK_TEST: failed, lock not unlocked\n");
342
+ return 1;
343
+ }
344
+
345
+ S_LOCK(&test_lock.lock);
346
+
347
+ if (test_lock.pad1 != 0x44 || test_lock.pad2 != 0x44)
348
+ {
349
+ printf("S_LOCK_TEST: failed, declared datatype is wrong size\n");
350
+ return 1;
351
+ }
352
+
353
+ if (S_LOCK_FREE(&test_lock.lock))
354
+ {
355
+ printf("S_LOCK_TEST: failed, lock not re-locked\n");
356
+ return 1;
357
+ }
358
+
359
+ printf("S_LOCK_TEST: this will print %d stars and then\n", NUM_DELAYS);
360
+ printf(" exit with a 'stuck spinlock' message\n");
361
+ printf(" if S_LOCK() and TAS() are working.\n");
362
+ fflush(stdout);
363
+
364
+ s_lock(&test_lock.lock, __FILE__, __LINE__);
365
+
366
+ printf("S_LOCK_TEST: failed, lock not locked\n");
367
+ return 1;
368
+ }
369
+
370
+ #endif /* S_LOCK_TEST */