Hi,
I'm trying to use CFFI in order to wrap execve (2). The wrapper also uses fork (2) and wait (2). While I have absolutely no problems with execve or fork I'm stumbling on a problem with wait.
Wait takes a pointer to an int to store child process' status. The problem is: after the call to wait the value stored in the pointer is the same as before the call.
I am using CFFI 0.10.5 and GNU CLISP 2.47 on Fedora 13.
The code follows:
(defcfun ("fork" c-fork) :int) (defcfun ("execve" c-execve) :int (filename :string) (args :pointer) (env :pointer)) (defcfun ("wait" c-wait) :int (status :pointer))
(defun execute-program (path argv env) (let ((child-pid (c-fork))) (if (= child-pid -1) (error "Unable to create child process") (if (= child-pid 0) ;; Child (progn ;; Remember: (nth 0 argv) must be the full path to the executable. (let ((c-argv (foreign-alloc :string :initial-contents (append (list path) argv) :null-terminated-p t)) (c-env (foreign-alloc :string :initial-contents env :null-terminated-p t))) (c-execve path c-argv c-env) (foreign-free c-argv) (foreign-free c-env))) ;; Parent code (progn (let ((wait-status (foreign-alloc :int))) (c-wait wait-status) ;; This test condition is a reimplementation of __WIFEXITED macro defined at ;; /usr/include/bits/waitstatus.h (if (= 0 (logand (mem-ref wait-status :int) #x7f)) ;; This test condition is a reimplementation of __WEXITSTATUS macro defined at ;; /usr/include/bits/waitstatus.h (when (/= 0 (ash (logand (mem-ref wait-status :int) #xff00) -8)) (error "Child returned an error")) (error "Failed to execute child process")) (foreign-free wait-status)))))))
On Tue, 1 Jun 2010 12:03:54 +0200, Lorenzo Villani said:
I'm trying to use CFFI in order to wrap execve (2). The wrapper also uses fork (2) and wait (2). While I have absolutely no problems with execve or fork I'm stumbling on a problem with wait.
Wait takes a pointer to an int to store child process' status. The problem is: after the call to wait the value stored in the pointer is the same as before the call.
I am using CFFI 0.10.5 and GNU CLISP 2.47 on Fedora 13.
Check the value returned by c-wait, because it sounds like it is getting an error. If it returns -1, then you need to check errno.
You should also use unwind-protect to ensure that foreign-free is called (or use with-foreign-pointer instead of foreign-alloc and foreign-free).
I don't know about CLISP, but your code will not work reliably if the Lisp implementation calls wait itself (e.g. in response to SIGCHLD). If possible, I would use a implementation-supplied function instead of trying to implement execute-program yourself.
__Martin
On Tue, 1 Jun 2010 15:55:32 +0100 Martin Simmons martin@lispworks.com wrote:
Check the value returned by c-wait, because it sounds like it is getting an error. If it returns -1, then you need to check errno.
You should also use unwind-protect to ensure that foreign-free is called (or use with-foreign-pointer instead of foreign-alloc and foreign-free).
When I tried, CLISP crashed.
I don't know about CLISP, but your code will not work reliably if the Lisp implementation calls wait itself (e.g. in response to SIGCHLD). If possible, I would use a implementation-supplied function instead of trying to implement execute-program yourself.
I hoped to be able to get a common implementation of that function but given the time I am wasting and the amount of low-level and implementation-dependant stuff I will follow your advice. Luckily both CFFI and SBCL come with similar functions.
__Martin
I'm trying to use CFFI in order to wrap execve (2). The wrapper also uses fork (2) and wait (2). While I have absolutely no problems with execve or fork I'm stumbling on a problem with wait.
You might try a portability library such as trivial-shell. http://common-lisp.net/project/trivial-shell/
- Daniel