Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief Latent Command Framework - real time settings frameworks for all Enduro/X
0003  *  processes (clients & servers)
0004  *
0005  * @file lcf.c
0006  */
0007 /* -----------------------------------------------------------------------------
0008  * Enduro/X Middleware Platform for Distributed Transaction Processing
0009  * Copyright (C) 2009-2016, ATR Baltic, Ltd. All Rights Reserved.
0010  * Copyright (C) 2017-2023, Mavimax, Ltd. All Rights Reserved.
0011  * This software is released under one of the following licenses:
0012  * AGPL (with Java and Go exceptions) or Mavimax's license for commercial use.
0013  * See LICENSE file for full text.
0014  * -----------------------------------------------------------------------------
0015  * AGPL license:
0016  *
0017  * This program is free software; you can redistribute it and/or modify it under
0018  * the terms of the GNU Affero General Public License, version 3 as published
0019  * by the Free Software Foundation;
0020  *
0021  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0022  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0023  * PARTICULAR PURPOSE. See the GNU Affero General Public License, version 3
0024  * for more details.
0025  *
0026  * You should have received a copy of the GNU Affero General Public License along 
0027  * with this program; if not, write to the Free Software Foundation, Inc.,
0028  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0029  *
0030  * -----------------------------------------------------------------------------
0031  * A commercial use license is available from Mavimax, Ltd
0032  * contact@mavimax.com
0033  * -----------------------------------------------------------------------------
0034  */
0035 
0036 /*---------------------------Includes-----------------------------------*/
0037 #include <ndrstandard.h>
0038 #include <ndebug.h>
0039 #include <lcf.h>
0040 #include <lcfint.h>
0041 #include <nstd_int.h>
0042 #include <nstd_shm.h>
0043 #include <ndebugcmn.h>
0044 #include <sys_unix.h>
0045 #include <nerror.h>
0046 #include <exhash.h>
0047 #include <exregex.h>
0048 #include <lcfint.h>
0049 #include "exsha1.h"
0050 #include <exatomic.h>
0051 #include <singlegrp.h>
0052 #include <lcfint.h>
0053 /*---------------------------Externs------------------------------------*/
0054 /*---------------------------Macros-------------------------------------*/
0055 #define MAX_LCFMAX_DFLT         20      /**< Default max commands       */
0056 #define MAX_READERS_DFLT        50      /**< Max readers for RW lock... */
0057 #define MAX_LCFREADERS_DFLT     1000    /**< Lcf readers max this is priority */
0058 #define MAX_LCFSTARTMAX_DFLT    60      /**< Apply 60 seconds old commands */
0059 #define SGMREFRESHMAX_DFLT      30      /**< Number of sec. in which lock stamp must be refreshed */
0060 #define PGMAX_DFLT              64      /**< Maximum number of singleton groups */
0061 #define PGMAX_MAX               99999   /**< Upper limit of number of process groups */
0062 #define MAX_QUEUES_DLFT         20000   /**< Max number of queues, dflt */
0063 /*---------------------------Enums--------------------------------------*/
0064 /*---------------------------Typedefs-----------------------------------*/
0065 /*---------------------------Globals------------------------------------*/
0066 expublic ndrx_nstd_libconfig_t ndrx_G_libnstd_cfg;
0067 expublic ndrx_lcf_shmcfg_t *ndrx_G_shmcfg=NULL;        /**< Shared mem config, full          */
0068 expublic ndrx_lcf_shmcfg_ver_t M_ver_start = {.shmcfgver_lcf=0};
0069 
0070 /** 
0071  * During the init we will change the ptrs ... 
0072  * value 1 will initiate the pull-in
0073  */
0074 expublic volatile ndrx_lcf_shmcfg_ver_t *ndrx_G_shmcfg_ver=&M_ver_start;/**< Only version handling            */
0075 
0076 expublic volatile unsigned ndrx_G_shmcfgver_chk = 0;            /**< Last checked shared mem cfg vers */
0077 /*---------------------------Statics------------------------------------*/
0078 exprivate ndrx_shm_t M_lcf_shm = {.fd=0, .path="", .mem=NULL};  /**< Shared memory for settings       */
0079 exprivate ndrx_sem_t M_lcf_sem = {.semid=0};          /**< RW semaphore for SHM protection  */
0080 
0081 exprivate ndrx_lcf_command_seen_t *M_locl_lcf=NULL;   /**< Local LCFs seen, set when mmap   */
0082 
0083 exprivate ndrx_lcf_reg_funch_t *M_funcs=NULL;         /**< functions registered for LCF     */
0084 exprivate ndrx_lcf_reg_xadminh_t *M_xadmin_cmds=NULL; /**< xadmin commands registered       */
0085 
0086 exprivate int M_startup_run = EXTRUE;                 /**< First startup run                */
0087 exprivate MUTEX_LOCKDECL(M_lcf_run);
0088 
0089 /*---------------------------Prototypes---------------------------------*/
0090 
0091 exprivate int ndrx_lcf_logrotate(ndrx_lcf_command_t *cmd, long *p_flags);
0092 exprivate int ndrx_lcf_logchg(ndrx_lcf_command_t *cmd, long *p_flags);
0093 
0094 /*
0095  * - installcb
0096  * - install cli infos (command_str, id, args A|B, descr) -> 
0097  */
0098 
0099 /**
0100  * Find the command in hash (internal version)
0101  * @param cmdstr command name
0102  * @return hash object or NULL
0103  */
0104 expublic ndrx_lcf_reg_xadminh_t* ndrx_lcf_xadmin_find_int(char *cmdstr)
0105 {
0106     ndrx_lcf_reg_xadminh_t *ret = NULL;
0107     
0108     MUTEX_LOCK_V(M_lcf_run);
0109     
0110     EXHASH_FIND_STR( M_xadmin_cmds, cmdstr, ret);
0111     
0112     MUTEX_UNLOCK_V(M_lcf_run);
0113     
0114     return ret;
0115 }
0116 
0117 /**
0118  * If command not found -> add
0119  * if command is found -> Replace
0120  * NOTE! we cannot use log functions. Only NDRX_LOG_EARLY allowed
0121  * as plugins may register the functions 
0122  * @param xcmd Xadmin function definition
0123  * @return EXSUCCEED/EXFAIL
0124  */
0125 expublic int ndrx_lcf_xadmin_add_int(ndrx_lcf_reg_xadmin_t *xcmd)
0126 {
0127     int ret = EXSUCCEED;
0128     ndrx_lcf_reg_xadminh_t *h;
0129     
0130     h = ndrx_lcf_xadmin_find_int(xcmd->cmdstr);
0131     
0132     if (NULL!=h)
0133     {
0134         NDRX_LOG_EARLY(log_debug, "xadmin [%s] lcf command %d", xcmd->cmdstr, xcmd->command);
0135         _Nset_error_fmt(NEEXISTS, "xadmin [%s] lcf command %d", xcmd->cmdstr, xcmd->command);
0136         EXFAIL_OUT(ret);
0137     }
0138     else
0139     {
0140         NDRX_LOG_EARLY(log_debug, "Adding [%s] xadmin lcf command %d", 
0141                 xcmd->cmdstr, xcmd->command);
0142     }
0143     
0144     /* OK now add */
0145     h = NDRX_FPMALLOC(sizeof(ndrx_lcf_reg_xadminh_t), 0);
0146     
0147     if (NULL==h)
0148     {
0149         NDRX_LOG_EARLY(log_error, "Failed to malloc %d bytes (xadmin lcf cmd hash): %s",
0150                 sizeof(ndrx_lcf_reg_xadminh_t), strerror(errno));
0151         _Nset_error_fmt(NEMALLOC, "Failed to malloc %d bytes (xadmin lcf cmd hash): %s",
0152                 sizeof(ndrx_lcf_reg_xadminh_t), strerror(errno));
0153         EXFAIL_OUT(ret);
0154     }
0155     
0156     memcpy(&h->xcmd, xcmd, sizeof(ndrx_lcf_reg_xadmin_t));
0157     NDRX_STRCPY_SAFE(h->cmdstr, xcmd->cmdstr);
0158     
0159     MUTEX_LOCK_V(M_lcf_run);
0160     EXHASH_ADD_STR(M_xadmin_cmds, cmdstr, h);
0161     MUTEX_UNLOCK_V(M_lcf_run);
0162     
0163 out:
0164     return ret;
0165 }
0166 
0167 /**
0168  * Find the command in hash (internal version)
0169  * @param command command code
0170  * @return hash object or NULL
0171  */
0172 expublic ndrx_lcf_reg_funch_t* ndrx_lcf_func_find_int(int command, int do_lock)
0173 {
0174     ndrx_lcf_reg_funch_t *ret = NULL;
0175     
0176     if (do_lock)
0177     {
0178         MUTEX_LOCK_V(M_lcf_run);
0179     }
0180     
0181     EXHASH_FIND_INT( M_funcs, &command, ret);
0182     
0183     if (do_lock)
0184     {
0185         MUTEX_UNLOCK_V(M_lcf_run);
0186     }
0187     return ret;
0188 }
0189 
0190 /**
0191  * Register callback commands
0192  * @param xcmd
0193  * @return EXSUCCEED/EXFAIL
0194  */
0195 expublic int ndrx_lcf_func_add_int(ndrx_lcf_reg_func_t *cfunc)
0196 {
0197     int ret = EXSUCCEED;
0198     ndrx_lcf_reg_funch_t *h;
0199     
0200     h = ndrx_lcf_func_find_int(cfunc->command, EXTRUE);
0201     
0202     if (NULL!=h)
0203     {
0204         /* duplicate func not allowd */
0205         _Nset_error_fmt(NEEXISTS, "Command [%d] already registered for [%s]",
0206                 h->command, h->cfunc.cmdstr);
0207         EXFAIL_OUT(ret);
0208         
0209     }
0210     else
0211     {
0212         NDRX_LOG_EARLY(log_debug, "Adding [%d] func lcf command [%s]", 
0213                 cfunc->command, cfunc->cmdstr);
0214     }
0215     
0216     /* OK now add */
0217     h = NDRX_FPMALLOC(sizeof(ndrx_lcf_reg_funch_t), 0);
0218     
0219     if (NULL==h)
0220     {
0221         NDRX_LOG_EARLY(log_error, "Failed to malloc %d bytes (func lcf cmd hash): %s",
0222                 sizeof(ndrx_lcf_reg_funch_t), strerror(errno));
0223         _Nset_error_fmt(NEMALLOC, "Failed to malloc %d bytes (func lcf cmd hash): %s",
0224                 sizeof(ndrx_lcf_reg_funch_t), strerror(errno));
0225         EXFAIL_OUT(ret);
0226     }
0227     
0228     memcpy(&h->cfunc, cfunc, sizeof(ndrx_lcf_reg_func_t));
0229     h->command = cfunc->command;
0230     
0231     MUTEX_LOCK_V(M_lcf_run);
0232     EXHASH_ADD_INT(M_funcs, command, h);
0233     MUTEX_UNLOCK_V(M_lcf_run);
0234     
0235 out:
0236     return ret;
0237 }
0238 
0239 /**
0240  * Load the LCF settings. Attach semaphores and shared memory.
0241  * - So we will re-use the same system-v sempahore array used for System-V queues
0242  *  with slot 2 used for LCF
0243  * - Add new shared memory block for LCF commands and general real time settings
0244  *  like current page of DDR routing data
0245  * We need early logging here, because once debug flag is open, the LCF is ready
0246  * to start to consume the commands.
0247  * @return EXSUCCEED/EXFAIL
0248  */
0249 expublic int ndrx_lcf_init(void)
0250 {
0251     int ret = EXSUCCEED;
0252     char *tmp;
0253     size_t sz;
0254     ndrx_lcf_reg_func_t creg;
0255     
0256     memset(&ndrx_G_libnstd_cfg, 0, sizeof(ndrx_G_libnstd_cfg));
0257     
0258     tmp = getenv(CONF_NDRX_LCFNORUN);
0259     
0260     if (NULL!=tmp && (tmp[0]=='y' || tmp[0]=='Y'))
0261     {
0262         ndrx_G_libnstd_cfg.lcf_norun=EXTRUE;
0263     }
0264     else
0265     {
0266         ndrx_G_libnstd_cfg.lcf_norun=EXFALSE;
0267     }
0268     
0269     
0270    /* Load some minimum env for shared mem processing */
0271     ndrx_G_libnstd_cfg.qprefix = getenv(CONF_NDRX_QPREFIX);
0272     if (NULL==ndrx_G_libnstd_cfg.qprefix)
0273     {
0274         /* Write to ULOG? */
0275         NDRX_LOG_EARLY(log_info, "Missing config key %s", CONF_NDRX_QPREFIX);
0276         EXFAIL_OUT(ret);
0277     }
0278     
0279     NDRX_LOG_EARLY(log_info, "%s set to %s", CONF_NDRX_QPREFIX, 
0280             ndrx_G_libnstd_cfg.qprefix);
0281 
0282     /* Read maximum number of singleton groups */
0283     tmp = getenv(CONF_NDRX_PGMAX);
0284     if (NULL==tmp)
0285     {
0286         ndrx_G_libnstd_cfg.pgmax = PGMAX_DFLT;
0287     }
0288     else
0289     {
0290         ndrx_G_libnstd_cfg.pgmax = atol(tmp);
0291     }
0292 
0293     if (ndrx_G_libnstd_cfg.pgmax > PGMAX_MAX)
0294     {
0295         NDRX_LOG_EARLY(log_error, "%s value %d exceeds hard limit %d, defaulting to %d",
0296             CONF_NDRX_PGMAX, ndrx_G_libnstd_cfg.pgmax, PGMAX_MAX, PGMAX_MAX);
0297         ndrx_G_libnstd_cfg.pgmax=PGMAX_MAX;
0298     }
0299 
0300     NDRX_LOG_EARLY(log_info, "%s set to %d", CONF_NDRX_PGMAX,
0301             ndrx_G_libnstd_cfg.pgmax);
0302 
0303     /* Read the SG refresh time */
0304     tmp = getenv(CONF_NDRX_SGREFRESH);
0305     if (NULL==tmp)
0306     {
0307         ndrx_G_libnstd_cfg.sgrefreshmax = SGMREFRESHMAX_DFLT;
0308     }
0309     else
0310     {
0311         ndrx_G_libnstd_cfg.sgrefreshmax = atol(tmp);
0312     }
0313 
0314     NDRX_LOG_EARLY(log_debug, "%s set to %d", CONF_NDRX_SGREFRESH, 
0315             ndrx_G_libnstd_cfg.sgrefreshmax);
0316 
0317     /* get number of concurrent threads */
0318     tmp = getenv(CONF_NDRX_SVQREADERSMAX);
0319     if (NULL==tmp)
0320     {
0321         ndrx_G_libnstd_cfg.svqreadersmax = MAX_READERS_DFLT;
0322     }
0323     else
0324     {
0325         ndrx_G_libnstd_cfg.svqreadersmax = atol(tmp);
0326     }
0327     NDRX_LOG_EARLY(log_info, "%s set to %d", CONF_NDRX_SVQREADERSMAX, 
0328             ndrx_G_libnstd_cfg.svqreadersmax);
0329     
0330     /* get number of concurrent threads */
0331     tmp = getenv(CONF_NDRX_LCFREADERSMAX);
0332     if (NULL==tmp)
0333     {
0334         ndrx_G_libnstd_cfg.lcfreadersmax = MAX_LCFREADERS_DFLT;
0335     }
0336     else
0337     {
0338         ndrx_G_libnstd_cfg.lcfreadersmax = atol(tmp);
0339     }
0340     NDRX_LOG_EARLY(log_info, "%s set to %d", CONF_NDRX_LCFREADERSMAX, 
0341             ndrx_G_libnstd_cfg.lcfreadersmax);
0342     
0343     /* Max number of LCF commands */
0344     tmp = getenv(CONF_NDRX_LCFMAX);
0345     if (NULL==tmp)
0346     {
0347         ndrx_G_libnstd_cfg.lcfmax = MAX_LCFMAX_DFLT;
0348     }
0349     else
0350     {
0351         ndrx_G_libnstd_cfg.lcfmax = atol(tmp);
0352     }
0353     NDRX_LOG_EARLY(log_info, "%s set to %d", CONF_NDRX_LCFMAX, 
0354             ndrx_G_libnstd_cfg.lcfmax);
0355     
0356     /* get queues max */
0357     tmp = getenv(CONF_NDRX_MSGQUEUESMAX);
0358     if (NULL==tmp)
0359     {
0360         ndrx_G_libnstd_cfg.queuesmax = MAX_QUEUES_DLFT;
0361         NDRX_LOG_EARLY(log_info, "Missing config key %s - defaulting to %d", 
0362                 CONF_NDRX_MSGQUEUESMAX, ndrx_G_libnstd_cfg.queuesmax);
0363     }
0364     else
0365     {
0366         ndrx_G_libnstd_cfg.queuesmax = atol(tmp);
0367     }
0368     NDRX_LOG_EARLY(log_info, "%s set to %d", CONF_NDRX_MSGQUEUESMAX, 
0369             ndrx_G_libnstd_cfg.queuesmax);
0370     
0371     /* Get SV5 IPC */
0372     tmp = getenv(CONF_NDRX_IPCKEY);
0373     if (NULL==tmp)
0374     {
0375         /* Write to ULOG? */
0376         NDRX_LOG_EARLY(log_info, "Missing config key %s - FAIL", CONF_NDRX_IPCKEY);
0377         EXFAIL_OUT(ret);
0378     }
0379     else
0380     {
0381         int tmpkey;
0382         
0383         sscanf(tmp, "%x", &tmpkey);
0384         ndrx_G_libnstd_cfg.ipckey = tmpkey;
0385 
0386         NDRX_LOG_EARLY(log_info, "(sysv queues): SystemV IPC Key set to: [%x]",
0387                             ndrx_G_libnstd_cfg.ipckey);
0388     }
0389     
0390     /* LCF Startup expiry for published commands (seconds) */
0391     tmp = getenv(CONF_NDRX_LCFCMDEXP);
0392     if (NULL==tmp)
0393     {
0394         ndrx_G_libnstd_cfg.startcmdexp = MAX_LCFSTARTMAX_DFLT;
0395     }
0396     else
0397     {
0398         ndrx_G_libnstd_cfg.startcmdexp = atol(tmp);
0399     }
0400     NDRX_LOG_EARLY(log_info, "%s set to %d", CONF_NDRX_LCFCMDEXP, 
0401             ndrx_G_libnstd_cfg.startcmdexp);
0402     
0403     
0404     /* Open up settings shared memory... */
0405     NDRX_LOG_EARLY(log_info, "Opening LCF shared memory...");
0406     
0407     /* We always create, thus if nstd library is loaded, we open semaphore
0408      * attach to settings memory
0409      */
0410     M_lcf_shm.fd = EXFAIL;
0411     M_lcf_shm.key = ndrx_G_libnstd_cfg.ipckey + NDRX_SHM_LCF_KEYOFSZ;
0412     
0413     /* calculate the size of the LCF */
0414     M_lcf_shm.size = sizeof(ndrx_lcf_shmcfg_t) 
0415         /* LCF command segment */
0416         + sizeof(ndrx_lcf_command_t) * ndrx_G_libnstd_cfg.lcfmax 
0417         /*  Singleton group segment */
0418         + sizeof(ndrx_sg_shm_t) * ndrx_G_libnstd_cfg.pgmax;
0419     
0420     snprintf(M_lcf_shm.path,  sizeof(M_lcf_shm.path), NDRX_SHM_LCF,  ndrx_G_libnstd_cfg.qprefix);
0421     
0422     if (EXSUCCEED!=ndrx_shm_open(&M_lcf_shm, EXTRUE))
0423     {
0424         /* cannot attach if settings are different */
0425         NDRX_LOG_EARLY(log_error, "Failed to attach to LCF memory");
0426         userlog("Failed to open LCF shared memory - possibly changed "
0427                 "NDRX_LCFMAX, thus use xadmin down -y to restart the app");
0428         EXFAIL_OUT(ret);
0429     }
0430     
0431     M_lcf_sem.key = ndrx_G_libnstd_cfg.ipckey + NDRX_SEM_LCFLOCKS;
0432     
0433     /*
0434      * Currently using single semaphore.
0435      * But from balancing when searching entries, we could use multiple sems.. 
0436      * to protect both shared mems...
0437      * If we use different two sems one for p2s and another for s2p we could
0438      * easily run into deadlock. Semop allows atomically work with multiple
0439      * semaphores, so maybe this can be used to increase performance.
0440      */
0441     M_lcf_sem.nrsems = 1;
0442     M_lcf_sem.maxreaders = ndrx_G_libnstd_cfg.lcfreadersmax;
0443     
0444     if (EXSUCCEED!=ndrx_sem_open(&M_lcf_sem, EXTRUE))
0445     {
0446         NDRX_LOG_EARLY(log_error, "Failed to open LCF semaphore");
0447         EXFAIL_OUT(ret);
0448     }
0449     
0450     sz = sizeof(ndrx_lcf_command_seen_t)*ndrx_G_libnstd_cfg.lcfmax;
0451      
0452     M_locl_lcf = NDRX_FPMALLOC(sz, 0);
0453     
0454     if (NULL==M_locl_lcf)
0455     {
0456         NDRX_LOG_EARLY(log_error, "Failed to malloc local LCF storage (%d bytes): %s",
0457                 sz, strerror(errno));
0458         EXFAIL_OUT(ret);
0459     }
0460     
0461     /* default init... */
0462     memset(M_locl_lcf, 0, sz);
0463     
0464     /* assign the mem -> do as last step, as in case of LCF failure, we
0465      * ignore the condition
0466      */
0467     ndrx_G_shmcfg = (ndrx_lcf_shmcfg_t*)M_lcf_shm.mem;
0468     
0469     /* swap the pointers --> This aspect makes as to have G_ndrx_debug_first in
0470      * debug macros
0471      * as otherwise we could just relay on shm config version */
0472     ndrx_G_shmcfg_ver = (ndrx_lcf_shmcfg_ver_t*)M_lcf_shm.mem;
0473     
0474     /* register standard callbacks */
0475     
0476     memset(&creg, 0, sizeof(creg));
0477     
0478     creg.version=NDRX_LCF_CCMD_VERSION;
0479     creg.pf_callback=ndrx_lcf_logrotate;
0480     creg.command=NDRX_LCF_CMD_LOGROTATE;
0481     NDRX_STRCPY_SAFE(creg.cmdstr, NDRX_LCF_CMDSTR_LOGROTATE);
0482     
0483     ndrx_lcf_func_add_int(&creg);
0484     
0485     memset(&creg, 0, sizeof(creg));
0486     
0487     
0488     creg.version=NDRX_LCF_CCMD_VERSION;
0489     creg.pf_callback=ndrx_lcf_logchg;
0490     creg.command=NDRX_LCF_CMD_LOGCHG;
0491     NDRX_STRCPY_SAFE(creg.cmdstr, NDRX_LCF_CMDSTR_LOGCHG);
0492     
0493     ndrx_lcf_func_add_int(&creg);
0494     
0495     if (EXSUCCEED!=ndrx_sg_init())
0496     {
0497         NDRX_LOG_EARLY(log_error, "Singleton group init failed");
0498         EXFAIL_OUT(ret);
0499     }
0500 
0501 out:
0502     
0503     if (EXSUCCEED!=ret)
0504     {
0505         /* We do not run also... */
0506         ndrx_G_libnstd_cfg.lcf_norun=EXTRUE;
0507     }
0508     
0509     return ret;    
0510 }
0511 
0512 /**
0513  * Process all relevant CLF commands
0514  * and save the results
0515  * @return EXSUCCEED/EXFAIL
0516  */
0517 expublic int ndrx_lcf_run(void)
0518 {
0519     int ret = EXSUCCEED;
0520     long flags;
0521     int i;
0522     long apply;
0523     ndrx_lcf_command_t *cur;
0524     char tmpbuf[32];
0525     long cmdage;
0526     ndrx_lcf_reg_funch_t* cbfunc;
0527     ndrx_lcf_command_t cmd_tmp;
0528     
0529     /* avoid run by other threads..., thus lock them, but as already
0530      * as possible we update the shared memory version so that threads
0531      * does not stuck here, but do the work instead
0532      */
0533     MUTEX_LOCK_V(M_lcf_run);
0534     
0535     /* If we get here. */
0536     if (ndrx_G_libnstd_cfg.lcf_norun)
0537     {
0538         /* If we get inconsistent readings (i.e not atomic), at the next run
0539          * they will be set to latest value
0540          */
0541         ndrx_G_shmcfgver_chk=ndrx_G_shmcfg_ver->shmcfgver_lcf;
0542         goto out;
0543     }
0544 
0545     if (ndrx_G_shmcfgver_chk==ndrx_G_shmcfg_ver->shmcfgver_lcf)
0546     {
0547         goto out;
0548     }
0549     
0550     if (EXSUCCEED!=ndrx_sem_rwlock(&M_lcf_sem, 0, NDRX_SEM_TYP_READ))
0551     {
0552         EXFAIL_OUT(ret);
0553     }
0554     
0555     /* mark the current version, not other threads will not pass to this func */
0556     ndrx_G_shmcfgver_chk=ndrx_G_shmcfg_ver->shmcfgver_lcf;
0557     
0558     for (i=0; i<ndrx_G_libnstd_cfg.lcfmax; i++)
0559     {
0560         if (ndrx_G_shmcfg->commands[i].cmdversion!=M_locl_lcf[i].cmdversion ||
0561               ndrx_G_shmcfg->commands[i].command !=M_locl_lcf[i].command ||
0562                 0!=ndrx_stopwatch_diff(& ndrx_G_shmcfg->commands[i].publtim, &M_locl_lcf[i].publtim)
0563                 )
0564         {
0565             cur = &ndrx_G_shmcfg->commands[i];
0566 
0567             apply = 0;
0568             /* Does affect us ? */
0569             if (cur->flags & NDRX_LCF_FLAG_ALL)
0570             {
0571                 apply=EXTRUE;
0572             }
0573             else if (cur->flags & NDRX_LCF_FLAG_PID)
0574             {
0575                 
0576                 /* test the pid regex */
0577                 if (cur->flags & NDRX_LCF_FLAG_DOREX)
0578                 {
0579                     snprintf(tmpbuf, sizeof(tmpbuf), "%d", (int)getpid());
0580                     if (EXSUCCEED==ndrx_regqexec(cur->procid, tmpbuf))
0581                     {
0582                         apply++;
0583                     }
0584                 }
0585                 else
0586                 {
0587                     pid_t pp = (pid_t)atoi (cur->procid);
0588                     
0589                     if (pp==getpid())
0590                     {
0591                         apply++;
0592                     }
0593                 }
0594             }
0595             else if (cur->flags & NDRX_LCF_FLAG_BIN)
0596             {
0597                 /* test the binary regex */
0598                 
0599                 if (cur->flags & NDRX_LCF_FLAG_DOREX)
0600                 {                    
0601                     if (EXSUCCEED==ndrx_regqexec(cur->procid, EX_PROGNAME))
0602                     {
0603                         apply++;
0604                     }
0605                 }
0606                 else if (0==strcmp(cur->procid, EX_PROGNAME))
0607                 {
0608                     apply++;
0609                 }
0610             }
0611             
0612             /* stage 2 filter: */
0613             cmdage = ndrx_stopwatch_get_delta_sec(&cur->publtim);
0614             
0615             if (M_startup_run)
0616             {
0617                 if ( (cur->flags & NDRX_LCF_FLAG_DOSTARTUPEXP) && 
0618                     cmdage <= ndrx_G_libnstd_cfg.startcmdexp)
0619                 {
0620                     apply++;
0621                 }
0622                 else if (cur->flags & NDRX_LCF_FLAG_DOSTARTUP)
0623                 {
0624                     apply++;
0625                 }
0626             }
0627             else
0628             {
0629                 apply++;
0630             }
0631             
0632             if (2==apply && NULL!=(cbfunc =ndrx_lcf_func_find_int(cur->command, EXFALSE)))
0633             {
0634                 apply++;
0635             }
0636             
0637             /* write the log only if startup & apply */
0638             
0639             if (apply==3)
0640             {
0641                 NDRX_LOG(log_debug, "LCF: Slot %d changed command code %d (%s) version %u "
0642                         "apply: %d flags: 0x%lx age: %ld apply: %d (%s)", 
0643                         i, cur->command, cur->cmdstr, cur->version, apply, 
0644                         cur->flags, cmdage, apply, apply==3?"apply":"ignore");
0645             }
0646             
0647             if (apply==3)
0648             {
0649                 /* lookup for command code... & exec */    
0650                 
0651                 memcpy(&cmd_tmp, cur, sizeof(cmd_tmp));
0652                 
0653                 flags=0;
0654                 if (EXSUCCEED!=cbfunc->cfunc.pf_callback(&cmd_tmp, &flags))
0655                 {
0656                     NDRX_ATOMIC_ADD(&cur->failed, 1);
0657                 }
0658                 else
0659                 {
0660                     NDRX_ATOMIC_ADD(&cur->applied, 1);
0661                 }
0662                 
0663                 /* load the responses, if any: */
0664                 if (flags & NDRX_LCF_FLAG_FBACK_CODE)
0665                 {
0666                     cur->fbackcode = cmd_tmp.fbackcode;
0667                 }
0668                 
0669                 if (flags & NDRX_LCF_FLAG_FBACK_MSG)
0670                 {
0671                     cmd_tmp.fbackmsg[NDRX_LCF_FEEDBACK_BUF-1]=EXEOS;
0672                     NDRX_STRCPY_SAFE(cur->fbackmsg, cmd_tmp.fbackmsg);
0673                 }
0674             }
0675             else
0676             {
0677                 NDRX_ATOMIC_ADD(&cur->seen, 1);
0678             }
0679             
0680             /* mark command as processed */
0681             M_locl_lcf[i].cmdversion = cur->cmdversion;
0682             M_locl_lcf[i].command = cur->command;
0683             M_locl_lcf[i].publtim = cur->publtim;
0684         }
0685     }
0686     
0687     if (EXSUCCEED!=ndrx_sem_rwunlock(&M_lcf_sem, 0, NDRX_SEM_TYP_READ))
0688     {
0689         EXFAIL_OUT(ret);
0690     }
0691     
0692 out:
0693                             
0694                             
0695     M_startup_run=EXFALSE;
0696     
0697     MUTEX_UNLOCK_V(M_lcf_run);
0698     
0699     return ret;
0700 }
0701 
0702 /**
0703  * Detach and remove resources
0704  */
0705 expublic int ndrx_lcf_down(void)
0706 {
0707     int ret = EXSUCCEED;
0708     
0709     ndrx_lcf_detach();
0710     
0711     
0712     if (EXSUCCEED!=ndrx_shm_remove(&M_lcf_shm))
0713     {
0714         ret = EXFAIL;
0715     }
0716     
0717     if (EXSUCCEED!=ndrx_sem_remove(&M_lcf_sem, EXTRUE))
0718     {
0719         ret = EXFAIL;
0720     }
0721     
0722     return ret;
0723     
0724 }
0725 
0726 /**
0727  * Once we detach, we shall close all loggers...
0728  */
0729 expublic void ndrx_lcf_detach(void)
0730 {
0731     /* process disconnects from shared settings memory
0732      * This somehow needs to be done when the debug is closed too.
0733      * Not?
0734      * So probably we need to add fork handler to close shared mem here after the
0735      * fork. Mark the debug-as non init.
0736      * Close the log file descriptors.
0737      * 
0738      * So if forked process continues to do some works, then debug-init will
0739      * start life again and attach to shm
0740      */
0741     ndrx_shm_close(&M_lcf_shm);
0742     ndrx_sem_close(&M_lcf_sem);
0743     
0744     /* de init the debug finally 
0745     ndrx_debug_force_closeall();
0746      * ? after exec shms and sems are released.
0747      * */
0748 
0749 }
0750 
0751 /**
0752  * Reopen the log handlers
0753  * @param cmd shared mem command
0754  * @param p_flags feedback flags
0755  * @return EXSUCCEED
0756  */
0757 exprivate int ndrx_lcf_logrotate(ndrx_lcf_command_t *cmd, long *p_flags)
0758 {
0759     return ndrx_debug_reopen_all();
0760 }
0761 
0762 /**
0763  * Re-configure logging on the fly
0764  * @param cmd shared mem command
0765  * @param p_flags feedback flags
0766  * @return EXSUCCEED/EXFAIL
0767  */
0768 exprivate int ndrx_lcf_logchg(ndrx_lcf_command_t *cmd, long *p_flags)
0769 {
0770     /* Update loggers to have dynamic config version
0771      * WARNING! After this all loggers will switch to process level settings
0772      */
0773     return tplogconfig_int(LOG_FACILITY_NDRX|LOG_FACILITY_UBF|LOG_FACILITY_TP, 
0774             EXFAIL, (char *)cmd->arg_a, NULL, NULL, NDRX_TPLOGCONFIG_VERSION_INC);
0775 }
0776 
0777 /**
0778  * Publish the LCF command
0779  * @param slot slot number to which command shall be applied
0780  * @param cmd fully initialized LCF command structure
0781  *  NOTE! counters must be set to zero here by caller.
0782  * @return EXSUCCEED/EXFAIL (possible issue with slot numbers)
0783  */
0784 expublic int ndrx_lcf_publish_int(int slot, ndrx_lcf_command_t *cmd)
0785 {
0786     int ret = EXSUCCEED;
0787     unsigned  cmdversion;
0788     /* check the shared mem config is LCF used at all 
0789      * If shm is not initialized, we cannot post
0790      */
0791     if (ndrx_G_shmcfg_ver==&M_ver_start)
0792     {
0793         _Nset_error_fmt(NESUPPORT, "LCF framework disabled - cannot publish command %d [%s]", 
0794                 cmd->command, cmd->cmdstr);
0795         
0796         NDRX_LOG(log_error, "LCF framework disabled - cannot publish command %d [%s]", 
0797                 cmd->command, cmd->cmdstr);
0798         EXFAIL_OUT(ret);
0799     }
0800     
0801     if (slot >=ndrx_G_libnstd_cfg.lcfmax)
0802     {
0803         _Nset_error_fmt(NELIMIT, "Invalid command slot number, max slot: %d got: %d", 
0804                 ndrx_G_libnstd_cfg.lcfmax-1, slot);
0805         EXFAIL_OUT(ret);
0806     }
0807     
0808     if (slot < 0 )
0809     {
0810         _Nset_error_fmt(NEINVAL, "Invalid command slot number, min slot: %d got: %d", 
0811                 0, slot);
0812         EXFAIL_OUT(ret);
0813     }
0814     
0815     if (EXSUCCEED!=ndrx_sem_rwlock(&M_lcf_sem, 0, NDRX_SEM_TYP_WRITE))
0816     {
0817         _Nset_error_msg(NESYSTEM, "Failed to lock lcf sem");
0818         EXFAIL_OUT(ret);
0819     }
0820     /* first have a clean memory, if publisher dies before copy data to dest
0821      * thus have full of terminator there.. 
0822      */
0823     memset(&ndrx_G_shmcfg->commands[slot], 0, sizeof(ndrx_G_shmcfg->commands[slot]));
0824     
0825     cmdversion = ndrx_G_shmcfg->commands[slot].cmdversion;
0826     memcpy(&ndrx_G_shmcfg->commands[slot], cmd, sizeof(*cmd));
0827     
0828     cmdversion++;
0829     ndrx_G_shmcfg->commands[slot].cmdversion=cmdversion;
0830     
0831     /* set the age of command, we have write lock, so no worry */
0832     ndrx_stopwatch_reset(&ndrx_G_shmcfg->commands[slot].publtim);
0833     
0834     /* finally let processes to see what we have done: */
0835     ndrx_G_shmcfg->shmcfgver_lcf++;
0836     
0837     if (EXSUCCEED!=ndrx_sem_rwunlock(&M_lcf_sem, 0, NDRX_SEM_TYP_WRITE))
0838     {
0839         EXFAIL_OUT(ret);
0840     }
0841     
0842 out:
0843     
0844     return ret;
0845 }
0846 
0847 /**
0848  * List the registered commands via callback
0849  * @param pf_callback callback function to inspect the commands
0850  */
0851 expublic void ndrx_lcf_xadmin_list(void (*pf_callback)(ndrx_lcf_reg_xadminh_t *xcmd))
0852 {
0853     ndrx_lcf_reg_xadminh_t *el, *elt;
0854     
0855     MUTEX_LOCK_V(M_lcf_run);
0856     
0857     /* loop over and do the callbacks */
0858     EXHASH_ITER(hh, M_xadmin_cmds, el, elt)
0859     {
0860         pf_callback(el);
0861     }
0862     
0863     MUTEX_UNLOCK_V(M_lcf_run);
0864     
0865 }
0866 
0867 /**
0868  * Perform read lock
0869  * @return EXSUCCEED/EXFAIL
0870  */
0871 expublic int ndrx_lcf_read_lock(void)
0872 {
0873     return ndrx_sem_rwlock(&M_lcf_sem, 0, NDRX_SEM_TYP_READ);
0874 }
0875 
0876 /**
0877  * Perform read unlock
0878  * @return EXSUCCEED/EXFAIL
0879  */
0880 expublic int ndrx_lcf_read_unlock(void)
0881 {
0882     return ndrx_sem_rwunlock(&M_lcf_sem, 0, NDRX_SEM_TYP_READ);
0883 }
0884 
0885 /**
0886  * Check is LCF supported
0887  * @return EXTRUE/EXFALSE
0888  */
0889 expublic int ndrx_lcf_supported_int(void)
0890 {
0891     int ret = EXTRUE;
0892     
0893     if (ndrx_G_shmcfg_ver==&M_ver_start)
0894     {
0895         ret=EXFALSE;
0896     }
0897     
0898 out:                            
0899     return ret;
0900 }
0901 
0902 /**
0903  * Would disable LCF processing
0904  * by switching back to local memory instead of SHM and restoring the version
0905  * numbers of LCF checks...
0906  * Note this assumes that LCF config is loaded. (i.e. some previous debug
0907  * did the pull-in)
0908  * @param ipckeybase resolve ipc key base of Enduro/X
0909  * @param q_prefix queue prefix used by app
0910  */
0911 expublic void ndrx_lcf_remove(key_t ipckeybase, char *q_prefix)
0912 {
0913     int do_reply = EXFALSE;
0914     NDRX_LOG(log_debug, "Removing LCF memory");
0915     /* Let other threads to lave the lcf runn */
0916     MUTEX_LOCK_V(M_lcf_run);
0917     
0918     ndrx_dbg_intlock_set();
0919     
0920     /* lock the debug for ptr swap */
0921     ndrx_dbg_lock();
0922     
0923     /* do not allow anybody else to get in the region, but really should
0924      * this must be last operations in xadmin down
0925      * all threads even system-v queues are terminated
0926      */
0927     G_ndrx_debug_first=EXTRUE;
0928     
0929     /* normally no other threads are expected at this point, but let it be
0930      */
0931     sched_yield();
0932     
0933     /* mask the LCF is any stuff new stuff is done */
0934     ndrx_G_shmcfg_ver=&M_ver_start;
0935     ndrx_G_shmcfgver_chk = ndrx_G_shmcfg_ver->shmcfgver_lcf;
0936     
0937     /* close the shared memory.. */
0938     ndrx_lcf_detach();
0939     
0940     /* remove lcf memory.. - re configure if the init was bad*/
0941     M_lcf_shm.key = ipckeybase + NDRX_SHM_LCF_KEYOFSZ;
0942     snprintf(M_lcf_shm.path,  sizeof(M_lcf_shm.path), NDRX_SHM_LCF,  q_prefix);
0943     
0944     ndrx_shm_remove(&M_lcf_shm);
0945     ndrx_G_shmcfg=NULL;
0946     /* remove semaphores.. */
0947     ndrx_sem_remove(&M_lcf_sem, EXTRUE);
0948      
0949     G_ndrx_debug_first=EXFALSE;
0950     
0951     ndrx_dbg_unlock();
0952     
0953     /* reply the logs finally... */
0954     ndrx_dbg_intlock_unset(&do_reply);
0955     
0956     /* to avoid deadlocks, do this ouside any load locking */
0957     if (do_reply)
0958     {
0959         ndrx_dbg_reply_memlog_all();
0960     }
0961     
0962 out:
0963     MUTEX_UNLOCK_V(M_lcf_run);
0964     
0965 }
0966 
0967 /**
0968  * Clear the LCF command blocks
0969  */
0970 expublic void ndrx_lcf_reset(void)
0971 {
0972     MUTEX_LOCK_V(M_lcf_run);
0973     
0974     /* acquire the write lock to shm... */
0975     
0976     /* if not attached, nothing todo */
0977     if (ndrx_G_shmcfg_ver==&M_ver_start)
0978     {
0979         goto out;
0980     }
0981     
0982     /* full write protect against all others...  */
0983     if (EXSUCCEED!=ndrx_sem_rwlock(&M_lcf_sem, 0, NDRX_SEM_TYP_WRITE))
0984     {
0985         goto out;
0986     }
0987     
0988     /* clean the thing... */
0989     memset(ndrx_G_shmcfg->commands, 0, sizeof(ndrx_G_shmcfg->commands[0])*ndrx_G_libnstd_cfg.lcfmax);
0990     
0991     ndrx_sem_rwunlock(&M_lcf_sem, 0, NDRX_SEM_TYP_WRITE);
0992     
0993     ndrx_G_shmcfg->use_ddr = EXFALSE;
0994     ndrx_G_shmcfg->ddr_page=0;
0995     ndrx_G_shmcfg->ddr_ver1=0;
0996     
0997 out:
0998     MUTEX_UNLOCK_V(M_lcf_run);
0999 }
1000 
1001 /* vim: set ts=4 sw=4 et smartindent: */