satch.c xenomai 时间钟信号触发举例

本系统通过生产者-消费者模型实现了一个简单的音乐播放队列,利用 POSIX 消息队列和定时器实现消息的发送与接收,并通过共享内存来传递歌曲信息。

satch.c

#ifndef __XENO_SIM__
#ifndef __KERNEL__
#include <stdio.h>
#define xnarch_printf printf
#endif

#include <time.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <sys/mman.h>
#include <pthread.h>
#include <mqueue.h>
#else /* __XENO_SIM */
#include <posix/posix.h>
#endif /* __XENO_SIM */

#define CONSUMER_TASK_PRI    1
#define CONSUMER_STACK_SIZE  8192

#define PRODUCER_TASK_PRI    2
#define PRODUCER_STACK_SIZE  8192

#define CONSUMER_WAIT 150
#define PRODUCER_TRIG 40

#define MQ_NAME "/satchmq"
#define SHM_NAME "/satchshm"

void normalize(struct timespec *ts)
{
    if (ts->tv_nsec > 1000000000)
        {
        ts->tv_sec += ts->tv_nsec / 1000000000;
        ts->tv_nsec %= 1000000000;
        }

    if (ts->tv_nsec < 0)
        {
        ts->tv_sec -= (-ts->tv_nsec) / 1000000000 + 1;
        ts->tv_nsec = 1000000000 - (-ts->tv_nsec % 1000000000);
        }
}

void abort_perror(const char *pref)
{
    xnprintf("%s: %d\n", pref, errno);
    pthread_exit(NULL);
}

#ifdef PRODUCER

static const char *private_satch_s_tunes[] = {
    "Surfing With The Alien",
    "Lords of Karma",
    "Banana Mango",
    "Psycho Monkey",
    "Luminous Flesh Giants",
    "Moroccan Sunset",
    "Satch Boogie",
    "Flying In A Blue Dream",
    "Ride",
    "Summer Song",
    "Speed Of Light",
    "Crystal Planet",
    "Raspberry Jam Delta-V",
    "Champagne?",
    "Clouds Race Across The Sky",
    "Engines Of Creation"
};

static unsigned satch_s_tunes[sizeof(private_satch_s_tunes)/sizeof(char *)];
static timer_t producer_tm = (timer_t) -1;
static mqd_t producer_mq = (mqd_t) -1;
static void *producer_shm = MAP_FAILED;
static pthread_t producer_task;

void *producer (void *cookie)

{
    struct itimerspec its;
    sigset_t blocked;
    unsigned pos;
    int next_msg;

    /* Copy the strings to shared memory. */
    pos = 0;
    for (next_msg = 0;
         next_msg < sizeof(private_satch_s_tunes)/sizeof(char *);
         next_msg++)
        {
        const char *msg = private_satch_s_tunes[next_msg];
        size_t len = strlen(msg) + 1;
        memcpy(producer_shm + pos, msg, len);
        satch_s_tunes[next_msg] = pos;
        pos += len;
        }
    next_msg = 0;

    sigemptyset(&blocked);
    sigaddset(&blocked, SIGRTMIN+1);
    pthread_sigmask(SIG_BLOCK, &blocked, NULL);

    its.it_value.tv_sec = 0;
    its.it_value.tv_nsec = 10000000 * PRODUCER_TRIG;
    normalize(&its.it_value);
    its.it_interval.tv_sec = 0;
    its.it_interval.tv_nsec = 0;
    normalize(&its.it_interval);

    for (;;)
      {
        unsigned msg_off;
        siginfo_t si;
        int nchar;

        if (timer_settime(producer_tm, 0, &its, NULL))
            abort_perror("timer_settime");
        while (sigwaitinfo(&blocked, &si) == -1 && errno == EINTR)
            ;

      msg_off = satch_s_tunes[next_msg++];
      next_msg %= (sizeof(satch_s_tunes) / sizeof(satch_s_tunes[0]));

        do 
            {
            nchar = mq_send(producer_mq, (char *)&msg_off, sizeof(msg_off), 0);
            }
        while (nchar == -1 && errno == EINTR);

        if (nchar == -1)
            abort_perror("mq_send");
      }

    return NULL;
}

#endif /* PRODUCER */

#ifdef CONSUMER

static timer_t consumer_tm = (timer_t) -1;
static mqd_t consumer_mq = (mqd_t) -1;
static void *consumer_shm = MAP_FAILED;
static pthread_t consumer_task;

void *consumer (void *cookie)

