Bug 1313148

Summary: A process forked in a thread will become an orphan process and the orphan one will be alive until we manually kill it
Product: Red Hat Enterprise Linux 7 Reporter: Xibo Ning <xning>
Component: pythonAssignee: Charalampos Stratakis <cstratak>
Status: CLOSED DUPLICATE QA Contact: BaseOS QE - Apps <qe-baseos-apps>
Severity: unspecified Docs Contact:
Priority: high    
Version: 7.2CC: cstratak, eguan
Target Milestone: rcKeywords: Patch
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2016-03-12 14:22:15 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:

Description Xibo Ning 2016-03-01 05:32:27 UTC
Description of problem:
A process forked in a thread will become an orphan process, and until manually kill it the process will be alive.

Version-Release number of selected component (if applicable):
RHEL7: python-2.7.5
Fedora23: python-2.7.10 and python-3.4.3

How reproducible:
Run the demo program as follows 

Steps to Reproduce:
1. python ./demo.py # python3 ./demo.py
2. ps -LwAeo comm,args,pid,ppid,tid,pgid,tpgid,sid,%cpu,\
%mem,bsdstart,bsdtime,c,flags,nlwp,wchan,nwchan,wchan | \
grep '\[python' | grep -v grep


Actual results:
There is an orphan process that has two threads.

Expected results:
The demo program quit successfully.

Additional info:
############demo.py###########################
#!/usr/bin/env python

import os
import sys
try:
    import Tkinter
except ImportError:
    import tkinter
try:
    import thread
except ImportError:
    import _thread as thread

def demo():
    try:
        pid = os.fork()
    except RuntimeError:
        sys.exit(0)

    if pid == 0:
        os.close(r)
        os.write(w, "Child".encode('utf8'))
        sys.exit(0)
    else:
        os.close(w)

if __name__ == "__main__":
    r, w=os.pipe()
    thread.start_new_thread(demo, ())
    sys.stdout.write(str(os.read(r, 5)))
##############END########################

Comment 2 Xibo Ning 2016-03-01 06:02:49 UTC
The Tkinter/tkinter module will add a child handler, which is used by tcl/tk to do the tcl/tk event queue and notifier interfaces, to the fork system call. When forking a process, the fork child handler will start a thread in the child process. And when the process done, the exit system call will tell the thread created by the fork child handler to quit.

While when a process forked in a thread, the thread created by the fork child handler left, and seems the exit system call didn't work.

Comment 3 Xibo Ning 2016-03-01 06:04:54 UTC
This bug cause building python-2.7.5 package on brew system stall.

Comment 5 Eryu Guan 2016-03-04 07:23:22 UTC
The tkinter module creates a new thread on fork(), the thread create pipes and does select() on the read side, which blocks the thread from exiting.

If I did this change to the test py file, test works for me, no thread left behind

# diff -u bz1313148.py bz1313148.py.new
--- bz1313148.py        2016-03-04 15:04:28.735037233 +0800
+++ bz1313148.py.new    2016-03-04 15:04:35.678778973 +0800
@@ -20,7 +20,7 @@
     if pid == 0:
         os.close(r)
         os.write(w, "Child".encode('utf8'))
-        sys.exit(0)
+        os._exit(0)
     else:
         os.close(w)
 
sys.exit() ends up calling _exit(), which only terminates the calling thread. On the other hand, os._exit() ends up calling exit_group(), which terminates all threads in the calling process's thread group.

But I'm not sure if it's a python/tkinter bug or a misuse of the module.

Comment 8 Charalampos Stratakis 2016-03-12 14:22:15 UTC

*** This bug has been marked as a duplicate of bug 1313259 ***