LCOV - code coverage report
Current view: top level - src/include/storage - proclist.h (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 47 47 100.0 %
Date: 2024-03-29 05:11:05 Functions: 8 8 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * proclist.h
       4             :  *      operations on doubly-linked lists of pgprocnos
       5             :  *
       6             :  * The interface is similar to dlist from ilist.h, but uses pgprocno instead
       7             :  * of pointers.  This allows proclist_head to be mapped at different addresses
       8             :  * in different backends.
       9             :  *
      10             :  * See proclist_types.h for the structs that these functions operate on.  They
      11             :  * are separated to break a header dependency cycle with proc.h.
      12             :  *
      13             :  * Portions Copyright (c) 2016-2024, PostgreSQL Global Development Group
      14             :  *
      15             :  * IDENTIFICATION
      16             :  *      src/include/storage/proclist.h
      17             :  *-------------------------------------------------------------------------
      18             :  */
      19             : #ifndef PROCLIST_H
      20             : #define PROCLIST_H
      21             : 
      22             : #include "storage/proc.h"
      23             : #include "storage/proclist_types.h"
      24             : 
      25             : /*
      26             :  * Initialize a proclist.
      27             :  */
      28             : static inline void
      29    37288350 : proclist_init(proclist_head *list)
      30             : {
      31    37288350 :     list->head = list->tail = INVALID_PROC_NUMBER;
      32    37288350 : }
      33             : 
      34             : /*
      35             :  * Is the list empty?
      36             :  */
      37             : static inline bool
      38     9220012 : proclist_is_empty(const proclist_head *list)
      39             : {
      40     9220012 :     return list->head == INVALID_PROC_NUMBER;
      41             : }
      42             : 
      43             : /*
      44             :  * Get a pointer to a proclist_node inside a given PGPROC, given a procno and
      45             :  * the proclist_node field's offset within struct PGPROC.
      46             :  */
      47             : static inline proclist_node *
      48      719052 : proclist_node_get(int procno, size_t node_offset)
      49             : {
      50      719052 :     char       *entry = (char *) GetPGProcByNumber(procno);
      51             : 
      52      719052 :     return (proclist_node *) (entry + node_offset);
      53             : }
      54             : 
      55             : /*
      56             :  * Insert a process at the beginning of a list.
      57             :  */
      58             : static inline void
      59        9226 : proclist_push_head_offset(proclist_head *list, int procno, size_t node_offset)
      60             : {
      61        9226 :     proclist_node *node = proclist_node_get(procno, node_offset);
      62             : 
      63             :     Assert(node->next == 0 && node->prev == 0);
      64             : 
      65        9226 :     if (list->head == INVALID_PROC_NUMBER)
      66             :     {
      67             :         Assert(list->tail == INVALID_PROC_NUMBER);
      68        6238 :         node->next = node->prev = INVALID_PROC_NUMBER;
      69        6238 :         list->head = list->tail = procno;
      70             :     }
      71             :     else
      72             :     {
      73             :         Assert(list->tail != INVALID_PROC_NUMBER);
      74             :         Assert(list->head != procno);
      75             :         Assert(list->tail != procno);
      76        2988 :         node->next = list->head;
      77        2988 :         proclist_node_get(node->next, node_offset)->prev = procno;
      78        2988 :         node->prev = INVALID_PROC_NUMBER;
      79        2988 :         list->head = procno;
      80             :     }
      81        9226 : }
      82             : 
      83             : /*
      84             :  * Insert a process at the end of a list.
      85             :  */
      86             : static inline void
      87      229780 : proclist_push_tail_offset(proclist_head *list, int procno, size_t node_offset)
      88             : {
      89      229780 :     proclist_node *node = proclist_node_get(procno, node_offset);
      90             : 
      91             :     Assert(node->next == 0 && node->prev == 0);
      92             : 
      93      229780 :     if (list->tail == INVALID_PROC_NUMBER)
      94             :     {
      95             :         Assert(list->head == INVALID_PROC_NUMBER);
      96      222038 :         node->next = node->prev = INVALID_PROC_NUMBER;
      97      222038 :         list->head = list->tail = procno;
      98             :     }
      99             :     else
     100             :     {
     101             :         Assert(list->head != INVALID_PROC_NUMBER);
     102             :         Assert(list->head != procno);
     103             :         Assert(list->tail != procno);
     104        7742 :         node->prev = list->tail;
     105        7742 :         proclist_node_get(node->prev, node_offset)->next = procno;
     106        7742 :         node->next = INVALID_PROC_NUMBER;
     107        7742 :         list->tail = procno;
     108             :     }
     109      229780 : }
     110             : 
     111             : /*
     112             :  * Delete a process from a list --- it must be in the list!
     113             :  */
     114             : static inline void
     115      239292 : proclist_delete_offset(proclist_head *list, int procno, size_t node_offset)
     116             : {
     117      239292 :     proclist_node *node = proclist_node_get(procno, node_offset);
     118             : 
     119             :     Assert(node->next != 0 || node->prev != 0);
     120             : 
     121      239292 :     if (node->prev == INVALID_PROC_NUMBER)
     122             :     {
     123             :         Assert(list->head == procno);
     124      238368 :         list->head = node->next;
     125             :     }
     126             :     else
     127         924 :         proclist_node_get(node->prev, node_offset)->next = node->next;
     128             : 
     129      239292 :     if (node->next == INVALID_PROC_NUMBER)
     130             :     {
     131             :         Assert(list->tail == procno);
     132      229284 :         list->tail = node->prev;
     133             :     }
     134             :     else
     135       10008 :         proclist_node_get(node->next, node_offset)->prev = node->prev;
     136             : 
     137      239292 :     node->next = node->prev = 0;
     138      239292 : }
     139             : 
     140             : /*
     141             :  * Check if a process is currently in a list.  It must be known that the
     142             :  * process is not in any _other_ proclist that uses the same proclist_node,
     143             :  * so that the only possibilities are that it is in this list or none.
     144             :  */
     145             : static inline bool
     146      138462 : proclist_contains_offset(const proclist_head *list, int procno,
     147             :                          size_t node_offset)
     148             : {
     149      138462 :     const proclist_node *node = proclist_node_get(procno, node_offset);
     150             : 
     151             :     /* If it's not in any list, it's definitely not in this one. */
     152      138462 :     if (node->prev == 0 && node->next == 0)
     153       42044 :         return false;
     154             : 
     155             :     /*
     156             :      * It must, in fact, be in this list.  Ideally, in assert-enabled builds,
     157             :      * we'd verify that.  But since this function is typically used while
     158             :      * holding a spinlock, crawling the whole list is unacceptable.  However,
     159             :      * we can verify matters in O(1) time when the node is a list head or
     160             :      * tail, and that seems worth doing, since in practice that should often
     161             :      * be enough to catch mistakes.
     162             :      */
     163             :     Assert(node->prev != INVALID_PROC_NUMBER || list->head == procno);
     164             :     Assert(node->next != INVALID_PROC_NUMBER || list->tail == procno);
     165             : 
     166       96418 :     return true;
     167             : }
     168             : 
     169             : /*
     170             :  * Remove and return the first process from a list (there must be one).
     171             :  */
     172             : static inline PGPROC *
     173       41990 : proclist_pop_head_node_offset(proclist_head *list, size_t node_offset)
     174             : {
     175             :     PGPROC     *proc;
     176             : 
     177             :     Assert(!proclist_is_empty(list));
     178       41990 :     proc = GetPGProcByNumber(list->head);
     179       41990 :     proclist_delete_offset(list, list->head, node_offset);
     180       41990 :     return proc;
     181             : }
     182             : 
     183             : /*
     184             :  * Helper macros to avoid repetition of offsetof(PGPROC, <member>).
     185             :  * 'link_member' is the name of a proclist_node member in PGPROC.
     186             :  */
     187             : #define proclist_delete(list, procno, link_member) \
     188             :     proclist_delete_offset((list), (procno), offsetof(PGPROC, link_member))
     189             : #define proclist_push_head(list, procno, link_member) \
     190             :     proclist_push_head_offset((list), (procno), offsetof(PGPROC, link_member))
     191             : #define proclist_push_tail(list, procno, link_member) \
     192             :     proclist_push_tail_offset((list), (procno), offsetof(PGPROC, link_member))
     193             : #define proclist_pop_head_node(list, link_member) \
     194             :     proclist_pop_head_node_offset((list), offsetof(PGPROC, link_member))
     195             : #define proclist_contains(list, procno, link_member) \
     196             :     proclist_contains_offset((list), (procno), offsetof(PGPROC, link_member))
     197             : 
     198             : /*
     199             :  * Iterate through the list pointed at by 'lhead', storing the current
     200             :  * position in 'iter'.  'link_member' is the name of a proclist_node member in
     201             :  * PGPROC.  Access the current position with iter.cur.
     202             :  *
     203             :  * The only list modification allowed while iterating is deleting the current
     204             :  * node with proclist_delete(list, iter.cur, node_offset).
     205             :  */
     206             : #define proclist_foreach_modify(iter, lhead, link_member)                   \
     207             :     for (AssertVariableIsOfTypeMacro(iter, proclist_mutable_iter),          \
     208             :          AssertVariableIsOfTypeMacro(lhead, proclist_head *),               \
     209             :          (iter).cur = (lhead)->head,                                     \
     210             :          (iter).next = (iter).cur == INVALID_PROC_NUMBER ? INVALID_PROC_NUMBER :    \
     211             :              proclist_node_get((iter).cur,                                  \
     212             :                                offsetof(PGPROC, link_member))->next;     \
     213             :          (iter).cur != INVALID_PROC_NUMBER;                                 \
     214             :          (iter).cur = (iter).next,                                          \
     215             :          (iter).next = (iter).cur == INVALID_PROC_NUMBER ? INVALID_PROC_NUMBER :    \
     216             :              proclist_node_get((iter).cur,                                  \
     217             :                                offsetof(PGPROC, link_member))->next)
     218             : 
     219             : #endif                          /* PROCLIST_H */

Generated by: LCOV version 1.14