summaryrefslogtreecommitdiff
path: root/lisp/emacs-parallel/parallel.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/emacs-parallel/parallel.el')
-rw-r--r--lisp/emacs-parallel/parallel.el310
1 files changed, 0 insertions, 310 deletions
diff --git a/lisp/emacs-parallel/parallel.el b/lisp/emacs-parallel/parallel.el
deleted file mode 100644
index 3e5eccfd73c..00000000000
--- a/lisp/emacs-parallel/parallel.el
+++ /dev/null
@@ -1,310 +0,0 @@
-;; -*- lexical-binding: t; -*-
-;;; parallel.el ---
-
-;; Copyright (C) 2013 Grégoire Jadi
-
-;; Author: Grégoire Jadi <gregoire.jadi@gmail.com>
-
-;; This program is free software: you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License as
-;; published by the Free Software Foundation, either version 3 of
-;; the License, or (at your option) any later version.
-
-;; This program is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;;; Code:
-
-(require 'cl)
-(require 'parallel-remote)
-
-(defgroup parallel nil
- "Execute stuff in parallel"
- :group 'emacs)
-
-(defcustom parallel-sleep 0.05
- "How many sec should we wait while polling."
- :type 'number
- :group 'parallel)
-
-(defcustom parallel-config nil
- "Global config setting to use."
- :type 'plist
- :group 'parallel)
-
-(defvar parallel--server nil)
-(defvar parallel--tasks nil)
-(defvar parallel--tunnels nil)
-
-;; Declare external function
-(declare-function parallel-send "parallel-remote")
-
-(defun parallel-make-tunnel (username hostname)
- (parallel--init-server)
- (let ((tunnel (find-if (lambda (tun)
- (and (string= username
- (process-get tun 'username))
- (string= hostname
- (process-get tun 'hostname))))
- parallel--tunnels)))
- (unless tunnel
- (setq tunnel (start-process "parallel-ssh" nil "ssh"
- "-N" "-R" (format "0:localhost:%s"
- (process-contact parallel--server :service))
- (format "%s@%s" username hostname)))
- (process-put tunnel 'username username)
- (process-put tunnel 'hostname hostname)
- (set-process-filter tunnel #'parallel--tunnel-filter)
- (while (null (process-get tunnel 'service))
- (sleep-for 0.01))
- (push tunnel parallel--tunnels))
- tunnel))
-
-(defun parallel-stop-tunnel (tunnel)
- (setq parallel--tunnels (delq tunnel parallel--tunnels))
- (delete-process tunnel))
-
-(defun parallel--tunnel-filter (proc output)
- (if (string-match "\\([0-9]+\\)" output)
- (process-put proc 'service (match-string 1 output))))
-
-(defmacro parallel--set-option (place config)
- `(setf ,place (or ,place
- (plist-get ,config ,(intern (format ":%s" (symbol-name place))))
- (plist-get parallel-config ,(intern (format ":%s" (symbol-name place)))))))
-
-(defmacro parallel--set-options (config &rest options)
- `(progn
- ,@(loop for option in options
- collect `(parallel--set-option ,option ,config))))
-
-(defun* parallel-start (exec-fun &key post-exec env timeout
- emacs-path library-path emacs-args
- graphical debug on-event continue-when-executed
- username hostname hostport
- config)
- (parallel--init-server)
-
- ;; Initialize parameters
- (parallel--set-options config
- post-exec
- env
- timeout
- emacs-args
- graphical
- debug
- on-event
- continue-when-executed
- username
- hostname
- hostport)
-
- (setq emacs-path (or emacs-path
- (plist-get config :emacs-path)
- (plist-get parallel-config :emacs-path)
- (expand-file-name invocation-name
- invocation-directory))
- library-path (or library-path
- (plist-get config :library-path)
- (plist-get parallel-config :library-path)
- (locate-library "parallel-remote")))
-
- (let ((task (parallel--new-task))
- proc tunnel ssh-args)
- (push task parallel--tasks)
- (put task 'initialized nil)
- (put task 'exec-fun exec-fun)
- (put task 'env env)
- (when (functionp post-exec)
- (put task 'post-exec post-exec))
- (when (functionp on-event)
- (put task 'on-event on-event))
- (put task 'results nil)
- (put task 'status 'run)
- (put task 'queue nil)
-
- ;; We need to get the tunnel if it exists so we can send the right
- ;; `service' to the remote.
- (when (and username hostname)
- (if hostport
- (setq ssh-args (list "-R" (format "%s:localhost:%s" hostport
- (process-contact parallel--server :service)))
- tunnel t)
- (setq tunnel (parallel-make-tunnel username hostname)
- hostport (process-get tunnel 'service)))
- (setq ssh-args (append
- ssh-args
- (if graphical (list "-X"))
- (list (format "%s@%s" username hostname)))))
- (setq emacs-args (remq nil
- (list* "-Q" "-l" library-path
- (if graphical nil "-batch")
- "--eval" (format "(setq parallel-service '%S)"
- (if tunnel
- hostport
- (process-contact parallel--server :service)))
- "--eval" (format "(setq parallel-task-id '%S)" task)
- "--eval" (format "(setq debug-on-error '%S)" debug)
- "--eval" (format "(setq parallel-continue-when-executed '%S)" continue-when-executed)
- "-f" "parallel-remote--init"
- emacs-args)))
-
- ;; Reformat emacs-args if we use a tunnel (escape string)
- (when tunnel
- (setq emacs-args (list (mapconcat (lambda (string)
- (if (find ?' string)
- (prin1-to-string string)
- string))
- emacs-args " "))))
- (setq proc (apply #'start-process "parallel" nil
- `(,@(when tunnel
- (list* "ssh" ssh-args))
- ,emacs-path
- ,@emacs-args)))
- (put task 'proc proc)
- (set-process-sentinel (get task 'proc) #'parallel--sentinel)
- (when timeout
- (run-at-time timeout nil (lambda ()
- (when (memq (parallel-status task)
- '(run stop))
- (parallel-stop task)))))
- task))
-
-(defun parallel--new-task ()
- "Generate a new task by enforcing a unique name."
- (let ((symbol-name (make-temp-name "parallel-task-")))
- (while (intern-soft symbol-name)
- (setq symbol-name (make-temp-name "parallel-task-")))
- (intern symbol-name)))
-
-(defun parallel--init-server ()
- "Initialize `parallel--server'."
- (when (or (null parallel--server)
- (not (eq (process-status parallel--server)
- 'listen)))
- (setq parallel--server
- (make-network-process :name "parallel-server"
- :buffer nil
- :server t
- :host "localhost"
- :service t
- :family 'ipv4
- :filter #'parallel--filter
- :filter-multibyte t))))
-
-(defun parallel--get-task-process (proc)
- "Return the task running the given PROC."
- (find-if (lambda (task)
- (eq (get task 'proc) proc))
- parallel--tasks))
-
-(defun parallel--sentinel (proc _event)
- "Sentinel to watch over the remote process.
-
-This function do the necessary cleanup when the remote process is
-finished."
- (when (memq (process-status proc) '(exit signal))
- (let* ((task (parallel--get-task-process proc))
- (results (get task 'results))
- (status (process-status proc)))
- ;; 0 means that the remote process has terminated normally (no
- ;; SIGNUM 0).
- (if (zerop (process-exit-status proc))
- (setq status 'success)
- ;; on failure, push the exit-code or signal number on the
- ;; results stack.
- (push (process-exit-status proc) results))
- (put task 'results results)
- (put task 'status status)
-
- (when (functionp (get task 'post-exec))
- (funcall (get task 'post-exec)
- results status))
- (setq parallel--tasks (delq task parallel--tasks)))))
-
-(defun parallel--call-with-env (fun env)
- "Return a string which can be READ/EVAL by the remote process
-to `funcall' FUN with ENV as arguments."
- (format "(funcall (read %S) %s)"
- (prin1-to-string fun)
- (mapconcat (lambda (obj)
- ;; We need to quote it because the remote
- ;; process will READ/EVAL it.
- (format "'%S" obj)) env " ")))
-
-(defun parallel--filter (connection output)
- "Server filter used to retrieve the results send by the remote
-process and send the code to be executed by it."
- (dolist (data (parallel--read-output output))
- (parallel--process-output connection (first data) (rest data))))
-
-(defun parallel--process-output (connection task result)
- (put task 'connection connection)
- (cond ((and (not (get task 'initialized))
- (eq result 'code))
- (apply #'parallel-send
- task
- (get task 'exec-fun)
- (get task 'env))
- (let ((code nil))
- (while (setq code (pop (get task 'queue)))
- (apply #'parallel-send task (car code) (cdr code))))
- (put task 'initialized t))
- (t
- (push result (get task 'results))
- (if (functionp (get task 'on-event))
- (funcall (get task 'on-event) result)))))
-
-(defun parallel-ready-p (task)
- "Determine whether TASK is finished and if the results are
-available."
- (memq (parallel-status task) '(success exit signal)))
-
-(defun parallel-get-result (task)
- "Return the last result send by the remote call, that is the
-result returned by exec-fun."
- (first (parallel-get-results task)))
-
-(defun parallel-get-results (task)
- "Return all results send during the call of exec-fun."
- (parallel-wait task)
- (get task 'results))
-
-(defun parallel-success-p (task)
- "Determine whether TASK has ended successfully."
- (parallel-wait task)
- (eq (parallel-status task) 'success))
-
-(defun parallel-status (task)
- "Return TASK status."
- (get task 'status))
-
-(defun parallel-wait (task)
- "Wait for TASK."
- (while (not (parallel-ready-p task))
- (sleep-for parallel-sleep))
- t) ; for REPL
-
-(defun parallel-stop (task)
- "Stop TASK."
- (delete-process (get task 'proc)))
-
-(defun parallel-send (task fun &rest env)
- "Send FUN to be evaluated by TASK in ENV."
- (let ((connection (get task 'connection)))
- (if connection
- (process-send-string
- connection
- (parallel--call-with-env fun env))
- (push (cons fun env) (get task 'queue)))))
-
-(provide 'parallel)
-
-;;; parallel.el ends here