guowenxue
2019-06-25 0c6d37d6eb4eae9a91c7433adc7e76ba54c67c0f
add and add mqttd proc.c and main.c, set 3 threads running
1 files modified
2 files added
502 ■■■■■ changed files
mqttd/lylib/proc.c 341 ●●●●● patch | view | raw | blame | history
mqttd/lylib/proc.h 52 ●●●●● patch | view | raw | blame | history
mqttd/main.c 109 ●●●●● patch | view | raw | blame | history
mqttd/lylib/proc.c
New file
@@ -0,0 +1,341 @@
/*********************************************************************************
 *      Copyright:  (C) 2018 LingYun IoT System Studio
 *                  All rights reserved.
 *
 *       Filename:  cp_proc.c
 *    Description:  This file is the process API
 *
 *        Version:  1.0.0(11/06/2018~)
 *         Author:  Guo Wenxue <guowenxue@gmail.com>
 *      ChangeLog:  1, Release initial version on "11/06/2018 09:19:02 PM"
 *
 ********************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libgen.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "proc.h"
#include "logger.h"
st_sigproc     g_signal={0};
void proc_sighandler(int sig)
{
    switch(sig)
    {
        case SIGINT:
            log_warn("SIGINT - stopping\n");
            g_signal.stop = 1;
            break;
        case SIGTERM:
            //log_warn("SIGTERM - stopping\n");
            g_signal.stop = 1;
            break;
#if 0
        case SIGSEGV:
            log_err("SIGSEGV - stopping\n");
            if(g_signal.stop)
                exit(0);
            g_signal.stop = 1;
            break;
#endif
        case SIGPIPE:
            log_warn("SIGPIPE - warnning\n");
            g_signal.stop = 1;
            break;
        default:
            break;
    }
}
void install_proc_signal(void)
{
    struct sigaction sigact, sigign;
    log_nrml("Install default signal handler.\n");
    /*  Initialize the catch signal structure. */
    sigemptyset(&sigact.sa_mask);
    sigact.sa_flags = 0;
    sigact.sa_handler = proc_sighandler;
    /*  Setup the ignore signal. */
    sigemptyset(&sigign.sa_mask);
    sigign.sa_flags = 0;
    sigign.sa_handler = SIG_IGN;
    sigaction(SIGTERM, &sigact, 0); /*  catch terminate signal "kill" command */
    sigaction(SIGINT,  &sigact, 0); /*  catch interrupt signal CTRL+C */
    //sigaction(SIGSEGV, &sigact, 0); /*  catch segmentation faults  */
    sigaction(SIGPIPE, &sigact, 0); /*  catch broken pipe */
#if 0
    sigaction(SIGCHLD, &sigact, 0); /*  catch child process return */
    sigaction(SIGUSR2, &sigact, 0); /*  catch USER signal */
#endif
}
/* ****************************************************************************
 * FunctionName: daemonize
 * Description : Set the programe runs as daemon in background
 * Inputs      : nodir: DON'T change the work directory to / :  1:NoChange 0:Change
 *               noclose: close the opened file descrtipion or not 1:Noclose 0:Close
 * Output      : NONE
 * Return      : NONE
 * *****************************************************************************/
void daemonize(int nochdir, int noclose)
{
    int retval, fd;
    int i;
    /*  already a daemon */
    if (1 == getppid())
        return;
    /*  fork error */
    retval = fork();
    if (retval < 0) exit(1);
    /*  parent process exit */
    if (retval > 0)
        exit(0);
    /*  obtain a new process session group */
    setsid();
    if (!noclose)
    {
        /*  close all descriptors */
        for (i = getdtablesize(); i >= 0; --i)
        {
            //if (i != g_logPtr->fd)
                close(i);
        }
        /*  Redirect Standard input [0] to /dev/null */
        fd = open("/dev/null", O_RDWR);
        /* Redirect Standard output [1] to /dev/null */
        dup(fd);
        /* Redirect Standard error [2] to /dev/null */
        dup(fd);
    }
    umask(0);
    if (!nochdir)
        chdir("/");
    return;
}
/* ****************************************************************************
 * FunctionName: record_daemon_pid
 * Description : Record the running daemon program PID to the file "pid_file"
 * Inputs      : pid_file:The record PID file path
 * Output      : NONE
 * Return      : 0: Record successfully  Else: Failure
 * *****************************************************************************/
