Raspberry Pi 3 A +, User / session limits, ulimit - Page 1
Forum section: electronics / general

author: luiHS
author_rank: Frequent Contributor
timestamp: January 02, 2021, 06:00:37 pm
content: Hi.I have a C program running on a Raspberry Pi 3 A +. It is a small 20K program that receives UART commands and calls another program to view videos.With each command to trigger a video, what I do from C is with popen () and pkill kill any program of the video player that is running, then I wait 100ms and call the program that plays the video, this one also with popen () .My problem is that these calls from C to the program that plays the videos only works 510 times, then it stops working. I can see with top or htop that my program is running but the two popen () are no longer launched (one for pkill and the other to launch the video player).I think it has something to do with the limitations per user/session, I was looking with ulimit -a and changing some parameters got it to run up to 867 times.The question is to know exactly what is limiting the number of calls my program can make using popen (), if it has something to do with ulimit and how to configure it to avoid these limitations.Regards

author: Nominal Animal
author_rank: Super Contributor
timestamp: January 02, 2021, 10:01:59 pm
content: Do you ever pclose() the handles you opened with popen()?Personally, I'd use a lower level fork()+exec() method, so that you can send it signals via its PID, and don't need to do any heuristic waits because when you reap the child process, you know for sure it has exited. Furthermore, you can both write to and read from any pipes to the player process, controlling it (pause, play, volume, etc.), even provide a pseudoterminal to terminal-based players.If the player isomxplayer, then adding the serial control directly to the player (possibly ripping out the silly dbus stuff) would be an option. Or use the dbus for existing omxplayer to control it, although I don't see if it can support opening new URLs via a dbus command.

