Print this page
    
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/fs/proc/prdata.h
          +++ new/usr/src/uts/common/fs/proc/prdata.h
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  23   23   * Use is subject to license terms.
  24   24   */
  25   25  
  26   26  /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
  27   27  /*        All Rights Reserved   */
  28   28  
  29   29  /*
  30   30   * Copyright 2015, Joyent, Inc.
  31   31   */
  32   32  
  33   33  #ifndef _SYS_PROC_PRDATA_H
  34   34  #define _SYS_PROC_PRDATA_H
  35   35  
  36   36  #include <sys/isa_defs.h>
  37   37  #include <sys/proc.h>
  38   38  #include <sys/vnode.h>
  39   39  #include <sys/prsystm.h>
  40   40  #include <sys/model.h>
  41   41  #include <sys/poll.h>
  42   42  #include <sys/list.h>
  43   43  
  44   44  #ifdef  __cplusplus
  45   45  extern "C" {
  46   46  #endif
  47   47  
  48   48  /*
  49   49   * Test for thread being stopped, not on an event of interest,
  50   50   * but with a directed stop in effect.
  51   51   */
  52   52  #define DSTOPPED(t)     \
  53   53          ((t)->t_state == TS_STOPPED && \
  54   54          ((t)->t_proc_flag & TP_PRSTOP))
  55   55  
  56   56  #define round4(r)       (((r) + 3) & (~3))
  57   57  #define round8(r)       (((r) + 7) & (~7))
  58   58  #define round16(r)      (((r) + 15) & (~15))
  59   59  #define roundlong(r)    (((r) + sizeof (long) - 1) & (~(sizeof (long) - 1)))
  60   60  
  61   61  #define PNSIZ   10                      /* max size of /proc name entries */
  62   62  #define PLNSIZ  10                      /* max size of /proc lwp name entries */
  63   63  
  64   64  /*
  65   65   * Common file object to which all /proc vnodes for a specific process
  66   66   * or lwp refer.  One for the process, one for each lwp.
  67   67   */
  68   68  typedef struct prcommon {
  69   69          kmutex_t        prc_mutex;      /* to wait for the proc/lwp to stop */
  70   70          kcondvar_t      prc_wait;       /* to wait for the proc/lwp to stop */
  71   71          ushort_t        prc_flags;      /* flags */
  72   72          uint_t          prc_writers;    /* number of write opens of prnodes */
  73   73          uint_t          prc_selfopens;  /* number of write opens by self */
  74   74          pid_t           prc_pid;        /* process id */
  75   75          model_t         prc_datamodel;  /* data model of the process */
  76   76          proc_t          *prc_proc;      /* process being traced */
  77   77          kthread_t       *prc_thread;    /* thread (lwp) being traced */
  78   78          int             prc_slot;       /* procdir slot number */
  79   79          id_t            prc_tid;        /* thread (lwp) id */
  80   80          int             prc_tslot;      /* lwpdir slot number, -1 if reaped */
  81   81          int             prc_refcnt;     /* this structure's reference count */
  82   82          struct pollhead prc_pollhead;   /* list of all pollers */
  83   83  } prcommon_t;
  84   84  
  85   85  /* prc_flags */
  86   86  #define PRC_DESTROY     0x01    /* process or lwp is being destroyed */
  87   87  #define PRC_LWP         0x02    /* structure refers to an lwp */
  88   88  #define PRC_SYS         0x04    /* process is a system process */
  89   89  #define PRC_POLL        0x08    /* poll() in progress on this process/lwp */
  90   90  #define PRC_EXCL        0x10    /* exclusive access granted (old /proc) */
  91   91  
  92   92  /*
  93   93   * Macros for mapping between i-numbers and pids.
  94   94   */
  95   95  #define pmkino(tslot, pslot, nodetype)          \
  96   96          (((((ino_t)(tslot) << nproc_highbit) |  \
  97   97          (ino_t)(pslot)) << 6) |                 \
  98   98          (nodetype) + 2)
  99   99  
 100  100  /* for old /proc interface */
 101  101  #define PRBIAS  64
 102  102  #define ptoi(n) ((int)(((n) + PRBIAS)))         /* pid to i-number */
 103  103  
 104  104  /*
 105  105   * Node types for /proc files (directories and files contained therein).
 106  106   */
 107  107  typedef enum prnodetype {
 108  108          PR_PROCDIR,             /* /proc                                */
 109  109          PR_SELF,                /* /proc/self                           */
 110  110          PR_PIDDIR,              /* /proc/<pid>                          */
 111  111          PR_AS,                  /* /proc/<pid>/as                       */
 112  112          PR_CTL,                 /* /proc/<pid>/ctl                      */
 113  113          PR_STATUS,              /* /proc/<pid>/status                   */
 114  114          PR_LSTATUS,             /* /proc/<pid>/lstatus                  */
 115  115          PR_PSINFO,              /* /proc/<pid>/psinfo                   */
 116  116          PR_LPSINFO,             /* /proc/<pid>/lpsinfo                  */
 117  117          PR_MAP,                 /* /proc/<pid>/map                      */
 118  118          PR_RMAP,                /* /proc/<pid>/rmap                     */
 119  119          PR_XMAP,                /* /proc/<pid>/xmap                     */
 120  120          PR_CRED,                /* /proc/<pid>/cred                     */
 121  121          PR_SIGACT,              /* /proc/<pid>/sigact                   */
 122  122          PR_AUXV,                /* /proc/<pid>/auxv                     */
 123  123  #if defined(__i386) || defined(__amd64)
 124  124          PR_LDT,                 /* /proc/<pid>/ldt                      */
 125  125  #endif
 126  126          PR_ARGV,                /* /proc/<pid>/argv                     */
 127  127          PR_USAGE,               /* /proc/<pid>/usage                    */
 128  128          PR_LUSAGE,              /* /proc/<pid>/lusage                   */
 129  129          PR_PAGEDATA,            /* /proc/<pid>/pagedata                 */
 130  130          PR_WATCH,               /* /proc/<pid>/watch                    */
 131  131          PR_CURDIR,              /* /proc/<pid>/cwd                      */
 132  132          PR_ROOTDIR,             /* /proc/<pid>/root                     */
 133  133          PR_FDDIR,               /* /proc/<pid>/fd                       */
 134  134          PR_FD,                  /* /proc/<pid>/fd/nn                    */
 135  135          PR_OBJECTDIR,           /* /proc/<pid>/object                   */
 136  136          PR_OBJECT,              /* /proc/<pid>/object/xxx               */
 137  137          PR_LWPDIR,              /* /proc/<pid>/lwp                      */
 138  138          PR_LWPIDDIR,            /* /proc/<pid>/lwp/<lwpid>              */
 139  139          PR_LWPCTL,              /* /proc/<pid>/lwp/<lwpid>/lwpctl       */
 140  140          PR_LWPSTATUS,           /* /proc/<pid>/lwp/<lwpid>/lwpstatus    */
 141  141          PR_LWPSINFO,            /* /proc/<pid>/lwp/<lwpid>/lwpsinfo     */
 142  142          PR_LWPUSAGE,            /* /proc/<pid>/lwp/<lwpid>/lwpusage     */
 143  143          PR_XREGS,               /* /proc/<pid>/lwp/<lwpid>/xregs        */
 144  144          PR_TMPLDIR,             /* /proc/<pid>/lwp/<lwpid>/templates    */
 145  145          PR_TMPL,                /* /proc/<pid>/lwp/<lwpid>/templates/<id> */
 146  146          PR_SPYMASTER,           /* /proc/<pid>/lwp/<lwpid>/spymaster    */
 147  147  #if defined(__sparc)
 148  148          PR_GWINDOWS,            /* /proc/<pid>/lwp/<lwpid>/gwindows     */
 149  149          PR_ASRS,                /* /proc/<pid>/lwp/<lwpid>/asrs         */
 150  150  #endif
 151  151          PR_PRIV,                /* /proc/<pid>/priv                     */
 152  152          PR_PATHDIR,             /* /proc/<pid>/path                     */
 153  153          PR_PATH,                /* /proc/<pid>/path/xxx                 */
 154  154          PR_CTDIR,               /* /proc/<pid>/contracts                */
 155  155          PR_CT,                  /* /proc/<pid>/contracts/<ctid>         */
 156  156          PR_PIDFILE,             /* old process file                     */
 157  157          PR_LWPIDFILE,           /* old lwp file                         */
 158  158          PR_OPAGEDATA,           /* old page data file                   */
 159  159          PR_NFILES               /* number of /proc node types           */
 160  160  } prnodetype_t;
 161  161  
 162  162  typedef struct prnode {
 163  163          vnode_t         *pr_next;       /* list of all vnodes for process */
 164  164          uint_t          pr_flags;       /* private flags */
 165  165          kmutex_t        pr_mutex;       /* locks pr_files and child pr_flags */
 166  166          prnodetype_t    pr_type;        /* node type */
 167  167          mode_t          pr_mode;        /* file mode */
 168  168          ino_t           pr_ino;         /* node id (for stat(2)) */
 169  169          uint_t          pr_hatid;       /* hat layer id for page data files */
 170  170          prcommon_t      *pr_common;     /* common data structure */
 171  171          prcommon_t      *pr_pcommon;    /* process common data structure */
 172  172          vnode_t         *pr_parent;     /* parent directory */
 173  173          vnode_t         **pr_files;     /* contained files array (directory) */
 174  174          uint_t          pr_index;       /* position within parent */
 175  175          vnode_t         *pr_pidfile;    /* substitute vnode for old /proc */
 176  176          vnode_t         *pr_realvp;     /* real vnode, file in object,fd dirs */
 177  177          proc_t          *pr_owner;      /* the process that created this node */
 178  178          vnode_t         *pr_vnode;      /* pointer to vnode */
 179  179          struct contract *pr_contract;   /* contract pointer */
 180  180          int             pr_cttype;      /* active template type */
 181  181  } prnode_t;
 182  182  
 183  183  /*
 184  184   * Values for pr_flags.
 185  185   */
 186  186  #define PR_INVAL        0x01            /* vnode is invalidated */
 187  187  #define PR_ISSELF       0x02            /* vnode is a self-open */
 188  188  #define PR_AOUT         0x04            /* vnode is for an a.out path */
 189  189  #define PR_OFFMAX       0x08            /* vnode is a large file open */
 190  190  
 191  191  /*
 192  192   * Conversion macros.
 193  193   */
 194  194  #define VTOP(vp)        ((struct prnode *)(vp)->v_data)
 195  195  #define PTOV(pnp)       ((pnp)->pr_vnode)
 196  196  
 197  197  /*
 198  198   * Flags to prlock().
 199  199   */
 200  200  #define ZNO     0       /* Fail on encountering a zombie process. */
 201  201  #define ZYES    1       /* Allow zombies. */
 202  202  
 203  203  /*
 204  204   * Assign one set to another (possible different sizes).
 205  205   *
 206  206   * Assigning to a smaller set causes members to be lost.
 207  207   * Assigning to a larger set causes extra members to be cleared.
 208  208   */
 209  209  #define prassignset(ap, sp)                                     \
 210  210  {                                                               \
 211  211          register int _i_ = sizeof (*(ap))/sizeof (uint32_t);    \
 212  212          while (--_i_ >= 0)                                      \
 213  213                  ((uint32_t *)(ap))[_i_] =                       \
 214  214                      (_i_ >= sizeof (*(sp))/sizeof (uint32_t)) ? \
 215  215                      0 : ((uint32_t *)(sp))[_i_];                \
 216  216  }
 217  217  
 218  218  /*
 219  219   * Determine whether or not a set (of arbitrary size) is empty.
 220  220   */
 221  221  #define prisempty(sp) \
 222  222          setisempty((uint32_t *)(sp), \
 223  223                  (uint_t)(sizeof (*(sp)) / sizeof (uint32_t)))
 224  224  
 225  225  /*
 226  226   * Resource usage with times as hrtime_t rather than timestruc_t.
 227  227   * Each member exactly matches the corresponding member in prusage_t.
 228  228   * This is for convenience of internal computation.
 229  229   */
 230  230  typedef struct prhusage {
 231  231          id_t            pr_lwpid;       /* lwp id.  0: process or defunct */
 232  232          int             pr_count;       /* number of contributing lwps */
 233  233          hrtime_t        pr_tstamp;      /* current time stamp */
 234  234          hrtime_t        pr_create;      /* process/lwp creation time stamp */
 235  235          hrtime_t        pr_term;        /* process/lwp termination time stamp */
 236  236          hrtime_t        pr_rtime;       /* total lwp real (elapsed) time */
 237  237          hrtime_t        pr_utime;       /* user level CPU time */
 238  238          hrtime_t        pr_stime;       /* system call CPU time */
 239  239          hrtime_t        pr_ttime;       /* other system trap CPU time */
 240  240          hrtime_t        pr_tftime;      /* text page fault sleep time */
 241  241          hrtime_t        pr_dftime;      /* data page fault sleep time */
 242  242          hrtime_t        pr_kftime;      /* kernel page fault sleep time */
 243  243          hrtime_t        pr_ltime;       /* user lock wait sleep time */
 244  244          hrtime_t        pr_slptime;     /* all other sleep time */
 245  245          hrtime_t        pr_wtime;       /* wait-cpu (latency) time */
 246  246          hrtime_t        pr_stoptime;    /* stopped time */
 247  247          hrtime_t        filltime[6];    /* filler for future expansion */
 248  248          uint64_t        pr_minf;        /* minor page faults */
 249  249          uint64_t        pr_majf;        /* major page faults */
 250  250          uint64_t        pr_nswap;       /* swaps */
 251  251          uint64_t        pr_inblk;       /* input blocks */
 252  252          uint64_t        pr_oublk;       /* output blocks */
 253  253          uint64_t        pr_msnd;        /* messages sent */
 254  254          uint64_t        pr_mrcv;        /* messages received */
 255  255          uint64_t        pr_sigs;        /* signals received */
 256  256          uint64_t        pr_vctx;        /* voluntary context switches */
 257  257          uint64_t        pr_ictx;        /* involuntary context switches */
 258  258          uint64_t        pr_sysc;        /* system calls */
 259  259          uint64_t        pr_ioch;        /* chars read and written */
 260  260          uint64_t        filler[10];     /* filler for future expansion */
 261  261  } prhusage_t;
 262  262  
 263  263  #if defined(_KERNEL)
 264  264  
 265  265  /* Exclude system processes from this test */
 266  266  #define PROCESS_NOT_32BIT(p)    \
 267  267          (!((p)->p_flag & SSYS) && (p)->p_as != &kas && \
 268  268          (p)->p_model != DATAMODEL_ILP32)
 269  269  
 270  270  extern  int     prnwatch;       /* number of supported watchpoints */
 271  271  extern  int     nproc_highbit;  /* highbit(v.v_nproc) */
 272  272  
 273  273  extern  struct vnodeops *prvnodeops;
 274  274  
 275  275  /*
 276  276   * Generic chained copyout buffers for procfs use.
 277  277   * In order to prevent procfs from making huge oversize kmem_alloc calls,
 278  278   * a list of smaller buffers can be concatenated and copied to userspace in
 279  279   * sequence.
 280  280   *
 281  281   * The implementation is opaque.
 282  282   *
 283  283   * A user of this will perform the following steps:
 284  284   *
 285  285   *      list_t  listhead;
 286  286   *      struct my *mp;
 287  287   *
 288  288   *      pr_iol_initlist(&listhead, sizeof (*mp), n);
 289  289   *      while (whatever) {
 290  290   *              mp = pr_iol_newbuf(&listhead, sizeof (*mp);
 291  291   *              ...
 292  292   *              error = ...
 293  293   *      }
 294  294   *
 295  295   * When done, depending on whether copyout() or uiomove() is supposed to
 296  296   * be used for transferring the buffered data to userspace, call either:
 297  297   *
 298  298   *      error = pr_iol_copyout_and_free(&listhead, &cmaddr, error);
 299  299   *
 300  300   * or else:
 301  301   *
 302  302   *      error = pr_iol_uiomove_and_free(&listhead, uiop, error);
 303  303   *
 304  304   * These two functions will in any case kmem_free() all list items, but
 305  305   * if an error occurred before they will not perform the copyout/uiomove.
 306  306   * If copyout/uiomove are done, the passed target address / uio_t
 307  307   * are updated. The error returned will either be the one passed in, or
 308  308   * the error that occurred during copyout/uiomove.
 309  309   */
 310  310  
 311  311  extern  void    pr_iol_initlist(list_t *head, size_t itemsize, int nitems);
 312  312  extern  void *  pr_iol_newbuf(list_t *head, size_t itemsize);
 313  313  extern  int     pr_iol_copyout_and_free(list_t *head, caddr_t *tgt, int errin);
 314  314  extern  int     pr_iol_uiomove_and_free(list_t *head, uio_t *uiop, int errin);
 315  315  
 316  316  #if defined(_SYSCALL32_IMPL)
 317  317  
 318  318  extern  int     prwritectl32(vnode_t *, struct uio *, cred_t *);
 319  319  extern  void    prgetaction32(proc_t *, user_t *, uint_t, struct sigaction32 *);
 320  320  extern  void    prcvtusage32(struct prhusage *, prusage32_t *);
 321  321  
 322  322  #endif  /* _SYSCALL32_IMPL */
 323  323  
 324  324  /* kludge to support old /proc interface */
 325  325  #if !defined(_SYS_OLD_PROCFS_H)
 326  326  extern  int     prgetmap(proc_t *, int, list_t *);
 327  327  extern  int     prgetxmap(proc_t *, list_t *);
 328  328  #if defined(_SYSCALL32_IMPL)
 329  329  extern  int     prgetmap32(proc_t *, int, list_t *);
 330  330  extern  int     prgetxmap32(proc_t *, list_t *);
 331  331  #endif  /* _SYSCALL32_IMPL */
 332  332  #endif /* !_SYS_OLD_PROCFS_H */
 333  333  
 334  334  extern  proc_t  *pr_p_lock(prnode_t *);
 335  335  extern  kthread_t *pr_thread(prnode_t *);
 336  336  extern  void    pr_stop(prnode_t *);
 337  337  extern  int     pr_wait_stop(prnode_t *, time_t);
 338  338  extern  int     pr_setrun(prnode_t *, ulong_t);
 339  339  extern  int     pr_wait(prcommon_t *, timestruc_t *, int);
 340  340  extern  void    pr_wait_die(prnode_t *);
 341  341  extern  int     pr_setsig(prnode_t *, siginfo_t *);
 342  342  extern  int     pr_kill(prnode_t *, int, cred_t *);
 343  343  extern  int     pr_unkill(prnode_t *, int);
 344  344  extern  int     pr_nice(proc_t *, int, cred_t *);
 345  345  extern  void    pr_setentryexit(proc_t *, sysset_t *, int);
 346  346  extern  int     pr_set(proc_t *, long);
 347  347  extern  int     pr_unset(proc_t *, long);
 348  348  extern  void    pr_sethold(prnode_t *, sigset_t *);
 349  349  extern  void    pr_setfault(proc_t *, fltset_t *);
 350  350  extern  int     prusrio(proc_t *, enum uio_rw, struct uio *, int);
 351  351  extern  int     prreadargv(proc_t *, char *, size_t, size_t *);
 352  352  extern  int     prreadenvv(proc_t *, char *, size_t, size_t *);
 353  353  extern  int     prwritectl(vnode_t *, struct uio *, cred_t *);
 354  354  extern  int     prlock(prnode_t *, int);
 355  355  extern  void    prunmark(proc_t *);
 356  356  extern  void    prunlock(prnode_t *);
 357  357  extern  size_t  prpdsize(struct as *);
 358  358  extern  int     prpdread(proc_t *, uint_t, struct uio *);
 359  359  extern  size_t  oprpdsize(struct as *);
 360  360  extern  int     oprpdread(struct as *, uint_t, struct uio *);
 361  361  extern  void    prgetaction(proc_t *, user_t *, uint_t, struct sigaction *);
 362  362  extern  void    prgetusage(kthread_t *, struct prhusage *);
 363  363  extern  void    praddusage(kthread_t *, struct prhusage *);
 364  364  extern  void    prcvtusage(struct prhusage *, prusage_t *);
 365  365  extern  void    prscaleusage(prhusage_t *);
 366  366  extern  kthread_t *prchoose(proc_t *);
 367  367  extern  void    allsetrun(proc_t *);
 368  368  extern  int     setisempty(uint32_t *, uint_t);
 369  369  extern  int     pr_u32tos(uint32_t, char *, int);
 370  370  extern  vnode_t *prlwpnode(prnode_t *, uint_t);
 371  371  extern  prnode_t *prgetnode(vnode_t *, prnodetype_t);
 372  372  extern  void    prfreenode(prnode_t *);
 373  373  extern  void    pr_object_name(char *, vnode_t *, struct vattr *);
 374  374  extern  int     set_watched_area(proc_t *, struct watched_area *);
 375  375  extern  int     clear_watched_area(proc_t *, struct watched_area *);
 376  376  extern  void    pr_free_watchpoints(proc_t *);
 377  377  extern  proc_t  *pr_cancel_watch(prnode_t *);
 378  378  extern  struct seg *break_seg(proc_t *);
 379  379  
 380  380  /*
 381  381   * Machine-dependent routines (defined in prmachdep.c).
 382  382   */
 383  383  extern  void    prgetprregs(klwp_t *, prgregset_t);
 384  384  extern  void    prsetprregs(klwp_t *, prgregset_t, int);
 385  385  
 386  386  #if defined(_SYSCALL32_IMPL)
 387  387  extern  void    prgetprregs32(klwp_t *, prgregset32_t);
 388  388  extern  void    prgregset_32ton(klwp_t *, prgregset32_t, prgregset_t);
 389  389  extern  void    prgetprfpregs32(klwp_t *, prfpregset32_t *);
 390  390  extern  void    prsetprfpregs32(klwp_t *, prfpregset32_t *);
 391  391  extern  size_t  prpdsize32(struct as *);
 392  392  extern  int     prpdread32(proc_t *, uint_t, struct uio *);
 393  393  extern  size_t  oprpdsize32(struct as *);
 394  394  extern  int     oprpdread32(struct as *, uint_t, struct uio *);
 395  395  #endif  /* _SYSCALL32_IMPL */
 396  396  
 397  397  extern  void    prpokethread(kthread_t *t);
 398  398  extern  int     prgetrvals(klwp_t *, long *, long *);
 399  399  extern  void    prgetprfpregs(klwp_t *, prfpregset_t *);
 400  400  extern  void    prsetprfpregs(klwp_t *, prfpregset_t *);
 401  401  extern  void    prgetprxregs(klwp_t *, caddr_t);
 402  402  extern  void    prsetprxregs(klwp_t *, caddr_t);
 403  403  extern  int     prgetprxregsize(proc_t *);
 404  404  extern  int     prhasfp(void);
 405  405  extern  int     prhasx(proc_t *);
 406  406  extern  caddr_t prgetstackbase(proc_t *);
 407  407  extern  caddr_t prgetpsaddr(proc_t *);
 408  408  extern  int     prisstep(klwp_t *);
 409  409  extern  void    prsvaddr(klwp_t *, caddr_t);
 410  410  extern  int     prfetchinstr(klwp_t *, ulong_t *);
 411  411  extern  ushort_t prgetpctcpu(uint64_t);
 412  412  
 413  413  #endif  /* _KERNEL */
 414  414  
 415  415  #ifdef  __cplusplus
 416  416  }
 417  417  #endif
 418  418  
 419  419  #endif  /* _SYS_PROC_PRDATA_H */
  
    | 
      ↓ open down ↓ | 
    419 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX