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))))))) -- Lorenzo Villani <lvillani@binaryhelix.net>
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
-- Lorenzo Villani <lvillani@binaryhelix.net>
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
participants (3)
-
dherring@tentpost.com
-
Lorenzo Villani
-
Martin Simmons