How do i use ev_io with mqueues? I'm trying to do the following with no luck.
#include <fcntl.h>
#include <sys/stat.h>
#include <mqueue.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "ev.h"
#define MAX_Q_SIZE 255
#define MY_QUEUE "/test_queue"
typedef struct __test_ctxt_t
{
ev_timer timeout_watcher[32];
ev_io stdin_watcher;
struct ev_loop *loop;
mqd_t mq;
int data;
}test_ctxt_t;
static test_ctxt_t *g_ctxt = NULL;
static void mq_callback(EV_P_ struct ev_io *w, int revents)
{
test_ctxt_t *ctxt = (test_ctxt_t *)w;
struct mq_attr attr;
char msg[256];
int rcvd_msg_size;
rcvd_msg_size = mq_receive(ctxt->mq, msg, MAX_Q_SIZE, NULL);
if (rcvd_msg_size >= 0)
{
msg[rcvd_msg_size] = '\0';
printf("Received: %s\n", msg);
if (strcmp(msg, "stop") == 0)
{
printf("Exiting....\n");
ev_unloop (EV_A_ EVUNLOOP_ONE);
}
}
}
static void timeout_cb1 (EV_P_ struct ev_timer *w, int revents)
{
puts ("timeout timeout_cb1");
//ev_unloop (EV_A_ EVUNLOOP_ONE);
}
static void timeout_cb2 (EV_P_ struct ev_timer *w, int revents)
{
puts ("timeout timeout_cb2");
//ev_unloop (EV_A_ EVUNLOOP_ONE);
}
static void timeout_cb3 (EV_P_ struct ev_timer *w, int revents)
{
puts ("timeout timeout_cb3");
//ev_unloop (EV_A_ EVUNLOOP_ONE);
}
int main (void)
{
struct mq_attr attr;
g_ctxt = (test_ctxt_t *)calloc(1, sizeof(test_ctxt_t));
g_ctxt->loop = ev_default_loop (0);
/* initialize the queue attributes */
attr.mq_flags = 0;
attr.mq_maxmsg = 10;
attr.mq_msgsize = 255;
g_ctxt->mq = mq_open(MY_QUEUE, O_CREAT | O_RDONLY, 0644, &attr);
if (g_ctxt->mq == -1)
{
printf("Unable to open Queue");
return -1;
}
ev_io_init(&g_ctxt->stdin_watcher, mq_callback, g_ctxt->mq, EV_READ);
ev_io_start(g_ctxt->loop, &g_ctxt->stdin_watcher);
ev_timer_init (&g_ctxt->timeout_watcher[0], timeout_cb1, 10, 0.);
ev_timer_start (g_ctxt->loop, &g_ctxt->timeout_watcher[0]);
ev_loop (g_ctxt->loop, 0);
return 0;
}
I'm able to get the timer call back but io callback is never called on sending a messsage to the queue. Is it possible to use POSIX mqueue with libev ?
There are basically three ways, how to do that:
1) On Linux platform, the message queue handler is a valid file descriptor.
Polling message queue descriptors
On Linux, a message queue descriptor is actually a file descriptor,
and can be monitored using select(2), poll(2), or epoll(7). This is
not portable.
From mq_overview man page
You can utilize ev_io watcher to listen for incoming messages.
This is LINUX specific and non-portable code.
2) You can use function mq_notify to configure a signal that will be send whenever then message queue receives a new message. This signal can be handled by a ev_signal watcher from libev.
This seems to be more portable code but due to a signal interaction, the performance will be a bit lower.
See mq_notify man page.
3) Switch to datagram-oriented sockets, UNIX or network. These offer the roughly equal ability to send a message (aka datagram). You will get connectionless, best effort delivery, unreliable, message delivery service.
This approach is very portable.
Macintosh note:
There is no POSIX message queue implementation in macOS so the portability of such a code is limited in regards to this Apple platform. There is a possibility to mimic the same function on NSOperationQueue or Grand Central Dispatch but it will certainly result in a extensive amount of the work.
Related
A previous question showed code for libaudit
How to use libaudit?
but the answer is not a complete example. I added include files to create a mwe, and it doesn't work. In this case, I am monitoring a file, and expected that the monitoring function would be called back whenever the file is changed. I tried touch, and appending to the file, and nothing happens. Can anyone spot what I am doing wrong?
#include <stdio.h>
#include <libaudit.h>
#include <unistd.h>
#include <ev.h>
int fd;
void monitoring(struct ev_loop *loop, struct ev_io *io, int revents) {
struct audit_reply reply;
audit_get_reply(fd, &reply, GET_REPLY_NONBLOCKING, 0);
if (reply.type != AUDIT_EOE &&
reply.type != AUDIT_PROCTITLE &&
reply.type != AUDIT_PATH) {
printf("Event: Type=%s Message=%.*s\n",
audit_msg_type_to_name(reply.type),
reply.len,
reply.message);
}
}
int main() {
fd = audit_open();
struct audit_rule_data* rule = new audit_rule_data();
// what directory we will follow.
// audit_add_watch_dir(AUDIT_DIR, &rule, "foo");
audit_add_watch(&rule, "foo/test.txt");
// setting rule.
audit_add_rule_data(fd, rule, AUDIT_FILTER_USER, AUDIT_ALWAYS);
struct ev_io monitor;
audit_set_pid(fd, getpid(), WAIT_YES);
audit_set_enabled(fd, 1);
struct ev_loop *loop = ev_default_loop(EVFLAG_NOENV);
ev_io_init(&monitor, monitoring, fd, EV_READ);
ev_io_start(loop, &monitor);
ev_loop(loop, 0);
audit_close(fd);
return 0;
}
It turns out I forgot to run with sudo, this can only be run with root permission but it did not crash, just nothing was reported.
I have a program in c which is supposed to send and receive ipc messages through msgq.
The problem I have is that when I run msgrcv() it sets my global int msqid to 0. And of course I need it at other methods, like in a signal handler.
here is some code:
/* all the includes and some variables*/
#include "msg.h" // include the one I made
int msgQ; // global int
int main(int argc, char *argv[])
{
key = ftok("progfile", 65);
msgQ = msgget(key, 0666 | IPC_CREAT);
printf("msg queue id: %d \n", msgQ);
start_tik_tok(); // setting up the timer and the signal handler
/* irrelevant code */
void read_msgs(msgQ);
}
void read_msgs(int msgQid)
{
while (1)
{
printf("before the read local:%d goval:%d\n", msgQid, msgQ);
int ret = msgrcv(msgQid, &message, sizeof(message), 1, 0);
printf("after the read local:%d global :%d\n", msgQid, msgQ);
if (ret == -1)
/* error handling */
switch (message.action_type)
{
/* mesage handling */
}
}
void signal_handler(int signo)
{
/*I need the global int here to send some messages */
}
void start_tik_tok()
{
//timer interval for setitimer function
struct itimerval timer;
timer.it_interval.tv_sec = 1; //every 1 seconds
timer.it_interval.tv_usec = 0;
timer.it_value.tv_sec = 1; //start in 1 seconds
timer.it_value.tv_usec = 0;
//action for the signal
struct sigaction new_sa;
memset(&new_sa, 0, sizeof(new_sa));
new_sa.sa_handler = &signal_handler;
sigaction(SIGALRM, &new_sa, NULL);
setitimer(ITIMER_REAL, &timer, NULL);
}
the msg.h file:
#include <sys/msg.h>
struct msg_buff{
long mesg_type; //reciver
int sender; //sender
char action_type;
char time_tiks; //time in tiks
} message;
output:
msg queue id: 45416448
before the read local:45416448 global:45416448
after the read local:45416448 global:0
...
you can see that after I run msgrcv(), the value of msgQ turns to 0, even though I'm using a variable to pass the value to the method read_msgs().
The msgrcv function takes a pointer to a structure that starts with a "header" of type long, followed by the message data. The third argument to msgrcv, msgsz, is the size of the message data body, not including the long that's the header. So you should pass something like sizeof message - sizeof(long). By passing sizeof message, you're asking it to overflow the buffer sizeof(long) bytes, and this is clobbering some other global variable.
I found the solution, I'm not sure why is that but it solved it.
I just initialized the int from the beginning.
changed:
int msgQ; // global int
for:
int msgQ = 0; // global int
It is very strange that bufferevent_write doesn't trigger EV_READ on the partner if bufferevent_write is called in another thread.
I prepare a simplified program to reproduce the strange result.
bufferevent_write in timeout callback immediately trigger EV_READ on the partner. but bufferevent_write running in another thread doesn't immediately trigger EV_READ on the partner. instead do_read is called just before timeout event.
Could someone help fix the problem.
Thanks a lot.
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "unistd.h"
#include <event2/bufferevent.h>
#include <event2/event.h>
#define BUF_BODY "hello world\n"
void thr_fn( void * pArg )
{
struct bufferevent *pBufEv = (struct bufferevent *)pArg;
while (1)
{
// write doesn't trigger EV_READ event on the partner.
bufferevent_write(pBufEv, BUF_BODY, strlen(BUF_BODY) + 1);
printf("write\n");
sleep(5);
}
}
void do_read( struct bufferevent * pBEv, void * pArg )
{
char buff[1024];
bufferevent_read(pBEv, buff, 1024);
puts(buff);
return;
}
static void
ev_timeout_cb (evutil_socket_t sock_fd, short events, void *ctx)
{
struct bufferevent * pBufEv = (struct bufferevent * )ctx;
puts("ev_timeout_cb ...\n");
// write immediately trigger EV_READ event on the partner.
//bufferevent_write(pBufEv, BUF_BODY, strlen(BUF_BODY) + 1);
}
int main( void )
{
struct event_base * pEventBase = NULL;
struct bufferevent * aPair[2] = {NULL};
// evthread_use_pthreads();
pEventBase = event_base_new();
int nRet = bufferevent_pair_new(pEventBase, 0, aPair);
bufferevent_setcb(aPair[0], do_read, NULL, NULL, NULL);
bufferevent_enable(aPair[0], EV_READ);
pthread_t tid;
pthread_create(&tid, NULL, thr_fn, aPair[1]);
struct timeval tv = {10, 0};
evtimer_add(event_new(pEventBase, -1, EV_PERSIST, ev_timeout_cb, aPair[1]), &tv);
event_base_dispatch(pEventBase);
return 0;
}
I have to do for University a project about UDP, where i have to guarantee reliable communication; for packets, i want use timer_gettime() and timer_Settime() functions, because i can queue signals and i can associate to them a timer; in particular, struct sigevent has a field which union sigval where i can pass value to handler when signal arrived; I would like to take advantage of this passing to handler number of packets for which timer expired; I have a problem, and I've done a simple program to verify this; when I start timer, i can disarm it setting it_value of struct sigevent to 0; but data doesn't change; if I send 100 signal, header receives only data of first signal. This is my code:
#include <signal.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
int d;
void err_exit(char* str)
{
perror(str);
exit(EXIT_FAILURE);
}
void sighandler(int sig, siginfo_t *si, void *uc)
{
(void) sig;
(void) uc;
d = si->si_value.sival_int;
}
void handle_signal(struct sigaction* sa)
{
sa->sa_flags = SA_SIGINFO;
sa->sa_sigaction = sighandler;
sigemptyset(&sa->sa_mask);
if (sigaction(SIGRTMAX,sa,NULL) == -1)
err_exit("sigaction");
}
void create_timer(struct sigevent* sev,timer_t* timer_id,int i)
{
union sigval s;
s.sival_int = i;
printf("value: %d\n",i);
sev->sigev_notify = SIGEV_SIGNAL;
sev->sigev_signo = SIGRTMAX;
sev->sigev_value = s;
timer_create(CLOCK_REALTIME,sev,timer_id);
}
void set_timer(timer_t timer_id,struct itimerspec* ts)
{
if(ts == NULL)
printf("itimerspec null\n");
if (timer_settime(timer_id, 0, ts, NULL) == -1){
printf("errno code: %d\n",errno);
err_exit("timer_settime");
}
}
void initialize_timerspec(struct itimerspec* ts)
{
ts->it_value.tv_sec = 2;
ts->it_value.tv_nsec = 5;
ts->it_interval.tv_sec = 0;
ts->it_interval.tv_nsec = 0;
}
void reset_timer(timer_t timer_id, struct itimerspec* ts)
{
ts->it_value.tv_sec = 0;
ts->it_value.tv_nsec = 0;
ts->it_interval.tv_sec = 0;
ts->it_interval.tv_nsec = 0;
if (timer_settime(timer_id, 0, ts, NULL) == -1){
printf("errno code: %d\n",errno);
err_exit("timer_settime");
}
}
int main()
{
struct sigaction sa;
struct itimerspec ts[2];
struct sigevent sev[2];
timer_t timer_id[2];
handle_signal(&sa);
create_timer(sev,timer_id,0);
initialize_timerspec(ts);
set_timer(timer_id,ts);
reset_timer(timer_id,ts);
create_timer(sev + 1,timer_id + 1,1);
initialize_timerspec(ts + 1);
set_timer(timer_id,ts + 1);
printf("id1: %ju id2: %ju\n",timer_id[0],timer_id[1]);
sleep(10);
printf("d = %d\n",d);
exit(EXIT_SUCCESS);
}
I disarm first timer, and send another signal; but handler receives data associated to first signal, because it prints 0. Is there a way to send to overwrite data, sending to handler data of second signal(in this case 1)?
Actually I want to implement non-blocking timer, when the timer expires a handler will be called and will do something (for now it prints data). I google and realized that timer_create, timer_settimer are non-blocking timer. BUT still I've issue, I have to wait for my timer to expire (sleep(MAX) or while(1) {;}). But then if I'm calling my start_timer method with different "expiry" time, it should work accordingly, should not block other. e.g. here first time I'm calling timer, and expecting to call handler in 5 sec but before that 2nd call should print its data as, that interval I've given is 1sec only. And of course its not behaving same. Any idea?
#include <time.h>
#include <stdio.h>
#include <signal.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>
typedef struct _data{
char *name;
}data;
void handler(union sigval val)
{
data *data_handler = val.sival_ptr;
printf("Handler entered with value :%s\n", data_handler->name);
}
void mod_timer(timer_t timerid, struct sigevent sig, struct itimerspec in, struct itimerspec out)
{
printf("mod_timer\n");
timer_settime(timerid, 0, &in, &out);
while(1)
sleep(1);
//delete the timer.
timer_delete(timerid);
}
void start_timer(void* val, int interval)
{
int Ret;
pthread_attr_t attr;
pthread_attr_init( &attr );
struct sched_param parm;
parm.sched_priority = 255;
pthread_attr_setschedparam(&attr, &parm);
struct sigevent sig;
sig.sigev_notify = SIGEV_THREAD;
sig.sigev_notify_function = handler;
// sig.sigev_value.sival_int = val;
sig.sigev_value.sival_ptr = val;
sig.sigev_notify_attributes = &attr;
//create a new timer.
timer_t timerid;
Ret = timer_create(CLOCK_REALTIME, &sig, &timerid);
if (Ret == 0)
{
struct itimerspec in, out;
in.it_value.tv_sec = 1;
in.it_value.tv_nsec = 0;
in.it_interval.tv_sec = interval;
in.it_interval.tv_nsec = 0;
mod_timer(timerid, sig, in, out);
}
}
void main()
{
// start_timer(1, 5);
// start_timer(2, 1);
data handler_data1 = {"Handler Data 1"};
data handler_data2 = {"Handler Data 2"};
void *data1 = &handler_data1;
void *data2 = &handler_data2;
start_timer(data1, 5);
start_timer(data2, 1);
}
You can use the alarm function to generate a signal, and the signal function to specify the handler to that signal.