{
    struct itimerspec its;
    sigset_t blocked;
    
    sigemptyset(&blocked);
    sigaddset(&blocked, SIGALRM);
    pthread_sigmask(SIG_BLOCK, &blocked, NULL);

    its.it_value.tv_sec = 0;
    its.it_value.tv_nsec = CONSUMER_WAIT * 10000000; /* 10 ms */
    normalize(&its.it_value);
    its.it_interval.tv_sec = 0;
    its.it_interval.tv_nsec = CONSUMER_WAIT * 10000000;
    normalize(&its.it_interval);

    if(timer_settime(consumer_tm, 0, &its, NULL))
        abort_perror("timer_settime");

    for (;;)
      {
        siginfo_t si;
        while (sigwaitinfo(&blocked, &si) == -1 && errno == EINTR)
            ;

        for (;;)
          {
            unsigned prio;
            unsigned msg;
            int nchar;

            do 
                {
                nchar = mq_receive(consumer_mq,(char *)&msg, sizeof(msg), &prio);
                }
            while (nchar == -1 && errno == EINTR);
            
            if (nchar == -1 && errno == EAGAIN)
                break;

            if (nchar == -1)
                abort_perror("mq_receive");

          printf("Now playing %s...\n",(char *) consumer_shm + msg);
          }
      }

    return NULL;
}

#endif /* CONSUMER */

void __xeno_user_exit (void)

{
#ifdef PRODUCER
    if (producer_task)
        {
        pthread_cancel(producer_task);
        pthread_join(producer_task, NULL);
        }
    if (producer_tm != (timer_t) -1)
        timer_delete(producer_tm);
    if (producer_mq != (mqd_t) -1)
        mq_close(producer_mq);
    mq_unlink(MQ_NAME);
    if (producer_shm != MAP_FAILED)
        munmap(producer_shm, 65536);
    shm_unlink(SHM_NAME);
#endif /* PRODUCER */

#ifdef CONSUMER
    if (consumer_task)
        {
        pthread_cancel(consumer_task);
        pthread_join(consumer_task, NULL);
        }
    if (consumer_tm != (timer_t) -1)
        timer_delete(consumer_tm);
    if (consumer_mq != (mqd_t) -1)
        mq_close(consumer_mq);
    if (consumer_shm != MAP_FAILED)
        munmap(consumer_shm, 65536);
#endif /* CONSUMER */
}

int __xeno_user_init (void)

{
    struct sched_param parm;
    pthread_attr_t attr;
    int rc = 0, fd = -1;
    struct mq_attr mattr;
    struct sigevent evt;

    fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0777);
    if (fd == -1)
        {
        xnprintf("shm_open: %d\n", errno);
        return -errno;
        }

    if (ftruncate(fd, 65536))
        {
        xnprintf("ftruncate: %d\n", errno);
        goto out;
        }

    pthread_attr_init(&attr);
    pthread_attr_setinheritsched(&attr, 1);
    pthread_attr_setschedpolicy(&attr, SCHED_FIFO);