int record_daemon_pid(const char *pid_file)
{
    struct stat fStatBuf;
    int fd = -1;
    int mode = S_IROTH | S_IXOTH | S_IRGRP | S_IXGRP | S_IRWXU;
    char ipc_dir[64] = { 0 };
    strncpy(ipc_dir, pid_file, 64);
    /* dirname() will modify ipc_dir and save the result */
    dirname(ipc_dir);
    /* If folder pid_file PATH doesnot exist, then we will create it" */
    if (stat(ipc_dir, &fStatBuf) < 0)
    {
        if (mkdir(ipc_dir, mode) < 0)
        {
            log_fatal("cannot create %s: %s\n", ipc_dir, strerror(errno));
            return -1;
        }
        (void)chmod(ipc_dir, mode);
    }
    /*  Create the process running PID file */
    mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
    if ((fd = open(pid_file, O_RDWR | O_CREAT | O_TRUNC, mode)) >= 0)
    {
        char pid[PID_ASCII_SIZE];
        snprintf(pid, sizeof(pid), "%u\n", (unsigned)getpid());
        write(fd, pid, strlen(pid));
        close(fd);
        log_dbg("Record PID<%u> to file %s.\n", getpid(), pid_file);
    }
    else
    {
        log_fatal("cannot create %s: %s\n", pid_file, strerror(errno));
        return -1;
    }
    return 0;
}
/* ****************************************************************************
 * FunctionName: get_daemon_pid
 * Description : Get the daemon process PID from the PID record file "pid_file"
 * Inputs      : pid_file: the PID record file
 * Output      : NONE
 * Return      : pid_t: The daemon process PID number
 * *****************************************************************************/
pid_t get_daemon_pid(const char *pid_file)
{
    FILE *f;
    pid_t pid;
    if ((f = fopen(pid_file, "rb")) != NULL)
    {
        char pid_ascii[PID_ASCII_SIZE];
        (void)fgets(pid_ascii, PID_ASCII_SIZE, f);
        (void)fclose(f);
        pid = atoi(pid_ascii);
    }
    else
    {
        log_fatal("Can't open PID record file %s: %s\n", pid_file, strerror(errno));
        return -1;
    }
    return pid;
}
/* ****************************************************************************
 * FunctionName: check_daemon_running
 * Description : Check the daemon program already running or not
 * Inputs      : pid_file: The record running daemon program PID
 * Output      : NONE
 * Return      : 1: The daemon program alread running   0: Not running
 * *****************************************************************************/
int check_daemon_running(const char *pid_file)
{
    int retVal = -1;
    struct stat fStatBuf;
    retVal = stat(pid_file, &fStatBuf);
    if (0 == retVal)
    {
        pid_t pid = -1;
        printf("PID record file \"%s\" exist.\n", pid_file);
        pid = get_daemon_pid(pid_file);
        if (pid > 0)  /*  Process pid exist */
        {
            if ((retVal = kill(pid, 0)) == 0)
            {
                printf("Program with PID[%d] seems running.\n", pid);
                return 1;
            }
            else   /* Send signal to the old process get no reply. */
            {
                printf("Program with PID[%d] seems exit.\n", pid);
                remove(pid_file);
                return 0;
            }
        }
        else if (0 == pid)
        {
            printf("Can not read program PID form record file.\n");
            remove(pid_file);
            return 0;
        }
        else  /* Read pid from file "pid_file" failure */
        {
            printf("Read record file \"%s\" failure, maybe program still running.\n", pid_file);
            return 1;
        }
    }
    return 0;
}
/* ****************************************************************************
 * FunctionName: set_daemon_running
 * Description : Set the programe running as daemon if it's not running and record
 *               its PID to the pid_file.
 * Inputs      : pid_file: The record running daemon program PID
 * Output      : NONE
 * Return      : 0: Successfully. 1: Failure
 * *****************************************************************************/
int set_daemon_running(const char *pid_file)
{
    daemonize(0, 1);
    log_nrml("Program running as daemon [PID:%d].\n", getpid());
    if (record_daemon_pid(pid_file) < 0)
    {
        log_fatal("Record PID to file \"%s\" failure.\n", pid_file);
        return -2;
    }
    return 0;
}
int thread_start(pthread_t * thread_id, thread_function* thread_workbody, void *thread_arg)
{
    int        retval = 0;
    pthread_attr_t thread_attr;
    /* Initialize the thread  attribute */
    retval = pthread_attr_init(&thread_attr);
    if(retval)
        return -1;
    /* Set the stack size of the thread */
    retval = pthread_attr_setstacksize(&thread_attr, 120 * 1024);
    if(retval)
        goto CleanUp;
    /* Set thread to detached state:Don`t need pthread_join */
    retval = pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
    if(retval)
        goto CleanUp;
    /* Create the thread */
    retval = pthread_create(thread_id, &thread_attr, thread_workbody, thread_arg);
    if(retval)
        goto CleanUp;
CleanUp:
    /* Destroy the  attributes  of  thread */
    pthread_attr_destroy(&thread_attr);
    return retval;
}
void exec_system_cmd(const char *format, ...)
{
    char                cmd[256];
    va_list             args;
    int                 done;
    memset(cmd, 0, sizeof(cmd));
    va_start(args, format);
    done = vsnprintf(cmd, sizeof(cmd), format, args);
    va_end(args);
    system(cmd);
}
mqttd/lylib/proc.h
New file
@@ -0,0 +1,52 @@
/********************************************************************************
 *      Copyright:  (C) 2018 LingYun IoT System Studio
 *                  All rights reserved.
 *
 *       Filename:  proc.h
 *    Description:  This head file is for Linux process API
 *
 *        Version:  1.0.0(11/06/2018~)
 *         Author:  Guo Wenxue <guowenxue@gmail.com>
 *      ChangeLog:  1, Release initial version on "11/06/2018 09:21:33 PM"
 *
 ********************************************************************************/
