I created a message queue with following code. First few times it works properly.
int main()
{
mqd_t mqdes;
char mq_name[10] = "/mq";
int oflag = O_CREAT | O_RDWR, ret;
struct mq_attr attr;
attr.mq_maxmsg = 1024;
attr.mq_msgsize = 2048;
mqdes = mq_open(mq_name, oflag, 0766, &attr);
if(mqdes == -1) {
perror("mq_open");
if(errno == EMFILE)
perror("EMFILE");
exit(1);
}
printf("mqueue created, mq_descriptor: %d\n", mqdes);
ret = mq_close(mqdes);
if(ret == -1) {
perror("mq_close");
exit(2);
}
printf(" mq closed successful\n");
return 0;
}
After that, it's giving following error
mq_open: Too many open files
EMFILE: Too many open files
But why i'm getting this error? How can I see possix message queues like ipcs is for system V?
Try to set the resource limits:
#include <sys/resource.h>
struct rlimit rlim;
memset(&rlim, 0, sizeof(rlim));
rlim.rlim_cur = RLIM_INFINITY;
rlim.rlim_max = RLIM_INFINITY;
setrlimit(RLIMIT_MSGQUEUE, &rlim);
I had the same issue while trying something. If you have by accident too many open message queues left on your system, you can try deleting your mqueue's in directory /dev/mqueue. This worked for me.
Also you might want to use mq_unlink(const char *name) after the mq_close() to ensure that the queue is removed from the system as described here.
I had the same problem and I solved it by increasing RLIMIT_MSGQUEUE via setrlimit.
If the hard limit (rlim_max) is too low as well (which was the case for me), you will have to give your process the CAP_SYS_RESOURCE privilege so that you can set the hard limit before you set the process limit (rlim_cur). Either run $ setcap 'CAP_SYS_RESOURCE=+ep' /path/to/executable over an executable or edit /etc/security/capability.conf to give CAP_SYS_RESOURCE to a user/group.
Related
I am trying to understand the working of message queues in Linux.
Eventually, I'd want to have a program where I could send and receive stuff between different threads/processes, but to start off, I only create a message queue, and have it block on an input in a queue, but mq_receive() returns Message too long.
Looking at the documentation, this error indicates `msg_len was less than the mq_msgsize attribute of the message queue., but this isn't the case for me.
Sorry if I'm missing something obvious but I couldn't figure it out.
#define MAX_MESSAGES 10
#define MAX_MSG_SIZE 256
#define MSG_BUFFER_SIZE MAX_MSG_SIZE + 10
int main()
{
mqd_t qd_server, qd_client;
char in_buffer [MSG_BUFFER_SIZE];
char out_buffer [MSG_BUFFER_SIZE];
struct mq_attr attr, tmpAttr;
attr.mq_flags = 0;
attr.mq_maxmsg = MAX_MESSAGES;
attr.mq_msgsize = MAX_MSG_SIZE;
attr.mq_curmsgs = 0;
if ((qd_server = mq_open ("/sp-example-server", O_RDONLY|O_CREAT, 0644, &attr)) == -1)
{
printf("%s\n", strerror(errno));
}
if (mq_getattr(qd_server, &tmpAttr) == -1)
{
printf("mq_getattr error");
}
printf("Maximum # of messages on queue: %ld\n", tmpAttr.mq_maxmsg);
printf("Maximum message size: %ld\n", tmpAttr.mq_msgsize);
int iret = mq_receive(qd_server, in_buffer, sizeof(in_buffer), NULL);
if (iret == -1)
{
printf("%s\n", strerror(errno));
}
return 0;
}
Edit:
After running mmq_getattr(qd_server, & tmpAttr), it seems as if attributes were never set which probably is the cause. Now on to why are attributes not set?
// output:
Maximum # of messages on queue: 10
Maximum message size: 8192
The code you've shown us did not create the /sp-example-server message queue.
Instead, some prior process created that queue with the values you see for mq_maxmsg and mq_msgsize. If the queue's creator omitted the attribute specification — that is, passed a NULL struct mq_attr * to mq_open — then the implementation will provide default values. On Linux, these defaults match the values you see.
It seems plausible some early version of your code called mq_open with NULL attributes, and thus O_CREAT'd the queue as you are experiencing it now.
To accommodate this, you might reboot or mq_unlink the queue, forcing the next call to mq_open to re-create it. More defensively, when you do not open the queue O_EXCLusively, then use mq_getattr to validate the queue's attributes.
Problem Summary
I am writing a program that is intended to fork multiple processes, each of which open a unique message queue for receiving messages. Every time I run my program, however, every single forked process encounters the Bad address error when initializing their respective queues with mq_open.
Some Details
My code is intended to generate message queue names dynamically, following the form "/_*, where * is some unique letter (a, b, c, etc.) However, upon trying the same code with the string "/hello"put in place of the dynamically generated names, the program still failed with the same error.
This has led me to believe that the issue is a failure to create a new queue, rather than an issue with the name itself. However, I believe I am passing O_CREAT correctly, so I can't figure out what the problem is.
I did find this previous thread on the subject, but it doesn't seem that that guy was having the same problems. I believe I have included all relevant code below, but please let me know if more is needed. Any help is much appreciated!
My code
Here is the wrapper function that actually calls mq_open:
mqd_t init_queue(char *desc, long m_flags, long m_max, long m_size)
{
mqd_t mq_des;
struct mq_attr attr;
mode_t mode = 0664;
attr.mq_maxmsg = m_max;
attr.mq_msgsize = m_size;
attr.mq_flags = m_flags;
if ((mq_des = mq_open(desc, O_CREAT | O_RDWR, mode, attr)) == -1) {
perror("Error at init_queue");
exit(1);
}
return mq_des;
}
Here is the function that calls init_queue. I've pasted in the relevant macros and helper function (nid) at the top as well, so you can see those:
#define DESCPREF "/_"
#define DESCSIZE 4
#define FIRSTID 97
#define MAXMSGS 200
#define M_SIZE sizeof(struct _message)
char *nid(int id)
{
char *desc = malloc(sizeof(char) * DESCSIZE);
char c = id;
snprintf(desc, DESCSIZE, "%s%c", DESCPREF, c);
return desc;
}
int node(int id, int inc)
{
/* INIT */
proc_info me = malloc(PROCINF_SIZE);
me->id = id;
me->curr = id - FIRSTID + 1;
me->inc = inc;
char *mypath = nid(id);
me->listen = init_queue(mypath, O_NONBLOCK, MAXMSGS, M_SIZE);
/* Do some stuff ... */
close_queue(me->listen);
mq_unlink(mypath);
free(me);
return 0;
}
Finally, the bit of code that forks my individual processes:
int main(){
pid_t pid;
int nodes = TESTNODES;
for (int i = 0; i < nodes; i++) {
if ((pid = fork()) == -1) {
perror("Fork error\n");
exit(1);
} else if (pid == 0) {
node(FIRSTID + i, nodes);
exit(0);
} else {
printf("Forked: %d\n", (int) pid);
}
}
return 1;
}
Expected vs. Actual results
I would expect this code to simply run, printing the pids of forked processes, then exit. Instead I get the following errors (for one example run):
Forked: 27448
Forked: 27449
Error at init_queue: Bad address
Error at init_queue: Bad address
Forked: 27450
Error at init_queue: Bad address
Forked: 27451
Error at init_queue: Bad address
Forked: 27452
Error at init_queue: Bad address
As previously mentioned, I also tried this with the plain string "/hello" used as the input name for mq_open and received the same set of errors (all five failed in that case as well).
You need to pass the pointer to the mq_attr struct like:
if ((mq_des = mq_open(desc, O_CREAT | O_RDWR, mode, &attr)) == -1) {
perror("Error at init_queue");
exit(1);
}
also as per the manual page make sure the values for max messages and msg size make sense otherwise you will get an EINVAL.
EINVAL O_CREAT was specified in oflag, and attr was not NULL, but
attr->mq_maxmsg or attr->mq_msqsize was invalid. Both of
these fields must be greater than zero. In a process that is
unprivileged (does not have the CAP_SYS_RESOURCE capability),
attr->mq_maxmsg must be less than or equal to the msg_max
limit, and attr->mq_msgsize must be less than or equal to the
msgsize_max limit. In addition, even in a privileged process,
attr->mq_maxmsg cannot exceed the HARD_MAX limit. (See
mq_overview(7) for details of these limits.)
I want to send messages between two processes. But I get a EACCES error when im trying to send a message with msgsnd()
Creating the message queue
const char* MSG_QUEUE = "/tmp/msg_queue";
int file = open(MSG_QUEUE, O_CREAT | O_RDWR | O_APPEND, 0755);
close(file);
key_t key = ftok(MSG_QUEUE, 1);
errno = 0;
msg_queue = msgget(key, IPC_CREAT);
if(msg_queue == -1) {
M_DEBUG("Error %s\r\n", strerror(errno));
}
message struct
struct feld_msg_s {
long id;
char mtext[5];
};
sending a message
struct feld_msg_s a_msg = {1, "Test"};
errno = 0;
int ret = msgsnd(msg_queue, &a_msg, sizeof(a_msg.mtext), 0);
if(ret == -1) {
if(errno == EACCES) {
printf("\r\n NO PERMISSION\r\n");
} else {
printf("msgsnd ERROR!: %s\r\n", strerror(errno));
}
}
in the manpage of msgsnd is written
EACCES The calling process does not have read permission on the message queue, and does not have the CAP_IPC_OWNER capability.
so I've added the following capabilities with the setcap command
sudo setcap CAP_SETFCAP,CAP_IPC_OWNER+epi /home/mvollmer/build-APP-Desktop_Qt_5_6_1_GCC_64bit-Debug/APP
I've checked with getcap if the application got the capabilities. It's fine. But I still receive the No Permission Error.
When execute the application with root rights, its working!
One thing is very strange, altough msgget was succesfull ipcs dont show any message queues.
So where is my fault?
I'm using Linux Mint
Additional Question: Is is possible to use another datatype then char in the msg struct or is a message restricted to strings?
You need to read the man page. Per the POSIX msgget() standard:
SYNOPSIS
#include <sys/msg.h>
int msgget(key_t key, int msgflg); [Option End]
DESCRIPTION
...
The low-order 9 bits of msg_perm.mode shall be set to the low-order 9 bits of msgflg.
Thus, this code
msg_queue = msgget(key, IPC_CREAT);
has the "low-order 9 bits of msgflg" all set to zero. Thus the message queue mode is also all 0 - no permissions for anyone.
I'm creating a Linux module for a game library that let's you hotplug multiple joysticks, it uses inotify to watch /dev/input.
I am testing it with 3 joysticks:
First I connect 2 joysticks.
Then I start the application, the joysticks work and I don't get a error.
After that I connect the third joystick, perror gives: /dev/input/js1: Permission denied.
When I check ls -l /proc/<pid-of-process>/fd it lists /dev/input/js0 and /dev/input/js2.
All the joysticks work fine when I run it as root.
This is how it's initialized:
static void createGamepad(char *locName){
char dirName[30];
int fd;
snprintf(dirName, 30, "/dev/input/%s", locName);
fd = open(dirName, O_RDONLY | O_NONBLOCK, 0);
if(fd < 0){
perror(dirName);
}
}
struct dirent *dir;
DIR *d;
int i, notifyfd, watch;
// Attach notifications to check if a device connects/disconnects
notifyfd = inotify_init();
watch = inotify_add_watch(notifyfd, "/dev/input", IN_CREATE | IN_DELETE);
d = opendir("/dev/input");
i = 0;
while((dir = readdir(d)) != NULL){
if(*dir->d_name == 'j' && *(dir->d_name + 1) == 's'){
createGamepad(dir->d_name, i);
i++;
}
}
closedir(d);
After that inotify handles it like this in the while(1) loop:
static bool canReadINotify(){
fd_set set;
struct timeval timeout;
FD_ZERO(&set);
FD_SET(notifyfd, &set);
timeout.tv_sec = 0;
timeout.tv_usec = 0;
return select(notifyfd + 1, &set, NULL, NULL, &timeout) > 0 &&
FD_ISSET(notifyfd, &set);
}
// Inside the event loop
struct inotify_event ne;
while(canReadINotify()){
if(read(notifyfd, &ne, sizeof(struct inotify_event) + 16) >= 0){
if(*ne.name != 'j' || *(ne.name + 1) != 's'){
continue;
}
if(ne.mask & IN_CREATE){
createGamepad(ne.name);
}
}
}
Is it even possible with inotify or should I use udev? And if it's possible, how can I solve this?
It is very likely a race condition. You see, you get the inotify event when the device node is created (by udev using a mknod() call), but the access permissions are set by udev using a separate chown() call, just a tiny bit later.
See systemd src/udev/udev-node.c, node_permissions_apply(). In this particular case, /dev/input/jsX is not a symlink, but the actual device node; at least with systemd the device node access mode gets set sometime later, after the actual node is created.
One robust solution would be to modify your createGamepad() function, so that instead of failing completely at fd == -1 && errno == EACCES, you instead retry after a short while; at least a few times, say for up to a second or two.
However, ninjalj pointed out a better suggestion: use also the access permissions change as a trigger to check the device node. This is trivially accomplished, by using IN_CREATE | IN_DELETE | IN_ATTRIBUTE in the inotify_add_watch() function!
(You'll also want to ignore open()==-1, errno==EACCES errors in createGamepad(), as they are likely caused by this race condition, and the following IN_ATTRIBUTE inotify event will yield access to the same device.)
Prior to ninjalj's comment, I'd personally have used an array of input devices, and another for "possible" input devices that can/need to be retried after a short timeout to decide whether they are available or not, but I think his suggestion is much better.
Need/want an example?
I open a mesage queue in a .c file, and upon success it says the message queue id is 3. While that program is still running, in another terminal I start another program (of another .c file), that creates a new message queue with a different mqd_t. But its id also appears as 3. Is this a problem?
server file goes like this:
void server(char* req_mq) {
struct mq_attr attr;
mqd_t mqdes;
struct request* msgptr;
int n;
char *bufptr;
int buflen;
pid_t apid;
//attr.mq_maxmsg = 300;
//attr.mq_msgsize = 1024;
mqdes = mq_open(req_mq, O_RDWR | O_CREAT, 0666, NULL);
if (mqdes == -1) {
perror("can not create msg queue\n");
exit(1);
}
printf("server mq created, mq id = %d\n", (int) mqdes);
and the client goes like:
void client(char* req_mq, int min, int max, char* dir_path_name, char* outfile) {
pid_t pid;
/* get the process id */
if ((pid = getpid()) < 0) {
perror("unable to get client pid");
}
mqd_t mqd, dq;
char pfx[50] = DQ_PRFX;
char suffix[50]; //
sprintf(suffix, "%d", pid);
strcat(pfx, suffix);
dq = mq_open(pfx, O_RDWR | O_CREAT, 0666, NULL);
if (dq == -1) {
perror("can not open data queue\n");
exit(1);
}
printf("data queue created, mq id = %d\n", (int) dq);
mqd = mq_open(req_mq, O_RDWR);
if (mqd == -1) {
perror("can not open msg queue\n");
exit(1);
}
mqdes and dq seem to share the same id 3.
Think of a handle as an array index. An index into an array held by the operating system, one for every process in the system.
When you open a handle (be it for a file, message queue, socket, etc) the operating system records the settings for that object in an array that is unique for your process. The operating system then returns an index into that array to your program.
Every time your program uses that "handle" the operating system is really just looking up a structure in that private array it keeps to find out how to deal with the object related to that "handle".
Linux typically reserves handles 0, 1 and 2 for STDIN, STDOUT, and STDERR respectively. But from then on any handles you open will be numbered 3, 4, and so forth. And your handle 3 might relate to file "/tmp/foo.txt" while another process's handle 3 might relate to file "/tmp/bar.txt". So if two processes are using similar file "handles" it is irrelevant.
By the way, you shouldn't need to know, or care, about what a handle actually contains. In theory it could be anything - a magic number, a pointer, an integer, it doesn't matter. The handle is really a secret token that you just hand to the operating system any time you want access to your system object.
maybe you didn't close the first message queue. because in that situation os gives the same id (index) to the new one.
Message queues are distinguished by the name you give them when you open a message queue using mq_open(3). Message queue descriptors returned by mq_open(3) are only meaningful within a process scope. Put in other words, what another process have as value for message queue descriptor is totally irrelevant to another process. This is completely analogous to file paths and file descriptors. Indeed, Linux is special in the sense that the message queue descriptors are actually file descriptors - see Linux manual page mq_overview(7). This is the explanation for the common value 3 that you see two processes get when opening message queue (in the most typical case 0, 1, 2 having been already opened for the purpose of providing STDIN, STDOUT, and STDERR like PP. already mentions in his answer).