#ifdef PRODUCER
    mattr.mq_maxmsg = 30;
    mattr.mq_msgsize = sizeof(unsigned);
    producer_mq = mq_open(MQ_NAME, O_CREAT| O_EXCL| O_WRONLY, 0, &mattr);
    if (producer_mq == (mqd_t) -1)
        {
      if (errno == EEXIST)
          {
          xnprintf("Satch: producer module is already running, please "
                 "only launch one producer instance.\n");
          goto out;
          }

        xnprintf("mq_open(producer_mq): %d\n", errno);
        goto out;
        }
    
    producer_shm = mmap(NULL, 65536, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (producer_shm == MAP_FAILED)
        {
        xnprintf("mmap(producer_shm): %d\n", errno);
        return -errno;
        }

    evt.sigev_notify = SIGEV_SIGNAL;
    evt.sigev_signo = SIGRTMIN+1;
    evt.sigev_value.sival_ptr = &producer_tm;
    if (timer_create(CLOCK_REALTIME, &evt, &producer_tm))
        {
        xnprintf("timer_create(producer_tm): %d\n", errno);
        goto out;
        }

    pthread_attr_setstacksize(&attr, PRODUCER_STACK_SIZE);
    parm.sched_priority = PRODUCER_TASK_PRI;
    pthread_attr_setschedparam(&attr, &parm);
    rc = pthread_create(&producer_task, &attr, &producer, NULL);

    if (rc)
        {
        xnprintf("pthread_create(producer_task): %d\n", rc);
        goto out;
        }
#endif /* PRODUCER */

#ifdef CONSUMER
    mattr.mq_maxmsg = 30;
    mattr.mq_msgsize = sizeof(unsigned);
    consumer_mq = mq_open(MQ_NAME, O_NONBLOCK| O_RDONLY, 0, &mattr);
    if (consumer_mq == (mqd_t) -1)
        {
      if (errno == ENOENT)
          {
          xnprintf("Satch: producer module not running, please launch producer"
                 " module before\nlaunching consumer application.\n");
          goto out;
          }

        xnprintf("mq_open(consumer_mq): %d\n", errno);
        goto out;
        }

    consumer_shm = mmap(NULL, 65536, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (consumer_shm == MAP_FAILED)
        {
        xnprintf("mmap(consumer_shm): %d\n", errno);
        goto out;
        }

    evt.sigev_notify = SIGEV_SIGNAL;
    evt.sigev_signo = SIGALRM;
    evt.sigev_value.sival_ptr = &consumer_tm;
    if(timer_create(CLOCK_REALTIME, &evt, &consumer_tm))
        {
        xnprintf("timer_create(consumer_tm): %d\n", errno);
        goto out;
        }

    pthread_attr_setstacksize(&attr, CONSUMER_STACK_SIZE);
    parm.sched_priority = CONSUMER_TASK_PRI;
    pthread_attr_setschedparam(&attr, &parm);
    rc = pthread_create(&consumer_task, &attr, &consumer, NULL);
    if (rc)
        {
        xnprintf("pthread_create(consumer_task): %d\n", rc);
        goto out;
        }
#endif /* CONSUMER */

    if (close(fd))
        {
        xnprintf("close: %d\n", errno);
        rc = -errno;
      goto err;
        }

    return 0;

  out:
    rc = -rc ?: -errno;
    if (close(fd))
          
        xnprintf("close: %d\n", errno);
  err:
    __xeno_user_exit();
    return rc;
}

#ifdef __KERNEL__
MODULE_AUTHOR("gilles.chanteperdrix@xenomai.org");
MODULE_LICENSE("GPL");
module_init(__xeno_user_init);
module_exit(__xeno_user_exit);

#elif !defined(__XENO_SIM__)
int main (int ac, char *av[])

{
    sigset_t mask;
    int rc, sig;

    sigemptyset(&mask);
    sigaddset(&mask,SIGINT);
    sigaddset(&mask,SIGTERM);
    sigaddset(&mask,SIGHUP);
    sigaddset(&mask,SIGALRM);

    pthread_sigmask(SIG_BLOCK, &mask, NULL);

    mlockall(MCL_CURRENT|MCL_FUTURE);

    rc = __xeno_user_init();

    if (rc)
        {
        xnprintf("__xeno_user_init: %d\n", -rc);
        return -rc;
        }

    sigwait(&mask, &sig);
    __xeno_user_exit();

    return 0;
}
#endif /* !__XENO_SIM__ && !__KERNEL__ */
/* * Copyright (C) 2009 Philippe Gerum <rpm@xenomai.org>. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * * * BUFP-based client/server demo, using the read(2)/write(2) * system calls to exchange data over a socket. * * In this example, two sockets are created. A server thread (reader) * is bound to a real-time port and receives a stream of bytes sent to * this port from a client thread (writer). */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <string.h> #include <pthread.h> #include <errno.h> #include <boilerplate/ancillaries.h> #include <rtdm/ipc.h> pthread_t svtid, cltid; #define BUFP_PORT_LABEL "bufp-demo" static const char *msg[] = { "Surfing With The Alien", "Lords of Karma", "Banana Mango", "Psycho Monkey", "Luminous Flesh Giants", "Moroccan Sunset", "Satch Boogie", "Flying In A Blue Dream", "Ride", "Summer Song", "Speed Of Light", "Crystal Planet", "Raspberry Jam Delta-V", "Champagne?", "Clouds Race Across The Sky", "Engines Of Creation" }; static void fail(const char *reason) { perror(reason); exit(EXIT_FAILURE); } static void *server(void *arg) { struct rtipc_port_label plabel; struct sockaddr_ipc saddr; char buf[128]; size_t bufsz; int ret, s; s = socket(AF_RTIPC, SOCK_DGRAM, IPCPROTO_BUFP); if (s < 0) fail("socket"); /* * Set a 16k buffer for the server endpoint. This * configuration must be done prior to binding the socket to a * port. */ bufsz = 16384; /* bytes */ ret = setsockopt(s, SOL_BUFP, BUFP_BUFSZ, &bufsz, sizeof(bufsz)); if (ret) fail("setsockopt"); /* * Set a port label. This name will be registered when * binding, in addition to the port number (if given). */ strcpy(plabel.label, BUFP_PORT_LABEL); ret = setsockopt(s, SOL_BUFP, BUFP_LABEL, &plabel, sizeof(plabel)); if (ret) fail("setsockopt"); /* * Bind the socket to the port. Assign that port a label, so * that peers may use a descriptive information to locate * it. Labeled ports will appear in the * /proc/xenomai/registry/rtipc/bufp directory once the socket * is bound. * * saddr.sipc_port specifies the port number to use. If -1 is * passed, the BUFP driver will auto-select an idle port. */ saddr.sipc_family = AF_RTIPC; saddr.sipc_port = -1; ret = bind(s, (struct sockaddr *)&saddr, sizeof(saddr)); if (ret) fail("bind"); for (;;) { ret = read(s, buf, sizeof(buf)); if (ret < 0) { close(s); fail("read"); } printf("%s: received %d bytes, \"%.*s\"\n", __FUNCTION__, ret, ret, buf); } return NULL; } static void *client(void *arg) { struct rtipc_port_label plabel; struct sockaddr_ipc svsaddr; int ret, s, n = 0, len; struct timespec ts; s = socket(AF_RTIPC, SOCK_DGRAM, IPCPROTO_BUFP); if (s < 0) fail("socket"); /* * Set the port label. This name will be used to find the peer * when connecting, instead of the port number. The label must * be set _after_ the socket is bound to the port, so that * BUFP does not try to register this label for the client * port as well (like the server thread did). */ strcpy(plabel.label, BUFP_PORT_LABEL); ret = setsockopt(s, SOL_BUFP, BUFP_LABEL, &plabel, sizeof(plabel)); if (ret) fail("setsockopt"); memset(&svsaddr, 0, sizeof(svsaddr)); svsaddr.sipc_family = AF_RTIPC; svsaddr.sipc_port = -1; /* Tell BUFP to search by label. */ ret = connect(s, (struct sockaddr *)&svsaddr, sizeof(svsaddr)); if (ret) fail("connect"); for (;;) { len = strlen(msg[n]); ret = write(s, msg[n], len); if (ret < 0) { close(s); fail("write"); } printf("%s: sent %d bytes, \"%.*s\"\n", __FUNCTION__, ret, ret, msg[n]); n = (n + 1) % ARRAY_SIZE(msg); /* * We run in full real-time mode (i.e. primary mode), * so we have to let the system breathe between two * iterations. */ ts.tv_sec = 0; ts.tv_nsec = 500000000; /* 500 ms */ clock_nanosleep(CLOCK_REALTIME, 0, &ts, NULL); } return NULL; } int main(int argc, char **argv) { struct sched_param svparam = {.sched_priority = 71 }; struct sched_param clparam = {.sched_priority = 70 }; pthread_attr_t svattr, clattr; sigset_t set; int sig; sigemptyset(&set); sigaddset(&set, SIGINT); sigaddset(&set, SIGTERM); sigaddset(&set, SIGHUP); pthread_sigmask(SIG_BLOCK, &set, NULL); pthread_attr_init(&svattr); pthread_attr_setdetachstate(&svattr, PTHREAD_CREATE_JOINABLE); pthread_attr_setinheritsched(&svattr, PTHREAD_EXPLICIT_SCHED); pthread_attr_setschedpolicy(&svattr, SCHED_FIFO); pthread_attr_setschedparam(&svattr, &svparam); errno = pthread_create(&svtid, &svattr, &server, NULL); if (errno) fail("pthread_create"); pthread_attr_init(&clattr); pthread_attr_setdetachstate(&clattr, PTHREAD_CREATE_JOINABLE); pthread_attr_setinheritsched(&clattr, PTHREAD_EXPLICIT_SCHED); pthread_attr_setschedpolicy(&clattr, SCHED_FIFO); pthread_attr_setschedparam(&clattr, &clparam); errno = pthread_create(&cltid, &clattr, &client, NULL); if (errno) fail("pthread_create"); __STD(sigwait(&set, &sig)); pthread_cancel(svtid); pthread_cancel(cltid); pthread_join(svtid, NULL); pthread_join(cltid, NULL); return 0; } 用代码背景加注释逐行解释每一行在做什么
最新发布
08-23
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值