#ifndef __CP_PROC_H
#define __CP_PROC_H
#include <signal.h>
#define PID_ASCII_SIZE  11
typedef struct _st_sigproc
{
    int       signal;
    unsigned  stop;     /* 0: Not term  1: Stop  */
}  st_sigproc;
/* global variable for process or thread to exit  */
extern st_sigproc     g_signal;
/* install signal handler  */
extern void install_proc_signal(void);
/* record process PID into $pid_file for check_daemon_running() to check program running or not */
extern int record_daemon_pid(const char *pid_file);
/* check program already running or not
 * 1: The daemon program alread running   0: Not running
 */
extern int check_daemon_running(const char *pid_file);
/* set program running as daemon */
extern int set_daemon_running(const char *pid_file);
/* create a system command and excute it */
extern void exec_system_cmd(const char *format, ...);
/* create and start a thread to excute function pointed by $thread_workbody  */
typedef void *(thread_function) (void *thread_arg);
extern int thread_start(pthread_t * thread_id, thread_function * thread_workbody, void *thread_arg);
#endif
mqttd/main.c
@@ -15,28 +15,58 @@
#include <unistd.h>
#include "logger.h"
#include "proc.h"
#include "hal.h"
/********************************************************************************
 *  Description:
 *   Input Args:
 *  Output Args:
 * Return Value:
 ********************************************************************************/
#define DAEMON_PIDFILE             "/tmp/.mqtt.pid"
typedef struct mqtt_ctx_s
{
    int        conf;
} mqtt_ctx_t;
int check_set_program_running(int daemon);
void *mqtt_sub_worker(void *args);
void *mqtt_pub_worker(void *args);
int main (int argc, char **argv)
{
    float              temp;
    float              rh;
    int                daemon = 0;
    pthread_t          tid;
    mqtt_ctx_t         ctx;
    //if( logger_init("mqttd.log", LOG_LEVEL_DEBUG, 1024) < 0 ) 
    if( logger_init(DBG_LOG_FILE, LOG_LEVEL_DEBUG, 1024) < 0 ) 
    {
        fprintf(stderr, "Logger system initialise failure\n");
        return -1;
        return -2;
    }
    log_dbg("Logger system initialise ok\n");
    install_proc_signal();
    if( check_set_program_running(daemon) < 0 )
    {
        goto OUT;
    }
    if( thread_start(&tid, mqtt_sub_worker, &ctx ) < 0 )
    {
        log_fatal("Start MQTT subscibe worker thread failure\n");
        goto OUT;
    }
    log_dbg("Logger system initialise ok\n");
    if( thread_start(&tid, mqtt_pub_worker, &ctx) < 0 )
    {
        log_fatal("Start MQTT publish worker thread failure\n");
        goto OUT;
    }
#if 0
    if( hal_init() < 0 )
@@ -44,14 +74,75 @@
        log_err("Initialise hardware failure\n");
        return -1;
    }
    log_nrml("HAL initialise ok\n");
#endif
    
    log_nrml("HAL initialise ok\n");
    while( ! g_signal.stop )
    {
        msleep(1000);
        log_nrml("Main control thread continue running\n");
    }
OUT:
    logger_term();
    
    return 0;
} /* ----- End of main() ----- */
int check_set_program_running(int daemon)
{
    if( check_daemon_running(DAEMON_PIDFILE) )
    {
        log_err("Program already running, process exit now");
        return -1;
    }
    if( daemon )
    {
        if( set_daemon_running(DAEMON_PIDFILE) < 0 )
        {
            log_err("set program running as daemon failure\n");
            return -2;
        }
    }
    else
    {
        if( record_daemon_pid(DAEMON_PIDFILE) < 0 )
        {
            log_err("record program running PID failure\n");
            return -3;
        }
    }
    return 0;
}
void *mqtt_pub_worker(void *args)
{
    mqtt_ctx_t           *ctx = (mqtt_ctx_t *)args;
    while( !g_signal.stop )
    {
        msleep(1000);
        log_nrml("MQTT publish thread running\n");
    }
    return NULL;
}
void *mqtt_sub_worker(void *args)
{
    mqtt_ctx_t           *ctx = (mqtt_ctx_t *)args;
    while( !g_signal.stop )
    {
        msleep(1000);
        log_nrml("MQTT subscibe thread running\n");
    }
    return NULL;
}