1 /*- 2 * Copyright (c) 1996, 2020 Oracle and/or its affiliates. All rights reserved. 3 * 4 * See the file LICENSE for license information. 5 */ 6 /* 7 * Copyright (c) 1991, 1993 8 * The Regents of the University of California. All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * @(#)queue.h 8.5 (Berkeley) 8/20/94 39 * $FreeBSD: src/sys/sys/queue.h,v 1.54 2002/08/05 05:18:43 alfred Exp $ 40 */ 41 42 #ifndef _DB_QUEUE_H_ 43 #define _DB_QUEUE_H_ 44 45 #if defined(__cplusplus) 46 extern "C" { 47 #endif 48 49 /* 50 * This file defines four types of data structures: singly-linked lists, 51 * singly-linked tail queues, lists and tail queues. 52 * 53 * A singly-linked list is headed by a single forward pointer. The elements 54 * are singly linked for minimum space and pointer manipulation overhead at 55 * the expense of O(n) removal for arbitrary elements. New elements can be 56 * added to the list after an existing element or at the head of the list. 57 * Elements being removed from the head of the list should use the explicit 58 * macro for this purpose for optimum efficiency. A singly-linked list may 59 * only be traversed in the forward direction. Singly-linked lists are ideal 60 * for applications with large datasets and few or no removals or for 61 * implementing a LIFO queue. 62 * 63 * A singly-linked tail queue is headed by a pair of pointers, one to the 64 * head of the list and the other to the tail of the list. The elements are 65 * singly linked for minimum space and pointer manipulation overhead at the 66 * expense of O(n) removal for arbitrary elements. New elements can be added 67 * to the list after an existing element, at the head of the list, or at the 68 * end of the list. Elements being removed from the head of the tail queue 69 * should use the explicit macro for this purpose for optimum efficiency. 70 * A singly-linked tail queue may only be traversed in the forward direction. 71 * Singly-linked tail queues are ideal for applications with large datasets 72 * and few or no removals or for implementing a FIFO queue. 73 * 74 * A list is headed by a single forward pointer (or an array of forward 75 * pointers for a hash table header). The elements are doubly linked 76 * so that an arbitrary element can be removed without a need to 77 * traverse the list. New elements can be added to the list before 78 * or after an existing element or at the head of the list. A list 79 * may only be traversed in the forward direction. 80 * 81 * A tail queue is headed by a pair of pointers, one to the head of the 82 * list and the other to the tail of the list. The elements are doubly 83 * linked so that an arbitrary element can be removed without a need to 84 * traverse the list. New elements can be added to the list before or 85 * after an existing element, at the head of the list, or at the end of 86 * the list. A tail queue may be traversed in either direction. 87 * 88 * For details on the use of these macros, see the queue(3) manual page. 89 * 90 * 91 * SLIST LIST STAILQ TAILQ 92 * _HEAD + + + + 93 * _HEAD_INITIALIZER + + + + 94 * _ENTRY + + + + 95 * _INIT + + + + 96 * _EMPTY + + + + 97 * _FIRST + + + + 98 * _NEXT + + + + 99 * _PREV - - - + 100 * _LAST - - + + 101 * _FOREACH + + + + 102 * _FOREACH_REVERSE - - - + 103 * _INSERT_HEAD + + + + 104 * _INSERT_BEFORE - + - + 105 * _INSERT_AFTER + + + + 106 * _INSERT_TAIL - - + + 107 * _CONCAT - - + + 108 * _REMOVE_HEAD + - + - 109 * _REMOVE + + + + 110 * 111 */ 112 113 /* 114 * !!! 115 * We #undef all of the macros because there are incompatible versions of this 116 * file and these macros on various systems. What makes the problem worse is 117 * they are included and/or defined by system include files which we may have 118 * already loaded into Berkeley DB before getting here. For example, FreeBSD's 119 * <rpc/rpc.h> includes its system <sys/queue.h>, and VxWorks UnixLib.h defines 120 * several of the LIST_XXX macros. Visual C.NET 7.0 also defines some of these 121 * same macros in Vc7\PlatformSDK\Include\WinNT.h. Make sure we use ours. 122 */ 123 #undef LIST_EMPTY 124 #undef LIST_ENTRY 125 #undef LIST_FIRST 126 #undef LIST_FOREACH 127 #undef LIST_HEAD 128 #undef LIST_HEAD_INITIALIZER 129 #undef LIST_INIT 130 #undef LIST_INSERT_AFTER 131 #undef LIST_INSERT_BEFORE 132 #undef LIST_INSERT_HEAD 133 #undef LIST_NEXT 134 #undef LIST_REMOVE 135 #undef QMD_TRACE_ELEM 136 #undef QMD_TRACE_HEAD 137 #undef QUEUE_MACRO_DEBUG 138 #undef SLIST_EMPTY 139 #undef SLIST_ENTRY 140 #undef SLIST_FIRST 141 #undef SLIST_FOREACH 142 #undef SLIST_FOREACH_PREVPTR 143 #undef SLIST_HEAD 144 #undef SLIST_HEAD_INITIALIZER 145 #undef SLIST_INIT 146 #undef SLIST_INSERT_AFTER 147 #undef SLIST_INSERT_HEAD 148 #undef SLIST_NEXT 149 #undef SLIST_REMOVE 150 #undef SLIST_REMOVE_HEAD 151 #undef STAILQ_CONCAT 152 #undef STAILQ_EMPTY 153 #undef STAILQ_ENTRY 154 #undef STAILQ_FIRST 155 #undef STAILQ_FOREACH 156 #undef STAILQ_HEAD 157 #undef STAILQ_HEAD_INITIALIZER 158 #undef STAILQ_INIT 159 #undef STAILQ_INSERT_AFTER 160 #undef STAILQ_INSERT_HEAD 161 #undef STAILQ_INSERT_TAIL 162 #undef STAILQ_LAST 163 #undef STAILQ_NEXT 164 #undef STAILQ_REMOVE 165 #undef STAILQ_REMOVE_HEAD 166 #undef STAILQ_REMOVE_HEAD_UNTIL 167 #undef TAILQ_CONCAT 168 #undef TAILQ_EMPTY 169 #undef TAILQ_ENTRY 170 #undef TAILQ_FIRST 171 #undef TAILQ_FOREACH 172 #undef TAILQ_FOREACH_REVERSE 173 #undef TAILQ_HEAD 174 #undef TAILQ_HEAD_INITIALIZER 175 #undef TAILQ_INIT 176 #undef TAILQ_INSERT_AFTER 177 #undef TAILQ_INSERT_BEFORE 178 #undef TAILQ_INSERT_HEAD 179 #undef TAILQ_INSERT_TAIL 180 #undef TAILQ_LAST 181 #undef TAILQ_NEXT 182 #undef TAILQ_PREV 183 #undef TAILQ_REMOVE 184 #undef TRACEBUF 185 #undef TRASHIT 186 187 #define QUEUE_MACRO_DEBUG 0 188 #if QUEUE_MACRO_DEBUG 189 /* Store the last 2 places the queue element or head was altered */ 190 struct qm_trace { 191 char * lastfile; 192 int lastline; 193 char * prevfile; 194 int prevline; 195 }; 196 197 #define TRACEBUF struct qm_trace trace; 198 #define TRASHIT(x) do {(x) = (void *)-1;} while (0) 199 200 #define QMD_TRACE_HEAD(head) do { \ 201 (head)->trace.prevline = (head)->trace.lastline; \ 202 (head)->trace.prevfile = (head)->trace.lastfile; \ 203 (head)->trace.lastline = __LINE__; \ 204 (head)->trace.lastfile = __FILE__; \ 205 } while (0) 206 207 #define QMD_TRACE_ELEM(elem) do { \ 208 (elem)->trace.prevline = (elem)->trace.lastline; \ 209 (elem)->trace.prevfile = (elem)->trace.lastfile; \ 210 (elem)->trace.lastline = __LINE__; \ 211 (elem)->trace.lastfile = __FILE__; \ 212 } while (0) 213 214 #else 215 #define QMD_TRACE_ELEM(elem) 216 #define QMD_TRACE_HEAD(head) 217 #define TRACEBUF 218 #define TRASHIT(x) 219 #endif /* QUEUE_MACRO_DEBUG */ 220 221 /* 222 * Singly-linked List declarations. 223 */ 224 #define SLIST_HEAD(name, type) \ 225 struct name { \ 226 struct type *slh_first; /* first element */ \ 227 } 228 229 #define SLIST_HEAD_INITIALIZER(head) \ 230 { NULL } 231 232 #define SLIST_ENTRY(type) \ 233 struct { \ 234 struct type *sle_next; /* next element */ \ 235 } 236 237 /* 238 * Singly-linked List functions. 239 */ 240 #define SLIST_EMPTY(head) ((head)->slh_first == NULL) 241 242 #define SLIST_FIRST(head) ((head)->slh_first) 243 244 #define SLIST_FOREACH(var, head, field) \ 245 for ((var) = SLIST_FIRST((head)); \ 246 (var); \ 247 (var) = SLIST_NEXT((var), field)) 248 249 #define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ 250 for ((varp) = &SLIST_FIRST((head)); \ 251 ((var) = *(varp)) != NULL; \ 252 (varp) = &SLIST_NEXT((var), field)) 253 254 #define SLIST_INIT(head) do { \ 255 SLIST_FIRST((head)) = NULL; \ 256 } while (0) 257 258 #define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ 259 SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ 260 SLIST_NEXT((slistelm), field) = (elm); \ 261 } while (0) 262 263 #define SLIST_INSERT_HEAD(head, elm, field) do { \ 264 SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ 265 SLIST_FIRST((head)) = (elm); \ 266 } while (0) 267 268 #define SLIST_NEXT(elm, field) ((elm)->field.sle_next) 269 270 #define SLIST_REMOVE(head, elm, type, field) do { \ 271 if (SLIST_FIRST((head)) == (elm)) { \ 272 SLIST_REMOVE_HEAD((head), field); \ 273 } \ 274 else { \ 275 struct type *curelm = SLIST_FIRST((head)); \ 276 while (curelm != NULL && \ 277 SLIST_NEXT(curelm, field) != (elm)) \ 278 curelm = SLIST_NEXT(curelm, field); \ 279 if (curelm != NULL) \ 280 SLIST_NEXT(curelm, field) = \ 281 SLIST_NEXT(SLIST_NEXT(curelm, field), field);\ 282 } \ 283 } while (0) 284 285 #define SLIST_REMOVE_HEAD(head, field) do { \ 286 SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ 287 } while (0) 288 289 /* 290 * Singly-linked Tail queue declarations. 291 */ 292 #define STAILQ_HEAD(name, type) \ 293 struct name { \ 294 struct type *stqh_first;/* first element */ \ 295 struct type **stqh_last;/* addr of last next element */ \ 296 } 297 298 #define STAILQ_HEAD_INITIALIZER(head) \ 299 { NULL, &(head).stqh_first } 300 301 #define STAILQ_ENTRY(type) \ 302 struct { \ 303 struct type *stqe_next; /* next element */ \ 304 } 305 306 /* 307 * Singly-linked Tail queue functions. 308 */ 309 #define STAILQ_CONCAT(head1, head2) do { \ 310 if (!STAILQ_EMPTY((head2))) { \ 311 *(head1)->stqh_last = (head2)->stqh_first; \ 312 (head1)->stqh_last = (head2)->stqh_last; \ 313 STAILQ_INIT((head2)); \ 314 } \ 315 } while (0) 316 317 #define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) 318 319 #define STAILQ_FIRST(head) ((head)->stqh_first) 320 321 #define STAILQ_FOREACH(var, head, field) \ 322 for ((var) = STAILQ_FIRST((head)); \ 323 (var); \ 324 (var) = STAILQ_NEXT((var), field)) 325 326 #define STAILQ_INIT(head) do { \ 327 STAILQ_FIRST((head)) = NULL; \ 328 (head)->stqh_last = &STAILQ_FIRST((head)); \ 329 } while (0) 330 331 #define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ 332 if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ 333 (head)->stqh_last = &STAILQ_NEXT((elm), field); \ 334 STAILQ_NEXT((tqelm), field) = (elm); \ 335 } while (0) 336 337 #define STAILQ_INSERT_HEAD(head, elm, field) do { \ 338 if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ 339 (head)->stqh_last = &STAILQ_NEXT((elm), field); \ 340 STAILQ_FIRST((head)) = (elm); \ 341 } while (0) 342 343 #define STAILQ_INSERT_TAIL(head, elm, field) do { \ 344 STAILQ_NEXT((elm), field) = NULL; \ 345 *(head)->stqh_last = (elm); \ 346 (head)->stqh_last = &STAILQ_NEXT((elm), field); \ 347 } while (0) 348 349 #define STAILQ_LAST(head, type, field) \ 350 (STAILQ_EMPTY((head)) ? \ 351 NULL : \ 352 ((struct type *) \ 353 ((char *)((head)->stqh_last) - __offsetof(struct type, field)))) 354 355 #define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) 356 357 #define STAILQ_REMOVE(head, elm, type, field) do { \ 358 if (STAILQ_FIRST((head)) == (elm)) { \ 359 STAILQ_REMOVE_HEAD((head), field); \ 360 } \ 361 else { \ 362 struct type *curelm = STAILQ_FIRST((head)); \ 363 while (STAILQ_NEXT(curelm, field) != (elm)) \ 364 curelm = STAILQ_NEXT(curelm, field); \ 365 if ((STAILQ_NEXT(curelm, field) = \ 366 STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\ 367 (head)->stqh_last = &STAILQ_NEXT((curelm), field);\ 368 } \ 369 } while (0) 370 371 #define STAILQ_REMOVE_HEAD(head, field) do { \ 372 if ((STAILQ_FIRST((head)) = \ 373 STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ 374 (head)->stqh_last = &STAILQ_FIRST((head)); \ 375 } while (0) 376 377 #define STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do { \ 378 if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL) \ 379 (head)->stqh_last = &STAILQ_FIRST((head)); \ 380 } while (0) 381 382 /* 383 * List declarations. 384 */ 385 #define LIST_HEAD(name, type) \ 386 struct name { \ 387 struct type *lh_first; /* first element */ \ 388 } 389 390 #define LIST_HEAD_INITIALIZER(head) \ 391 { NULL } 392 393 #define LIST_ENTRY(type) \ 394 struct { \ 395 struct type *le_next; /* next element */ \ 396 struct type **le_prev; /* address of previous next element */ \ 397 } 398 399 /* 400 * List functions. 401 */ 402 403 #define LIST_EMPTY(head) ((head)->lh_first == NULL) 404 405 #define LIST_FIRST(head) ((head)->lh_first) 406 407 #define LIST_FOREACH(var, head, field) \ 408 for ((var) = LIST_FIRST((head)); \ 409 (var); \ 410 (var) = LIST_NEXT((var), field)) 411 412 #define LIST_INIT(head) do { \ 413 LIST_FIRST((head)) = NULL; \ 414 } while (0) 415 416 #define LIST_INSERT_AFTER(listelm, elm, field) do { \ 417 if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ 418 LIST_NEXT((listelm), field)->field.le_prev = \ 419 &LIST_NEXT((elm), field); \ 420 LIST_NEXT((listelm), field) = (elm); \ 421 (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ 422 } while (0) 423 424 #define LIST_INSERT_BEFORE(listelm, elm, field) do { \ 425 (elm)->field.le_prev = (listelm)->field.le_prev; \ 426 LIST_NEXT((elm), field) = (listelm); \ 427 *(listelm)->field.le_prev = (elm); \ 428 (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ 429 } while (0) 430 431 #define LIST_INSERT_HEAD(head, elm, field) do { \ 432 if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ 433 LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ 434 LIST_FIRST((head)) = (elm); \ 435 (elm)->field.le_prev = &LIST_FIRST((head)); \ 436 } while (0) 437 438 #define LIST_NEXT(elm, field) ((elm)->field.le_next) 439 440 #define LIST_REMOVE(elm, field) do { \ 441 if (LIST_NEXT((elm), field) != NULL) \ 442 LIST_NEXT((elm), field)->field.le_prev = \ 443 (elm)->field.le_prev; \ 444 *(elm)->field.le_prev = LIST_NEXT((elm), field); \ 445 } while (0) 446 447 /* 448 * Tail queue declarations. 449 */ 450 #define TAILQ_HEAD(name, type) \ 451 struct name { \ 452 struct type *tqh_first; /* first element */ \ 453 struct type **tqh_last; /* addr of last next element */ \ 454 TRACEBUF \ 455 } 456 457 #define TAILQ_HEAD_INITIALIZER(head) \ 458 { NULL, &(head).tqh_first } 459 460 #define TAILQ_ENTRY(type) \ 461 struct { \ 462 struct type *tqe_next; /* next element */ \ 463 struct type **tqe_prev; /* address of previous next element */ \ 464 TRACEBUF \ 465 } 466 467 /* 468 * Tail queue functions. 469 */ 470 #define TAILQ_CONCAT(head1, head2, field) do { \ 471 if (!TAILQ_EMPTY(head2)) { \ 472 *(head1)->tqh_last = (head2)->tqh_first; \ 473 (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ 474 (head1)->tqh_last = (head2)->tqh_last; \ 475 TAILQ_INIT((head2)); \ 476 QMD_TRACE_HEAD(head); \ 477 QMD_TRACE_HEAD(head2); \ 478 } \ 479 } while (0) 480 481 #define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) 482 483 #define TAILQ_FIRST(head) ((head)->tqh_first) 484 485 #define TAILQ_FOREACH(var, head, field) \ 486 for ((var) = TAILQ_FIRST((head)); \ 487 (var); \ 488 (var) = TAILQ_NEXT((var), field)) 489 490 #define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ 491 for ((var) = TAILQ_LAST((head), headname); \ 492 (var); \ 493 (var) = TAILQ_PREV((var), headname, field)) 494 495 #define TAILQ_INIT(head) do { \ 496 TAILQ_FIRST((head)) = NULL; \ 497 (head)->tqh_last = &TAILQ_FIRST((head)); \ 498 QMD_TRACE_HEAD(head); \ 499 } while (0) 500 501 #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ 502 if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ 503 TAILQ_NEXT((elm), field)->field.tqe_prev = \ 504 &TAILQ_NEXT((elm), field); \ 505 else { \ 506 (head)->tqh_last = &TAILQ_NEXT((elm), field); \ 507 QMD_TRACE_HEAD(head); \ 508 } \ 509 TAILQ_NEXT((listelm), field) = (elm); \ 510 (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ 511 QMD_TRACE_ELEM(&(elm)->field); \ 512 QMD_TRACE_ELEM(&listelm->field); \ 513 } while (0) 514 515 #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ 516 (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ 517 TAILQ_NEXT((elm), field) = (listelm); \ 518 *(listelm)->field.tqe_prev = (elm); \ 519 (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ 520 QMD_TRACE_ELEM(&(elm)->field); \ 521 QMD_TRACE_ELEM(&listelm->field); \ 522 } while (0) 523 524 #define TAILQ_INSERT_HEAD(head, elm, field) do { \ 525 if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ 526 TAILQ_FIRST((head))->field.tqe_prev = \ 527 &TAILQ_NEXT((elm), field); \ 528 else \ 529 (head)->tqh_last = &TAILQ_NEXT((elm), field); \ 530 TAILQ_FIRST((head)) = (elm); \ 531 (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ 532 QMD_TRACE_HEAD(head); \ 533 QMD_TRACE_ELEM(&(elm)->field); \ 534 } while (0) 535 536 #define TAILQ_INSERT_TAIL(head, elm, field) do { \ 537 TAILQ_NEXT((elm), field) = NULL; \ 538 (elm)->field.tqe_prev = (head)->tqh_last; \ 539 *(head)->tqh_last = (elm); \ 540 (head)->tqh_last = &TAILQ_NEXT((elm), field); \ 541 QMD_TRACE_HEAD(head); \ 542 QMD_TRACE_ELEM(&(elm)->field); \ 543 } while (0) 544 545 #define TAILQ_LAST(head, headname) \ 546 (*(((struct headname *)((head)->tqh_last))->tqh_last)) 547 548 #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) 549 550 #define TAILQ_PREV(elm, headname, field) \ 551 (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) 552 553 #define TAILQ_REMOVE(head, elm, field) do { \ 554 if ((TAILQ_NEXT((elm), field)) != NULL) \ 555 TAILQ_NEXT((elm), field)->field.tqe_prev = \ 556 (elm)->field.tqe_prev; \ 557 else { \ 558 (head)->tqh_last = (elm)->field.tqe_prev; \ 559 QMD_TRACE_HEAD(head); \ 560 } \ 561 *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ 562 TRASHIT((elm)->field.tqe_next); \ 563 TRASHIT((elm)->field.tqe_prev); \ 564 QMD_TRACE_ELEM(&(elm)->field); \ 565 } while (0) 566 567 #if defined(__cplusplus) 568 } 569 #endif 570 #endif /* !_DB_QUEUE_H_ */ 571