Thanks for your comments. I put the Python program on its own pthread, and call a small C program to fork-execv to call the Python program as a child process. I revised the Python program to be a multiprocessing loop using the Python multiprocessing module. That bypasses the GIL and allows Python to run concurrently with C. So far so good.
Next I will use Linux pipes, not Python multiprocessing pipes, for IPC between Python and C. Multiprocessing pipes are (as far as I can tell) only for commo between two Python processes. I will have the parent thread send a signal through the pipe to the child process to exit when the parent thread is ready to exit, then call wait() to finalize the child process. I will reply back when it's finished and post the code so you can see what I have done. Thanks again. Jen Dec 4, 2021, 09:22 by ba...@barrys-emacs.org: > > >> On 1 Dec 2021, at 16:01, Jen Kris <>> jenk...@tutanota.com>> > wrote: >> >> Thanks for your comment re blocking. >> >> I removed pipes from the Python and C programs to see if it blocks without >> them, and it does. >> >> It looks now like the problem is not pipes. >> > > Ok. > > >> I use fork() and execv() in C to run Python in a child process, but the >> Python process blocks >> > > Use strace on the parent process to see what is happening. > You will need to use the option to follow subprocesses so that you can see > what goes on in the python process. > > See man strace and the --follow-forks and --output-separately options. > That will allow you to find the blocking system call that your code is making. > > >> because fork() does not create a new thread, so the Python global >> interpreter lock (GIL) prevents the C program from running once Python >> starts. >> > > Not sure why you think this. > > >> So the solution appears to be run Python in a separate thread, which I can >> do with pthread create. >> >> See "Thread State and the Global Interpreter Lock" >> >> https://docs.python.org/3/c-api/init.html#thread-state-and-the-global-interpreter-lock>> >> and the sections below that "Non-Python created threads" and "Cautions >> about fork()." >> > > I take it you mean that in the parent you think that using pthreads will > affect python after the exec() call? > I does not. After exec() the process has one main thread create by the kernel > and a new address space as defined by the /usr/bin/python. > The only state that in inherited from the parent are open file descriptors, > the current working directory and security state like UID, GID. > > >> I'm working on that today and I hope all goes well :) >> > > You seem to be missing background information on how processes work. > Maybe "Advanced Programming in the UNIX Environment" > would be helpful? > > https://www.amazon.co.uk/Programming-Environment-Addison-Wesley-Professional-Computing-dp-0321637739/dp/0321637739/ref=dp_ob_image_bk> > > > It's a great book and covers a wide range of Unix systems programming topics. > > Have you created a small C program that just does the fork and exec of a > python program to test out your assumptions? > If not I recommend that you do. > > Barry > > > >> >> >> >> Nov 30, 2021, 11:42 by >> ba...@barrys-emacs.org>> : >> >>> >>> >>> >>>> On 29 Nov 2021, at 22:31, Jen Kris <>>>> jenk...@tutanota.com>>>> > wrote: >>>> >>>> Thanks to you and Cameron for your replies. The C side has an epoll_ctl >>>> set, but no event loop to handle it yet. I'm putting that in now with a >>>> pipe write in Python-- as Cameron pointed out that is the likely source of >>>> blocking on C. The pipes are opened as rdwr in Python because that's >>>> nonblocking by default. The child will become more complex, but not in a >>>> way that affects polling. And thanks for the tip about the c-string >>>> termination. >>>> >>>> >>> >>> flags is a bit mask. You say its BLOCKing by not setting os.O_NONBLOCK. >>> You should not use O_RDWR when you only need O_RDONLY access or only >>> O_WRONLY access. >>> >>> You may find >>> >>> man 2 open >>> >>> useful to understand in detail what is behind os.open(). >>> >>> Barry >>> >>> >>> >>> >>>> >>>> >>>> Nov 29, 2021, 14:12 by >>>> ba...@barrys-emacs.org>>>> : >>>> >>>>> >>>>> >>>>>> On 29 Nov 2021, at 20:36, Jen Kris via Python-list <>>>>>> >>>>>> python-list@python.org>>>>>> > wrote: >>>>>> >>>>>> I have a C program that forks to create a child process and uses execv >>>>>> to call a Python program. The Python program communicates with the >>>>>> parent process (in C) through a FIFO pipe monitored with epoll(). >>>>>> >>>>>> The Python child process is in a while True loop, which is intended to >>>>>> keep it running while the parent process proceeds, and perform functions >>>>>> for the C program only at intervals when the parent sends data to the >>>>>> child -- similar to a daemon process. >>>>>> >>>>>> The C process writes to its end of the pipe and the child process reads >>>>>> it, but then the child process continues to loop, thereby blocking the >>>>>> parent. >>>>>> >>>>>> This is the Python code: >>>>>> >>>>>> #!/usr/bin/python3 >>>>>> import os >>>>>> import select >>>>>> >>>>>> #Open the named pipes >>>>>> pr = os.open('/tmp/Pipe_01', os.O_RDWR) >>>>>> >>>>> Why open rdwr if you are only going to read the pipe? >>>>> >>>>>> pw = os.open('/tmp/Pipe_02', os.O_RDWR) >>>>>> >>>>> Only need to open for write. >>>>> >>>>>> >>>>>> ep = select.epoll(-1) >>>>>> ep.register(pr, select.EPOLLIN) >>>>>> >>>>> >>>>> Is the only thing that the child does this: >>>>> 1. Read message from pr >>>>> 2. Process message >>>>> 3. Write result to pw. >>>>> 4. Loop from 1 >>>>> >>>>> If so as Cameron said you do not need to worry about the poll. >>>>> Do you plan for the child to become more complex? >>>>> >>>>>> >>>>>> while True: >>>>>> >>>>>> events = ep.poll(timeout=2.5, maxevents=-1) >>>>>> #events = ep.poll(timeout=None, maxevents=-1) >>>>>> >>>>>> print("child is looping") >>>>>> >>>>>> for fileno, event in events: >>>>>> print("Python fileno") >>>>>> print(fileno) >>>>>> print("Python event") >>>>>> print(event) >>>>>> v = os.read(pr,64) >>>>>> print("Pipe value") >>>>>> print(v) >>>>>> >>>>>> The child process correctly receives the signal from ep.poll and >>>>>> correctly reads the data in the pipe, but then it continues looping. >>>>>> For example, when I put in a timeout: >>>>>> >>>>>> child is looping >>>>>> Python fileno >>>>>> 4 >>>>>> Python event >>>>>> 1 >>>>>> Pipe value >>>>>> b'10\x00' >>>>>> >>>>> The C code does not need to write a 0 bytes at the end. >>>>> I assume the 0 is from the end of a C string. >>>>> UDS messages have a length. >>>>> In the C just write 2 byes in the case. >>>>> >>>>> Barry >>>>> >>>>>> child is looping >>>>>> child is looping >>>>>> >>>>>> That suggests that a while True loop is not the right thing to do in >>>>>> this case. My question is, what type of process loop is best for this >>>>>> situation? The multiprocessing, asyncio and subprocess libraries are >>>>>> very extensive, and it would help if someone could suggest the best >>>>>> alternative for what I am doing here. >>>>>> >>>>>> Thanks very much for any ideas. >>>>>> >>>>>> >>>>>> -- >>>>>> https://mail.python.org/mailman/listinfo/python-list >>>>>> >>>> >>>> >> >> -- https://mail.python.org/mailman/listinfo/python-list