author: luiHS
author_rank: Frequent Contributor
timestamp: January 03, 2021, 07:34:47 am
content: I tried with pclose (), but then the video playback cannot be terminated before the entire video is displayed. I'm not using omxplayer at the moment, I'm using hello_video, although for a version with sound I would like to try the omxmplayer.The application is a game, so a lot of videos are triggered during the game, but any video can be interrupted by a new video during the game, and here comes the problem. I realized after playing for a long time that the screen went black and no longer worked. Then debugging my workbench I saw that when I reached 510 calls with poppen () for pkill and followed by another poppen () to call the video, everything collapses and the poppen () are no longer triggered, seen in top and htop, although my program still works. If I modify the limits in ulimit it can reach 867 calls but then the whole system collapses.I read something about fork () + exec (), the question is whether with this system it will also have the same limitations. I do not understand what happens with poppen (), it is as if something was left open that consumes resources in each session, because if I close the program and rerun it, I will be able to execute the triggering of the videos another 510 times.As for controlling omxplayer with pipes, I have thought about it for how much I need videos with sound, but the problem is that I need to control which video is opened and closed, and I think that it cannot be controlled with pipes and omxplayer.Right now the only thing I can think of is to put my program inside the hello_video source so as not to have to use popper (), then from within the program itself I will be able to open and close the videos. The problem will be when I need sound, because I only know omxplayer and then I would have to use popper () again.To debug I have created this loop that launches the video non-stop, first it pkills with poppen () to kill any other video that may be playing and then calls the program that plays the video with another poppen ().1.- This using pclose () but then the video cannot be interrupted, it plays until the end before being able to launch a new video, so it is not useful to me.FILE *fp = NULL;FILE *fp2 = NULL;while(1){fp2 = popen("pkill player.bin" , "r");pclose(fp2); // Cierro popen()usleep(100000); // wait 100 msfp = popen("/program/player.bin /program/videos/video.h264", "r");pclose(fp); // Cierro popen()printf("Cuenta: %d \r\n", cuenta_gpu);cuenta_gpu++;usleep(300000); // wait 300 ms}2.- And this as I have it currently programmed, works fine until the loop has called the video 510 times, then the poppen () no longer work and the screen goes black. My program continues to work, it is the poppen () that are no longer executed, seen with top and htop. If I increase the limits with ulimit then it reaches 867 times, but the whole system collapses.while(1){popen("pkill player.bin" , "r");usleep(100000); // wait 100 mspopen("/program/player.bin /program/videos/video.h264", "r");printf("Cuenta: %d \r\n", cuenta_gpu);cuenta_gpu++;usleep(300000); // wait 300 ms}

author: andersm
author_rank: Super Contributor
timestamp: January 03, 2021, 01:31:27 pm
content: The streams allocated by popen() must be freed by matching calls to pclose(), now you're just leaking them. This might work, but I haven't tested. Ultimately, switching to a player with a proper RPC interface would be preferable.Code:while(1) {fp = popen("/program/player.bin /program/videos/video.h264", "r");usleep(300000);fp2 = popen("pkill player.bin" , "r");pclose(fp);pclose(fp2);usleep(100000);}

author: Nominal Animal
author_rank: Super Contributor
timestamp: January 03, 2021, 02:34:55 pm
content: OMXPlayer has a full dbus interface, including loading new videos.This means you can just start a single OMXPlayer instance, and use the dbus interface to start/stop/pause each video.

author: luiHS
author_rank: Frequent Contributor
timestamp: January 03, 2021, 05:29:17 pm
content: Quote from: andersm on January 03, 2021, 01:31:27 pmThanks, but as I already said that does not help me since the popen () does not end and goes to the next instruction until the video in the video player ends, so I cannot cancel it before it ends, which is what I want to do.

author: andersm
author_rank: Super Contributor
timestamp: January 03, 2021, 05:52:16 pm
content: The point is that you call pclose() after the process has been killed. Pclose() will wait until the process has been terminated, but it's already been killed by pkill. And since you're reclaiming the resources you're currently leaking, you won't run up against the system limits.

author: luiHS
author_rank: Frequent Contributor
timestamp: January 03, 2021, 06:34:55 pm
content: Quote from: andersm on January 03, 2021, 05:52:16 pmThank you my friend, first I apologize for saying that your code would not work for me without having tried it.I have tried it and it works perfectly, you have saved my life, this issue already had me very desperate. Even today I tried to put my code in the hello_video and the problems were multiplied by a thousand.Thanks again, you are my hero.

author: luiHS
author_rank: Frequent Contributor
timestamp: January 03, 2021, 10:11:22 pm
content: Quote from: Nominal Animal on January 03, 2021, 02:34:55 pmDo you know if omxplayer loading can be accelerated by creating a Ramdisk to run from Ram?In general omxplayer I see that it has some lag compared to hello_video, so it does not convince me, but I do not know for now another solution that allows video with sound.It could also be sped up, I suppose, if the omxplayer runs when the Raspberry boots and communicates with a pipe with my program, that would do me good if I can control the omxplayer to tell it to open or close a file. What little I have read about omxplayer I think it only allowed to control the loaded video when calling omxplayer, but not to close and open other videos using the pipe.

author: Nominal Animal
author_rank: Super Contributor
timestamp: January 04, 2021, 01:24:12 am
content: Quote from: luiHS on January 03, 2021, 10:11:22 pmNo, I doubt it; I think the latency in OMXPlayer is due to its internal buffering.I do know thatmpvis easy to control via JSON-formatted IPC, and has minimal lag/delay (and you can control the buffering options). Could you try that to see if it works better for your use case?

author: Nominal Animal
author_rank: Super Contributor
timestamp: January 04, 2021, 02:41:36 am
content: Consider this simple example program,simple.c:Code:#define _POSIX_C_SOURCE 200809L#define _GNU_SOURCE#include <stdlib.h>#include <unistd.h>#include <sys/socket.h>#include <sys/un.h>#include <fcntl.h>#include <stdio.h>#include <string.h>#include <errno.h>int main(void){char *line = NULL;size_t size = 0;int fd = { -1, -1 };char *cmd = NULL;if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) == -1) {fprintf(stderr, "Cannot create an Unix domain stream socket pair: %s.\n", strerror(errno));return EXIT_FAILURE;}fcntl(fd, F_SETFD, FD_CLOEXEC);if (asprintf(&cmd, "/usr/bin/mpv --input-file=fd://%d --idle=yes --no-input-terminal --input-vo-keyboard=no -fs --video-sync=display-resample >/dev/null 2>/dev/null", fd) == -1) {fprintf(stderr, "%s.\n", strerror(ENOMEM));return EXIT_FAILURE;}FILE *mpv = popen(cmd, "we");if (!mpv) {fprintf(stderr, "Cannot execute '%s'.\n", cmd);return EXIT_FAILURE;}close(fd);fprintf(stderr, "Some commands:\n");fprintf(stderr, "\tloadfile URL\n");fprintf(stderr, "\tstop\n");fprintf(stderr, "\tquit\n");fflush(stderr);while (1) {ssize_t len = getline(&line, &size, stdin);if (len < 0)break;fprintf(stderr, "Forwarding %zd bytes .. ", len);fflush(stderr);char *ptr = line;char *const end = line + len;while (ptr < end) {ssize_t n = write(fd, ptr, (size_t)(end - ptr));if (n > 0) {ptr += n;} elseif (n != -1) {fprintf(stderr, "Failed; write() returned %zd.\n", n);fflush(stderr);break;} elseif (errno != EINTR) {fprintf(stderr, "Failed: %s.\n", strerror(errno));fflush(stderr);break;}}if (ptr == end) {fprintf(stderr, "Done.\n");fflush(stderr);}if (!strcmp(line, "quit\n"))break;}fprintf(stderr, "Waiting for mpv to exit ... ");fflush(stderr);pclose(mpv);fprintf(stderr, "Done.\n");return EXIT_SUCCESS;}Compile and run it usinggcc -Wall -O2 simple.c -o simple./simpleThe simple program just forwards the commands to mpv.To stop playing whatever it is playing and start playing a local file /home/you/video.mp4, supplyloadfile file:///home/you/video.mp4To exit, supplyquit.It is very, very responsive. For me, local files have a small fraction of a second delay to start playing.The idea above is thatmpvis started in slave mode, receiving commands from a file descriptor that the program prepared as one end of a Unix domain stream socket pair, with the other end as close-on-exec. The popen FILE handle isn't used, and like I said, I prefer to use my own fork()/exec() with a control pipe to detect exec failures reliably. Runningmpvin its own session would also let us send signals to its entire process group, in case it starts helper programs or such.For Raspberry Pi, you might wish to change the options a bit, sayCode:if (asprintf(&cmd, "/usr/bin/mpv --input-file=fd://%d --idle=yes --no-input-terminal --input-vo-keyboard=no -fs --video-sync=display-resample --vo=rpi:background --geometry='30%%+1200+100' --ytdl-format='bestvideo[ext=mp4][width<=1920][height<=1080][fps<=30]+bestaudio[ext=m4a]' >/dev/null 2>/dev/null", fd) == -1) {fprintf(stderr, "%s.\n", strerror(ENOMEM));return EXIT_FAILURE;}since that's whathttps://awesome.nwgat.ninja/deb/mpv/mpv.confhas, and they use mpv for R'Pi video playback.mpv also supports JSON IPC, where each command is wrapped in a JSON package. Then, mpv will also respond with success/failure, and provide events like "video ended" and so on. For some really odd reason, there is no option to give it a JSON socket; it wants an Unix domain socketaddressinstead, which means reliable manipulation (using a temporary socket address that gets unlinked as soon as we connect to our own mpv slave) takes a bit more effort, about 300-350 lines of C. Most of it is just error checking, and it isn't "big" at all, just a couple of k of machine code.Thing is, the best way to implement the mpv control via JSON depends on how you process the serial data; and whether your program is just a forwarder, or if it controls the serial device also. (A forwarder would simply wait in a poll()/select() loop for input; then read and parse, and when necessary, forward the event to the other device. Simples, really.)

author: luiHS
author_rank: Frequent Contributor
timestamp: January 04, 2021, 03:09:19 am
content: Ok, thanks, I'll try it.Where can I find instructions to download and install MPV for Raspberry?

author: Nominal Animal
author_rank: Super Contributor
timestamp: January 04, 2021, 04:05:31 am
content: Quote from: luiHS on January 04, 2021, 03:09:19 amIt was the mpv link in my earlier post:https://nwgat.ninja/quick-easy-compiling-mpv-for-raspberry-pi/.You only need to download and install the three packages,mpv_0.20.0_armhf.deblibass_0.13.3-1_armhf.debffmpeg_3.1.3-1_armhf.deband optionally, create~/.config/mpv/mpv.confwithCode:vo=rpi:backgroundgeometry=30%+1200+100ytdl-format='bestvideo[ext=mp4][width<=1920][height<=1080][fps<=30]+bestaudio[ext=m4a]'video-sync=display-resampleso mpv will default to the settings nwgat.ninja recommends for R'Pis. (The last one is mine; it tells mpv to resample audio to compensate for small differences in video playback frame rates; I find it gives much smoother video playback.)Then you can compile and test my example program above.Note that that webpage is from 2016, so it is very likely Raspbian/Debian already has newer versions of the packages – I just don't know for sure.If you have a more recent installation, you might wish to tryfirstsudo apt install mpv libass ffmpegand see if that version of mpv provides hardware-accelerated video on your R'Pi.

author: luiHS
author_rank: Frequent Contributor
timestamp: January 04, 2021, 07:30:01 pm
content: Ok, thanks I'll try it.