Klimi's new dotfiles with stow.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

933 lines
30 KiB

преди 5 години
  1. ;;;; -*- indent-tabs-mode: nil -*-
  2. ;;;
  3. ;;; swank-mkcl.lisp --- SLIME backend for MKCL.
  4. ;;;
  5. ;;; This code has been placed in the Public Domain. All warranties
  6. ;;; are disclaimed.
  7. ;;;
  8. ;;; Administrivia
  9. (defpackage swank/mkcl
  10. (:use cl swank/backend))
  11. (in-package swank/mkcl)
  12. ;;(declaim (optimize (debug 3)))
  13. (defvar *tmp*)
  14. (defimplementation gray-package-name ()
  15. '#:gray)
  16. (eval-when (:compile-toplevel :load-toplevel)
  17. (swank/backend::import-swank-mop-symbols :clos
  18. ;; '(:eql-specializer
  19. ;; :eql-specializer-object
  20. ;; :generic-function-declarations
  21. ;; :specializer-direct-methods
  22. ;; :compute-applicable-methods-using-classes)
  23. nil
  24. ))
  25. ;;; UTF8
  26. (defimplementation string-to-utf8 (string)
  27. (mkcl:octets (si:utf-8 string)))
  28. (defimplementation utf8-to-string (octets)
  29. (string (si:utf-8 octets)))
  30. ;;;; TCP Server
  31. (eval-when (:compile-toplevel :load-toplevel)
  32. ;; At compile-time we need access to the sb-bsd-sockets package for the
  33. ;; the following code to be read properly.
  34. ;; It is a bit a shame we have to load the entire module to get that.
  35. (require 'sockets))
  36. (defun resolve-hostname (name)
  37. (car (sb-bsd-sockets:host-ent-addresses
  38. (sb-bsd-sockets:get-host-by-name name))))
  39. (defimplementation create-socket (host port &key backlog)
  40. (let ((socket (make-instance 'sb-bsd-sockets:inet-socket
  41. :type :stream
  42. :protocol :tcp)))
  43. (setf (sb-bsd-sockets:sockopt-reuse-address socket) t)
  44. (sb-bsd-sockets:socket-bind socket (resolve-hostname host) port)
  45. (sb-bsd-sockets:socket-listen socket (or backlog 5))
  46. socket))
  47. (defimplementation local-port (socket)
  48. (nth-value 1 (sb-bsd-sockets:socket-name socket)))
  49. (defimplementation close-socket (socket)
  50. (sb-bsd-sockets:socket-close socket))
  51. (defun accept (socket)
  52. "Like socket-accept, but retry on EINTR."
  53. (loop (handler-case
  54. (return (sb-bsd-sockets:socket-accept socket))
  55. (sb-bsd-sockets:interrupted-error ()))))
  56. (defimplementation accept-connection (socket
  57. &key external-format
  58. buffering timeout)
  59. (declare (ignore timeout))
  60. (sb-bsd-sockets:socket-make-stream (accept socket)
  61. :output t ;; bogus
  62. :input t ;; bogus
  63. :buffering buffering ;; bogus
  64. :element-type (if external-format
  65. 'character
  66. '(unsigned-byte 8))
  67. :external-format external-format
  68. ))
  69. (defimplementation preferred-communication-style ()
  70. :spawn
  71. )
  72. (defvar *external-format-to-coding-system*
  73. '((:iso-8859-1
  74. "latin-1" "latin-1-unix" "iso-latin-1-unix"
  75. "iso-8859-1" "iso-8859-1-unix")
  76. (:utf-8 "utf-8" "utf-8-unix")))
  77. (defun external-format (coding-system)
  78. (or (car (rassoc-if (lambda (x) (member coding-system x :test #'equal))
  79. *external-format-to-coding-system*))
  80. (find coding-system (si:all-encodings) :test #'string-equal)))
  81. (defimplementation find-external-format (coding-system)
  82. #+unicode (external-format coding-system)
  83. ;; Without unicode support, MKCL uses the one-byte encoding of the
  84. ;; underlying OS, and will barf on anything except :DEFAULT. We
  85. ;; return NIL here for known multibyte encodings, so
  86. ;; SWANK:CREATE-SERVER will barf.
  87. #-unicode (let ((xf (external-format coding-system)))
  88. (if (member xf '(:utf-8))
  89. nil
  90. :default)))
  91. ;;;; Unix signals
  92. (defimplementation install-sigint-handler (handler)
  93. (let ((old-handler (symbol-function 'si:terminal-interrupt)))
  94. (setf (symbol-function 'si:terminal-interrupt)
  95. (if (consp handler)
  96. (car handler)
  97. (lambda (&rest args)
  98. (declare (ignore args))
  99. (funcall handler)
  100. (continue))))
  101. (list old-handler)))
  102. (defimplementation getpid ()
  103. (mkcl:getpid))
  104. (defimplementation set-default-directory (directory)
  105. (mk-ext::chdir (namestring directory))
  106. (default-directory))
  107. (defimplementation default-directory ()
  108. (namestring (mk-ext:getcwd)))
  109. (defmacro progf (plist &rest forms)
  110. `(let (_vars _vals)
  111. (do ((p ,plist (cddr p)))
  112. ((endp p))
  113. (push (car p) _vars)
  114. (push (cadr p) _vals))
  115. (progv _vars _vals ,@forms)
  116. )
  117. )
  118. (defvar *inferior-lisp-sleeping-post* nil)
  119. (defimplementation quit-lisp ()
  120. (progf (ignore-errors (eval (read-from-string "swank::*saved-global-streams*"))) ;; restore original IO streams.
  121. (when *inferior-lisp-sleeping-post* (mt:semaphore-signal *inferior-lisp-sleeping-post*))
  122. ;;(mk-ext:quit :verbose t)
  123. ))
  124. ;;;; Compilation
  125. (defvar *buffer-name* nil)
  126. (defvar *buffer-start-position*)
  127. (defvar *buffer-string*)
  128. (defvar *compile-filename*)
  129. (defun signal-compiler-condition (&rest args)
  130. (signal (apply #'make-condition 'compiler-condition args)))
  131. #|
  132. (defun handle-compiler-warning (condition)
  133. (signal-compiler-condition
  134. :original-condition condition
  135. :message (format nil "~A" condition)
  136. :severity :warning
  137. :location
  138. (if *buffer-name*
  139. (make-location (list :buffer *buffer-name*)
  140. (list :offset *buffer-start-position* 0))
  141. ;; ;; compiler::*current-form*
  142. ;; (if compiler::*current-function*
  143. ;; (make-location (list :file *compile-filename*)
  144. ;; (list :function-name
  145. ;; (symbol-name
  146. ;; (slot-value compiler::*current-function*
  147. ;; 'compiler::name))))
  148. (list :error "No location found.")
  149. ;; )
  150. )))
  151. |#
  152. #|
  153. (defun condition-location (condition)
  154. (let ((file (compiler:compiler-message-file condition))
  155. (position (compiler:compiler-message-file-position condition)))
  156. (if (and position (not (minusp position)))
  157. (if *buffer-name*
  158. (make-buffer-location *buffer-name*
  159. *buffer-start-position*
  160. position)
  161. (make-file-location file position))
  162. (make-error-location "No location found."))))
  163. |#
  164. (defun condition-location (condition)
  165. (if *buffer-name*
  166. (make-location (list :buffer *buffer-name*)
  167. (list :offset *buffer-start-position* 0))
  168. ;; ;; compiler::*current-form* ;
  169. ;; (if compiler::*current-function* ;
  170. ;; (make-location (list :file *compile-filename*) ;
  171. ;; (list :function-name ;
  172. ;; (symbol-name ;
  173. ;; (slot-value compiler::*current-function* ;
  174. ;; 'compiler::name)))) ;
  175. (if (typep condition 'compiler::compiler-message)
  176. (make-location (list :file (namestring (compiler:compiler-message-file condition)))
  177. (list :end-position (compiler:compiler-message-file-end-position condition)))
  178. (list :error "No location found."))
  179. )
  180. )
  181. (defun handle-compiler-message (condition)
  182. (unless (typep condition 'compiler::compiler-note)
  183. (signal-compiler-condition
  184. :original-condition condition
  185. :message (princ-to-string condition)
  186. :severity (etypecase condition
  187. (compiler:compiler-fatal-error :error)
  188. (compiler:compiler-error :error)
  189. (error :error)
  190. (style-warning :style-warning)
  191. (warning :warning))
  192. :location (condition-location condition))))
  193. (defimplementation call-with-compilation-hooks (function)
  194. (handler-bind ((compiler:compiler-message #'handle-compiler-message))
  195. (funcall function)))
  196. (defimplementation swank-compile-file (input-file output-file
  197. load-p external-format
  198. &key policy)
  199. (declare (ignore policy))
  200. (with-compilation-hooks ()
  201. (let ((*buffer-name* nil)
  202. (*compile-filename* input-file))
  203. (handler-bind (#|
  204. (compiler::compiler-note
  205. #'(lambda (n)
  206. (format t "~%swank saw a compiler note: ~A~%" n) (finish-output) nil))
  207. (compiler::compiler-warning
  208. #'(lambda (w)
  209. (format t "~%swank saw a compiler warning: ~A~%" w) (finish-output) nil))
  210. (compiler::compiler-error
  211. #'(lambda (e)
  212. (format t "~%swank saw a compiler error: ~A~%" e) (finish-output) nil))
  213. |#
  214. )
  215. (multiple-value-bind (output-truename warnings-p failure-p)
  216. (compile-file input-file :output-file output-file :external-format external-format)
  217. (values output-truename warnings-p
  218. (or failure-p
  219. (and load-p (not (load output-truename))))))))))
  220. (defimplementation swank-compile-string (string &key buffer position filename policy)
  221. (declare (ignore filename policy))
  222. (with-compilation-hooks ()
  223. (let ((*buffer-name* buffer)
  224. (*buffer-start-position* position)
  225. (*buffer-string* string))
  226. (with-input-from-string (s string)
  227. (when position (file-position position))
  228. (compile-from-stream s)))))
  229. (defun compile-from-stream (stream)
  230. (let ((file (mkcl:mkstemp "TMP:MKCL-SWANK-TMPXXXXXX"))
  231. output-truename
  232. warnings-p
  233. failure-p
  234. )
  235. (with-open-file (s file :direction :output :if-exists :overwrite)
  236. (do ((line (read-line stream nil) (read-line stream nil)))
  237. ((not line))
  238. (write-line line s)))
  239. (unwind-protect
  240. (progn
  241. (multiple-value-setq (output-truename warnings-p failure-p)
  242. (compile-file file))
  243. (and (not failure-p) (load output-truename)))
  244. (when (probe-file file) (delete-file file))
  245. (when (probe-file output-truename) (delete-file output-truename)))))
  246. ;;;; Documentation
  247. (defun grovel-docstring-for-arglist (name type)
  248. (flet ((compute-arglist-offset (docstring)
  249. (when docstring
  250. (let ((pos1 (search "Args: " docstring)))
  251. (if pos1
  252. (+ pos1 6)
  253. (let ((pos2 (search "Syntax: " docstring)))
  254. (when pos2
  255. (+ pos2 8))))))))
  256. (let* ((docstring (si::get-documentation name type))
  257. (pos (compute-arglist-offset docstring)))
  258. (if pos
  259. (multiple-value-bind (arglist errorp)
  260. (ignore-errors
  261. (values (read-from-string docstring t nil :start pos)))
  262. (if (or errorp (not (listp arglist)))
  263. :not-available
  264. arglist
  265. ))
  266. :not-available ))))
  267. (defimplementation arglist (name)
  268. (cond ((and (symbolp name) (special-operator-p name))
  269. (let ((arglist (grovel-docstring-for-arglist name 'function)))
  270. (if (consp arglist) (cdr arglist) arglist)))
  271. ((and (symbolp name) (macro-function name))
  272. (let ((arglist (grovel-docstring-for-arglist name 'function)))
  273. (if (consp arglist) (cdr arglist) arglist)))
  274. ((or (functionp name) (fboundp name))
  275. (multiple-value-bind (name fndef)
  276. (if (functionp name)
  277. (values (function-name name) name)
  278. (values name (fdefinition name)))
  279. (let ((fle (function-lambda-expression fndef)))
  280. (case (car fle)
  281. (si:lambda-block (caddr fle))
  282. (t (typecase fndef
  283. (generic-function (clos::generic-function-lambda-list fndef))
  284. (compiled-function (grovel-docstring-for-arglist name 'function))
  285. (function :not-available)))))))
  286. (t :not-available)))
  287. (defimplementation function-name (f)
  288. (si:compiled-function-name f)
  289. )
  290. (eval-when (:compile-toplevel :load-toplevel)
  291. ;; At compile-time we need access to the walker package for the
  292. ;; the following code to be read properly.
  293. ;; It is a bit a shame we have to load the entire module to get that.
  294. (require 'walker))
  295. (defimplementation macroexpand-all (form &optional env)
  296. (declare (ignore env))
  297. (walker:macroexpand-all form))
  298. (defimplementation describe-symbol-for-emacs (symbol)
  299. (let ((result '()))
  300. (dolist (type '(:VARIABLE :FUNCTION :CLASS))
  301. (let ((doc (describe-definition symbol type)))
  302. (when doc
  303. (setf result (list* type doc result)))))
  304. result))
  305. (defimplementation describe-definition (name type)
  306. (case type
  307. (:variable (documentation name 'variable))
  308. (:function (documentation name 'function))
  309. (:class (documentation name 'class))
  310. (t nil)))
  311. ;;; Debugging
  312. (eval-when (:compile-toplevel :load-toplevel)
  313. (import
  314. '(si::*break-env*
  315. si::*ihs-top*
  316. si::*ihs-current*
  317. si::*ihs-base*
  318. si::*frs-base*
  319. si::*frs-top*
  320. si::*tpl-commands*
  321. si::*tpl-level*
  322. si::frs-top
  323. si::ihs-top
  324. si::ihs-fun
  325. si::ihs-env
  326. si::sch-frs-base
  327. si::set-break-env
  328. si::set-current-ihs
  329. si::tpl-commands)))
  330. (defvar *backtrace* '())
  331. (defun in-swank-package-p (x)
  332. (and
  333. (symbolp x)
  334. (member (symbol-package x)
  335. (list #.(find-package :swank)
  336. #.(find-package :swank/backend)
  337. #.(ignore-errors (find-package :swank-mop))
  338. #.(ignore-errors (find-package :swank-loader))))
  339. t))
  340. (defun is-swank-source-p (name)
  341. (setf name (pathname name))
  342. #+(or)
  343. (pathname-match-p
  344. name
  345. (make-pathname :defaults swank-loader::*source-directory*
  346. :name (pathname-name name)
  347. :type (pathname-type name)
  348. :version (pathname-version name)))
  349. nil)
  350. (defun is-ignorable-fun-p (x)
  351. (or
  352. (in-swank-package-p (frame-name x))
  353. (multiple-value-bind (file position)
  354. (ignore-errors (si::compiled-function-file (car x)))
  355. (declare (ignore position))
  356. (if file (is-swank-source-p file)))))
  357. (defmacro find-ihs-top (x)
  358. (declare (ignore x))
  359. '(si::ihs-top))
  360. (defimplementation call-with-debugging-environment (debugger-loop-fn)
  361. (declare (type function debugger-loop-fn))
  362. (let* (;;(*tpl-commands* si::tpl-commands)
  363. (*ihs-base* 0)
  364. (*ihs-top* (find-ihs-top 'call-with-debugging-environment))
  365. (*ihs-current* *ihs-top*)
  366. (*frs-base* (or (sch-frs-base 0 #|*frs-top*|# *ihs-base*) (1+ (frs-top))))
  367. (*frs-top* (frs-top))
  368. (*read-suppress* nil)
  369. ;;(*tpl-level* (1+ *tpl-level*))
  370. (*backtrace* (loop for ihs from 0 below *ihs-top*
  371. collect (list (si::ihs-fun ihs)
  372. (si::ihs-env ihs)
  373. nil))))
  374. (declare (special *ihs-current*))
  375. (loop for f from *frs-base* to *frs-top*
  376. do (let ((i (- (si::frs-ihs f) *ihs-base* 1)))
  377. (when (plusp i)
  378. (let* ((x (elt *backtrace* i))
  379. (name (si::frs-tag f)))
  380. (unless (mkcl:fixnump name)
  381. (push name (third x)))))))
  382. (setf *backtrace* (remove-if #'is-ignorable-fun-p (nreverse *backtrace*)))
  383. (setf *tmp* *backtrace*)
  384. (set-break-env)
  385. (set-current-ihs)
  386. (let ((*ihs-base* *ihs-top*))
  387. (funcall debugger-loop-fn))))
  388. (defimplementation call-with-debugger-hook (hook fun)
  389. (let ((*debugger-hook* hook)
  390. (*ihs-base* (find-ihs-top 'call-with-debugger-hook)))
  391. (funcall fun)))
  392. (defimplementation compute-backtrace (start end)
  393. (when (numberp end)
  394. (setf end (min end (length *backtrace*))))
  395. (loop for f in (subseq *backtrace* start end)
  396. collect f))
  397. (defimplementation format-sldb-condition (condition)
  398. "Format a condition for display in SLDB."
  399. ;;(princ-to-string condition)
  400. (format nil "~A~%In thread: ~S" condition mt:*thread*)
  401. )
  402. (defun frame-name (frame)
  403. (let ((x (first frame)))
  404. (if (symbolp x)
  405. x
  406. (function-name x))))
  407. (defun function-position (fun)
  408. (multiple-value-bind (file position)
  409. (si::compiled-function-file fun)
  410. (and file (make-location
  411. `(:file ,(if (stringp file) file (namestring file)))
  412. ;;`(:position ,position)
  413. `(:end-position , position)))))
  414. (defun frame-function (frame)
  415. (let* ((x (first frame))
  416. fun position)
  417. (etypecase x
  418. (symbol (and (fboundp x)
  419. (setf fun (fdefinition x)
  420. position (function-position fun))))
  421. (function (setf fun x position (function-position x))))
  422. (values fun position)))
  423. (defun frame-decode-env (frame)
  424. (let ((functions '())
  425. (blocks '())
  426. (variables '()))
  427. (setf frame (si::decode-ihs-env (second frame)))
  428. (dolist (record frame)
  429. (let* ((record0 (car record))
  430. (record1 (cdr record)))
  431. (cond ((or (symbolp record0) (stringp record0))
  432. (setq variables (acons record0 record1 variables)))
  433. ((not (mkcl:fixnump record0))
  434. (push record1 functions))
  435. ((symbolp record1)
  436. (push record1 blocks))
  437. (t
  438. ))))
  439. (values functions blocks variables)))
  440. (defimplementation print-frame (frame stream)
  441. (let ((function (first frame)))
  442. (let ((fname
  443. ;;; (cond ((symbolp function) function)
  444. ;;; ((si:instancep function) (slot-value function 'name))
  445. ;;; ((compiled-function-p function)
  446. ;;; (or (si::compiled-function-name function) 'lambda))
  447. ;;; (t :zombi))
  448. (si::get-fname function)
  449. ))
  450. (if (eq fname 'si::bytecode)
  451. (format stream "~A [Evaluation of: ~S]"
  452. fname (function-lambda-expression function))
  453. (format stream "~A" fname)
  454. )
  455. (when (si::closurep function)
  456. (format stream
  457. ", closure generated from ~A"
  458. (si::get-fname (si:closure-producer function)))
  459. )
  460. )
  461. )
  462. )
  463. (defimplementation frame-source-location (frame-number)
  464. (nth-value 1 (frame-function (elt *backtrace* frame-number))))
  465. (defimplementation frame-catch-tags (frame-number)
  466. (third (elt *backtrace* frame-number)))
  467. (defimplementation frame-locals (frame-number)
  468. (loop for (name . value) in (nth-value 2 (frame-decode-env (elt *backtrace* frame-number)))
  469. with i = 0
  470. collect (list :name name :id (prog1 i (incf i)) :value value)))
  471. (defimplementation frame-var-value (frame-number var-id)
  472. (cdr (elt (nth-value 2 (frame-decode-env (elt *backtrace* frame-number))) var-id)))
  473. (defimplementation disassemble-frame (frame-number)
  474. (let ((fun (frame-fun (elt *backtrace* frame-number))))
  475. (disassemble fun)))
  476. (defimplementation eval-in-frame (form frame-number)
  477. (let ((env (second (elt *backtrace* frame-number))))
  478. (si:eval-in-env form env)))
  479. #|
  480. (defimplementation gdb-initial-commands ()
  481. ;; These signals are used by the GC.
  482. #+linux '("handle SIGPWR noprint nostop"
  483. "handle SIGXCPU noprint nostop"))
  484. (defimplementation command-line-args ()
  485. (loop for n from 0 below (si:argc) collect (si:argv n)))
  486. |#
  487. ;;;; Inspector
  488. (defmethod emacs-inspect ((o t))
  489. ; ecl clos support leaves some to be desired
  490. (cond
  491. ((streamp o)
  492. (list*
  493. (format nil "~S is an ordinary stream~%" o)
  494. (append
  495. (list
  496. "Open for "
  497. (cond
  498. ((ignore-errors (interactive-stream-p o)) "Interactive")
  499. ((and (input-stream-p o) (output-stream-p o)) "Input and output")
  500. ((input-stream-p o) "Input")
  501. ((output-stream-p o) "Output"))
  502. `(:newline) `(:newline))
  503. (label-value-line*
  504. ("Element type" (stream-element-type o))
  505. ("External format" (stream-external-format o)))
  506. (ignore-errors (label-value-line*
  507. ("Broadcast streams" (broadcast-stream-streams o))))
  508. (ignore-errors (label-value-line*
  509. ("Concatenated streams" (concatenated-stream-streams o))))
  510. (ignore-errors (label-value-line*
  511. ("Echo input stream" (echo-stream-input-stream o))))
  512. (ignore-errors (label-value-line*
  513. ("Echo output stream" (echo-stream-output-stream o))))
  514. (ignore-errors (label-value-line*
  515. ("Output String" (get-output-stream-string o))))
  516. (ignore-errors (label-value-line*
  517. ("Synonym symbol" (synonym-stream-symbol o))))
  518. (ignore-errors (label-value-line*
  519. ("Input stream" (two-way-stream-input-stream o))))
  520. (ignore-errors (label-value-line*
  521. ("Output stream" (two-way-stream-output-stream o)))))))
  522. ((si:instancep o) ;;t
  523. (let* ((cl (si:instance-class o))
  524. (slots (clos::class-slots cl)))
  525. (list* (format nil "~S is an instance of class ~A~%"
  526. o (clos::class-name cl))
  527. (loop for x in slots append
  528. (let* ((name (clos::slot-definition-name x))
  529. (value (if (slot-boundp o name)
  530. (clos::slot-value o name)
  531. "Unbound"
  532. )))
  533. (list
  534. (format nil "~S: " name)
  535. `(:value ,value)
  536. `(:newline)))))))
  537. (t (list (format nil "~A" o)))))
  538. ;;;; Definitions
  539. (defimplementation find-definitions (name)
  540. (if (fboundp name)
  541. (let ((tmp (find-source-location (symbol-function name))))
  542. `(((defun ,name) ,tmp)))))
  543. (defimplementation find-source-location (obj)
  544. (setf *tmp* obj)
  545. (or
  546. (typecase obj
  547. (function
  548. (multiple-value-bind (file pos) (ignore-errors (si::compiled-function-file obj))
  549. (if (and file pos)
  550. (make-location
  551. `(:file ,(if (stringp file) file (namestring file)))
  552. `(:end-position ,pos) ;; `(:position ,pos)
  553. `(:snippet
  554. ,(with-open-file (s file)
  555. (file-position s pos)
  556. (skip-comments-and-whitespace s)
  557. (read-snippet s))))))))
  558. `(:error (format nil "Source definition of ~S not found" obj))))
  559. ;;;; Profiling
  560. (eval-when (:compile-toplevel :load-toplevel)
  561. ;; At compile-time we need access to the profile package for the
  562. ;; the following code to be read properly.
  563. ;; It is a bit a shame we have to load the entire module to get that.
  564. (require 'profile))
  565. (defimplementation profile (fname)
  566. (when fname (eval `(profile:profile ,fname))))
  567. (defimplementation unprofile (fname)
  568. (when fname (eval `(profile:unprofile ,fname))))
  569. (defimplementation unprofile-all ()
  570. (profile:unprofile-all)
  571. "All functions unprofiled.")
  572. (defimplementation profile-report ()
  573. (profile:report))
  574. (defimplementation profile-reset ()
  575. (profile:reset)
  576. "Reset profiling counters.")
  577. (defimplementation profiled-functions ()
  578. (profile:profile))
  579. (defimplementation profile-package (package callers methods)
  580. (declare (ignore callers methods))
  581. (eval `(profile:profile ,(package-name (find-package package)))))
  582. ;;;; Threads
  583. (defvar *thread-id-counter* 0)
  584. (defvar *thread-id-counter-lock*
  585. (mt:make-lock :name "thread id counter lock"))
  586. (defun next-thread-id ()
  587. (mt:with-lock (*thread-id-counter-lock*)
  588. (incf *thread-id-counter*))
  589. )
  590. (defparameter *thread-id-map* (make-hash-table))
  591. (defparameter *id-thread-map* (make-hash-table))
  592. (defvar *thread-id-map-lock*
  593. (mt:make-lock :name "thread id map lock"))
  594. (defparameter +default-thread-local-variables+
  595. '(*macroexpand-hook*
  596. *default-pathname-defaults*
  597. *readtable*
  598. *random-state*
  599. *compile-print*
  600. *compile-verbose*
  601. *load-print*
  602. *load-verbose*
  603. *print-array*
  604. *print-base*
  605. *print-case*
  606. *print-circle*
  607. *print-escape*
  608. *print-gensym*
  609. *print-length*
  610. *print-level*
  611. *print-lines*
  612. *print-miser-width*
  613. *print-pprint-dispatch*
  614. *print-pretty*
  615. *print-radix*
  616. *print-readably*
  617. *print-right-margin*
  618. *read-base*
  619. *read-default-float-format*
  620. *read-eval*
  621. *read-suppress*
  622. ))
  623. (defun thread-local-default-bindings ()
  624. (let (local)
  625. (dolist (var +default-thread-local-variables+ local)
  626. (setq local (acons var (symbol-value var) local))
  627. )))
  628. ;; mkcl doesn't have weak pointers
  629. (defimplementation spawn (fn &key name initial-bindings)
  630. (let* ((local-defaults (thread-local-default-bindings))
  631. (thread
  632. ;;(mt:make-thread :name name)
  633. (mt:make-thread :name name
  634. :initial-bindings (nconc initial-bindings
  635. local-defaults))
  636. )
  637. (id (next-thread-id)))
  638. (mt:with-lock (*thread-id-map-lock*)
  639. (setf (gethash id *thread-id-map*) thread)
  640. (setf (gethash thread *id-thread-map*) id))
  641. (mt:thread-preset
  642. thread
  643. #'(lambda ()
  644. (unwind-protect
  645. (progn
  646. ;;(format t "~&Starting thread: ~S.~%" name) (finish-output)
  647. (mt:thread-detach nil)
  648. (funcall fn))
  649. (progn
  650. ;;(format t "~&Wrapping up thread: ~S.~%" name) (finish-output)
  651. (mt:with-lock (*thread-id-map-lock*)
  652. (remhash thread *id-thread-map*)
  653. (remhash id *thread-id-map*))
  654. ;;(format t "~&Finished thread: ~S~%" name) (finish-output)
  655. ))))
  656. (mt:thread-enable thread)
  657. (mt:thread-yield)
  658. thread
  659. ))
  660. (defimplementation thread-id (thread)
  661. (block thread-id
  662. (mt:with-lock (*thread-id-map-lock*)
  663. (or (gethash thread *id-thread-map*)
  664. (let ((id (next-thread-id)))
  665. (setf (gethash id *thread-id-map*) thread)
  666. (setf (gethash thread *id-thread-map*) id)
  667. id)))))
  668. (defimplementation find-thread (id)
  669. (mt:with-lock (*thread-id-map-lock*)
  670. (gethash id *thread-id-map*)))
  671. (defimplementation thread-name (thread)
  672. (mt:thread-name thread))
  673. (defimplementation thread-status (thread)
  674. (if (mt:thread-active-p thread)
  675. "RUNNING"
  676. "STOPPED"))
  677. (defimplementation make-lock (&key name)
  678. (mt:make-lock :name name :recursive t))
  679. (defimplementation call-with-lock-held (lock function)
  680. (declare (type function function))
  681. (mt:with-lock (lock) (funcall function)))
  682. (defimplementation current-thread ()
  683. mt:*thread*)
  684. (defimplementation all-threads ()
  685. (mt:all-threads))
  686. (defimplementation interrupt-thread (thread fn)
  687. (mt:interrupt-thread thread fn))
  688. (defimplementation kill-thread (thread)
  689. (mt:interrupt-thread thread #'mt:terminate-thread)
  690. )
  691. (defimplementation thread-alive-p (thread)
  692. (mt:thread-active-p thread))
  693. (defvar *mailbox-lock* (mt:make-lock :name "mailbox lock"))
  694. (defvar *mailboxes* (list))
  695. (declaim (type list *mailboxes*))
  696. (defstruct (mailbox (:conc-name mailbox.))
  697. thread
  698. locked-by
  699. (mutex (mt:make-lock :name "thread mailbox"))
  700. (semaphore (mt:make-semaphore))
  701. (queue '() :type list))
  702. (defun mailbox (thread)
  703. "Return THREAD's mailbox."
  704. (mt:with-lock (*mailbox-lock*)
  705. (or (find thread *mailboxes* :key #'mailbox.thread)
  706. (let ((mb (make-mailbox :thread thread)))
  707. (push mb *mailboxes*)
  708. mb))))
  709. (defimplementation send (thread message)
  710. (handler-case
  711. (let* ((mbox (mailbox thread))
  712. (mutex (mailbox.mutex mbox)))
  713. ;; (mt:interrupt-thread
  714. ;; thread
  715. ;; (lambda ()
  716. ;; (mt:with-lock (mutex)
  717. ;; (setf (mailbox.queue mbox)
  718. ;; (nconc (mailbox.queue mbox) (list message))))))
  719. ;; (format t "~&! thread = ~S~% thread = ~S~% message = ~S~%"
  720. ;; mt:*thread* thread message) (finish-output)
  721. (mt:with-lock (mutex)
  722. (setf (mailbox.locked-by mbox) mt:*thread*)
  723. (setf (mailbox.queue mbox)
  724. (nconc (mailbox.queue mbox) (list message)))
  725. ;;(format t "*") (finish-output)
  726. (handler-case
  727. (mt:semaphore-signal (mailbox.semaphore mbox))
  728. (condition (condition)
  729. (format t "Something went bad with semaphore-signal ~A" condition) (finish-output)
  730. ;;(break)
  731. ))
  732. (setf (mailbox.locked-by mbox) nil)
  733. )
  734. ;;(format t "+") (finish-output)
  735. )
  736. (condition (condition)
  737. (format t "~&Error in send: ~S~%" condition) (finish-output))
  738. )
  739. )
  740. ;; (defimplementation receive ()
  741. ;; (block got-mail
  742. ;; (let* ((mbox (mailbox mt:*thread*))
  743. ;; (mutex (mailbox.mutex mbox)))
  744. ;; (loop
  745. ;; (mt:with-lock (mutex)
  746. ;; (if (mailbox.queue mbox)
  747. ;; (return-from got-mail (pop (mailbox.queue mbox)))))
  748. ;; ;;interrupt-thread will halt this if it takes longer than 1sec
  749. ;; (sleep 1)))))
  750. (defimplementation receive-if (test &optional timeout)
  751. (handler-case
  752. (let* ((mbox (mailbox (current-thread)))
  753. (mutex (mailbox.mutex mbox))
  754. got-one)
  755. (assert (or (not timeout) (eq timeout t)))
  756. (loop
  757. (check-slime-interrupts)
  758. ;;(format t "~&: ~S~%" mt:*thread*) (finish-output)
  759. (handler-case
  760. (setq got-one (mt:semaphore-wait (mailbox.semaphore mbox) 2))
  761. (condition (condition)
  762. (format t "~&In (swank-mkcl) receive-if: Something went bad with semaphore-wait ~A~%" condition)
  763. (finish-output)
  764. nil
  765. )
  766. )
  767. (mt:with-lock (mutex)
  768. (setf (mailbox.locked-by mbox) mt:*thread*)
  769. (let* ((q (mailbox.queue mbox))
  770. (tail (member-if test q)))
  771. (when tail
  772. (setf (mailbox.queue mbox) (nconc (ldiff q tail) (cdr tail)))
  773. (setf (mailbox.locked-by mbox) nil)
  774. ;;(format t "~&thread ~S received: ~S~%" mt:*thread* (car tail))
  775. (return (car tail))))
  776. (setf (mailbox.locked-by mbox) nil)
  777. )
  778. ;;(format t "/ ~S~%" mt:*thread*) (finish-output)
  779. (when (eq timeout t) (return (values nil t)))
  780. ;; (unless got-one
  781. ;; (format t "~&In (swank-mkcl) receive-if: semaphore-wait timed out!~%"))
  782. )
  783. )
  784. (condition (condition)
  785. (format t "~&Error in (swank-mkcl) receive-if: ~S, ~A~%" condition condition) (finish-output)
  786. nil
  787. )
  788. )
  789. )
  790. (defmethod stream-finish-output ((stream stream))
  791. (finish-output stream))
  792. ;;
  793. ;;#+windows
  794. (defimplementation doze-in-repl ()
  795. (setq *inferior-lisp-sleeping-post* (mt:make-semaphore))
  796. ;;(loop (sleep 1))
  797. (mt:semaphore-wait *inferior-lisp-sleeping-post*)
  798. (mk-ext:quit :verbose t)
  799. )