Klimi's new dotfiles with stow.
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

797 lines
28 KiB

  1. ;;;; -*- indent-tabs-mode: nil -*-
  2. ;;;
  3. ;;; swank-clasp.lisp --- SLIME backend for CLASP.
  4. ;;;
  5. ;;; This code has been placed in the Public Domain. All warranties
  6. ;;; are disclaimed.
  7. ;;;
  8. ;;; Administrivia
  9. (defpackage swank/clasp
  10. (:use cl swank/backend))
  11. (in-package swank/clasp)
  12. #+(or)
  13. (eval-when (:compile-toplevel :load-toplevel :execute)
  14. (setq swank::*log-output* (open "/tmp/slime.log" :direction :output))
  15. (setq swank:*log-events* t))
  16. (defmacro slime-dbg (fmt &rest args)
  17. `(swank::log-event "slime-dbg ~a ~a~%" mp:*current-process* (apply #'format nil ,fmt ,args)))
  18. ;; Hard dependencies.
  19. (eval-when (:compile-toplevel :load-toplevel :execute)
  20. (require 'sockets))
  21. ;; Soft dependencies.
  22. (eval-when (:compile-toplevel :load-toplevel :execute)
  23. (when (probe-file "sys:profile.fas")
  24. (require :profile)
  25. (pushnew :profile *features*))
  26. (when (probe-file "sys:serve-event")
  27. (require :serve-event)
  28. (pushnew :serve-event *features*)))
  29. (declaim (optimize (debug 3)))
  30. ;;; Swank-mop
  31. (eval-when (:compile-toplevel :load-toplevel :execute)
  32. (import-swank-mop-symbols :clos nil))
  33. (defimplementation gray-package-name ()
  34. "GRAY")
  35. ;;;; TCP Server
  36. (defimplementation preferred-communication-style ()
  37. :spawn
  38. #| #+threads :spawn
  39. #-threads nil
  40. |#
  41. )
  42. (defun resolve-hostname (name)
  43. (car (sb-bsd-sockets:host-ent-addresses
  44. (sb-bsd-sockets:get-host-by-name name))))
  45. (defimplementation create-socket (host port &key backlog)
  46. (let ((socket (make-instance 'sb-bsd-sockets:inet-socket
  47. :type :stream
  48. :protocol :tcp)))
  49. (setf (sb-bsd-sockets:sockopt-reuse-address socket) t)
  50. (sb-bsd-sockets:socket-bind socket (resolve-hostname host) port)
  51. (sb-bsd-sockets:socket-listen socket (or backlog 5))
  52. socket))
  53. (defimplementation local-port (socket)
  54. (nth-value 1 (sb-bsd-sockets:socket-name socket)))
  55. (defimplementation close-socket (socket)
  56. (sb-bsd-sockets:socket-close socket))
  57. (defimplementation accept-connection (socket
  58. &key external-format
  59. buffering timeout)
  60. (declare (ignore timeout))
  61. (sb-bsd-sockets:socket-make-stream (accept socket)
  62. :output t
  63. :input t
  64. :buffering (ecase buffering
  65. ((t) :full)
  66. ((nil) :none)
  67. (:line :line))
  68. :element-type (if external-format
  69. 'character
  70. '(unsigned-byte 8))
  71. :external-format external-format))
  72. (defun accept (socket)
  73. "Like socket-accept, but retry on EAGAIN."
  74. (loop (handler-case
  75. (return (sb-bsd-sockets:socket-accept socket))
  76. (sb-bsd-sockets:interrupted-error ()))))
  77. (defimplementation socket-fd (socket)
  78. (etypecase socket
  79. (fixnum socket)
  80. (two-way-stream (socket-fd (two-way-stream-input-stream socket)))
  81. (sb-bsd-sockets:socket (sb-bsd-sockets:socket-file-descriptor socket))
  82. (file-stream (si:file-stream-fd socket))))
  83. (defvar *external-format-to-coding-system*
  84. '((:latin-1
  85. "latin-1" "latin-1-unix" "iso-latin-1-unix"
  86. "iso-8859-1" "iso-8859-1-unix")
  87. (:utf-8 "utf-8" "utf-8-unix")))
  88. (defun external-format (coding-system)
  89. (or (car (rassoc-if (lambda (x) (member coding-system x :test #'equal))
  90. *external-format-to-coding-system*))
  91. (find coding-system (ext:all-encodings) :test #'string-equal)))
  92. (defimplementation find-external-format (coding-system)
  93. #+unicode (external-format coding-system)
  94. ;; Without unicode support, CLASP uses the one-byte encoding of the
  95. ;; underlying OS, and will barf on anything except :DEFAULT. We
  96. ;; return NIL here for known multibyte encodings, so
  97. ;; SWANK:CREATE-SERVER will barf.
  98. #-unicode (let ((xf (external-format coding-system)))
  99. (if (member xf '(:utf-8))
  100. nil
  101. :default)))
  102. ;;;; Unix Integration
  103. ;;; If CLASP is built with thread support, it'll spawn a helper thread
  104. ;;; executing the SIGINT handler. We do not want to BREAK into that
  105. ;;; helper but into the main thread, though. This is coupled with the
  106. ;;; current choice of NIL as communication-style in so far as CLASP's
  107. ;;; main-thread is also the Slime's REPL thread.
  108. #+clasp-working
  109. (defimplementation call-with-user-break-handler (real-handler function)
  110. (let ((old-handler #'si:terminal-interrupt))
  111. (setf (symbol-function 'si:terminal-interrupt)
  112. (make-interrupt-handler real-handler))
  113. (unwind-protect (funcall function)
  114. (setf (symbol-function 'si:terminal-interrupt) old-handler))))
  115. #+threads
  116. (defun make-interrupt-handler (real-handler)
  117. (let ((main-thread (find 'si:top-level (mp:all-processes)
  118. :key #'mp:process-name)))
  119. #'(lambda (&rest args)
  120. (declare (ignore args))
  121. (mp:interrupt-process main-thread real-handler))))
  122. #-threads
  123. (defun make-interrupt-handler (real-handler)
  124. #'(lambda (&rest args)
  125. (declare (ignore args))
  126. (funcall real-handler)))
  127. (defimplementation getpid ()
  128. (si:getpid))
  129. (defimplementation set-default-directory (directory)
  130. (ext:chdir (namestring directory)) ; adapts *DEFAULT-PATHNAME-DEFAULTS*.
  131. (default-directory))
  132. (defimplementation default-directory ()
  133. (namestring (ext:getcwd)))
  134. (defimplementation quit-lisp ()
  135. (core:quit))
  136. ;;; Instead of busy waiting with communication-style NIL, use select()
  137. ;;; on the sockets' streams.
  138. #+serve-event
  139. (progn
  140. (defun poll-streams (streams timeout)
  141. (let* ((serve-event::*descriptor-handlers*
  142. (copy-list serve-event::*descriptor-handlers*))
  143. (active-fds '())
  144. (fd-stream-alist
  145. (loop for s in streams
  146. for fd = (socket-fd s)
  147. collect (cons fd s)
  148. do (serve-event:add-fd-handler fd :input
  149. #'(lambda (fd)
  150. (push fd active-fds))))))
  151. (serve-event:serve-event timeout)
  152. (loop for fd in active-fds collect (cdr (assoc fd fd-stream-alist)))))
  153. (defimplementation wait-for-input (streams &optional timeout)
  154. (assert (member timeout '(nil t)))
  155. (loop
  156. (cond ((check-slime-interrupts) (return :interrupt))
  157. (timeout (return (poll-streams streams 0)))
  158. (t
  159. (when-let (ready (poll-streams streams 0.2))
  160. (return ready))))))
  161. ) ; #+serve-event (progn ...
  162. #-serve-event
  163. (defimplementation wait-for-input (streams &optional timeout)
  164. (assert (member timeout '(nil t)))
  165. (loop
  166. (cond ((check-slime-interrupts) (return :interrupt))
  167. (timeout (return (remove-if-not #'listen streams)))
  168. (t
  169. (let ((ready (remove-if-not #'listen streams)))
  170. (if ready (return ready))
  171. (sleep 0.1))))))
  172. ;;;; Compilation
  173. (defvar *buffer-name* nil)
  174. (defvar *buffer-start-position*)
  175. (defun condition-severity (condition)
  176. (etypecase condition
  177. (cmp:redefined-function-warning :redefinition)
  178. (style-warning :style-warning)
  179. (warning :warning)
  180. (reader-error :read-error)
  181. (error :error)))
  182. (defun condition-location (origin)
  183. (if (null origin)
  184. (make-error-location "No error location available")
  185. (let ((location (core:source-pos-info-filepos origin)))
  186. (if *buffer-name*
  187. (make-buffer-location *buffer-name*
  188. *buffer-start-position*
  189. location)
  190. (make-file-location
  191. (core:file-scope-pathname
  192. (core:file-scope origin))
  193. location)))))
  194. (defun signal-compiler-condition (condition origin)
  195. (signal 'compiler-condition
  196. :original-condition condition
  197. :severity (condition-severity condition)
  198. :message (princ-to-string condition)
  199. :location (condition-location origin)))
  200. (defun handle-compiler-condition (condition)
  201. ;; First resignal warnings, so that outer handlers - which may choose to
  202. ;; muffle this - get a chance to run.
  203. (when (typep condition 'warning)
  204. (signal condition))
  205. (signal-compiler-condition (cmp:deencapsulate-compiler-condition condition)
  206. (cmp:compiler-condition-origin condition)))
  207. (defimplementation call-with-compilation-hooks (function)
  208. (handler-bind
  209. (((or error warning) #'handle-compiler-condition))
  210. (funcall function)))
  211. (defimplementation swank-compile-file (input-file output-file
  212. load-p external-format
  213. &key policy)
  214. (declare (ignore policy))
  215. (format t "Compiling file input-file = ~a output-file = ~a~%" input-file output-file)
  216. ;; Ignore the output-file and generate our own
  217. (let ((tmp-output-file (compile-file-pathname (si:mkstemp "TMP:clasp-swank-compile-file-"))))
  218. (format t "Using tmp-output-file: ~a~%" tmp-output-file)
  219. (multiple-value-bind (fasl warnings-p failure-p)
  220. (with-compilation-hooks ()
  221. (compile-file input-file :output-file tmp-output-file
  222. :external-format external-format))
  223. (values fasl warnings-p
  224. (or failure-p
  225. (when load-p
  226. (not (load fasl))))))))
  227. (defvar *tmpfile-map* (make-hash-table :test #'equal))
  228. (defun note-buffer-tmpfile (tmp-file buffer-name)
  229. ;; EXT:COMPILED-FUNCTION-FILE below will return a namestring.
  230. (let ((tmp-namestring (namestring (truename tmp-file))))
  231. (setf (gethash tmp-namestring *tmpfile-map*) buffer-name)
  232. tmp-namestring))
  233. (defun tmpfile-to-buffer (tmp-file)
  234. (gethash tmp-file *tmpfile-map*))
  235. (defimplementation swank-compile-string (string &key buffer position filename policy)
  236. (declare (ignore policy))
  237. (with-compilation-hooks ()
  238. (let ((*buffer-name* buffer) ; for compilation hooks
  239. (*buffer-start-position* position))
  240. (let ((tmp-file (si:mkstemp "TMP:clasp-swank-tmpfile-"))
  241. (fasl-file)
  242. (warnings-p)
  243. (failure-p))
  244. (unwind-protect
  245. (with-open-file (tmp-stream tmp-file :direction :output
  246. :if-exists :supersede)
  247. (write-string string tmp-stream)
  248. (finish-output tmp-stream)
  249. (multiple-value-setq (fasl-file warnings-p failure-p)
  250. (let ((truename (or filename (note-buffer-tmpfile tmp-file buffer))))
  251. (compile-file tmp-file
  252. :source-debug-pathname (pathname truename)
  253. :source-debug-offset (1- position)))))
  254. (when fasl-file (load fasl-file))
  255. (when (probe-file tmp-file)
  256. (delete-file tmp-file))
  257. (when fasl-file
  258. (delete-file fasl-file)))
  259. (not failure-p)))))
  260. ;;;; Documentation
  261. (defimplementation arglist (name)
  262. (multiple-value-bind (arglist foundp)
  263. (core:function-lambda-list name) ;; Uses bc-split
  264. (if foundp arglist :not-available)))
  265. (defimplementation function-name (f)
  266. (typecase f
  267. (generic-function (clos::generic-function-name f))
  268. (function (ext:compiled-function-name f))))
  269. ;; FIXME
  270. (defimplementation macroexpand-all (form &optional env)
  271. (declare (ignore env))
  272. (macroexpand form))
  273. ;;; modified from sbcl.lisp
  274. (defimplementation collect-macro-forms (form &optional environment)
  275. (let ((macro-forms '())
  276. (compiler-macro-forms '())
  277. (function-quoted-forms '()))
  278. (format t "In collect-macro-forms~%")
  279. (cmp:code-walk
  280. form environment
  281. :code-walker-function
  282. (lambda (form environment)
  283. (when (and (consp form)
  284. (symbolp (car form)))
  285. (cond ((eq (car form) 'function)
  286. (push (cadr form) function-quoted-forms))
  287. ((member form function-quoted-forms)
  288. nil)
  289. ((macro-function (car form) environment)
  290. (push form macro-forms))
  291. ((not (eq form (core:compiler-macroexpand-1 form environment)))
  292. (push form compiler-macro-forms))))
  293. form))
  294. (values macro-forms compiler-macro-forms)))
  295. (defimplementation describe-symbol-for-emacs (symbol)
  296. (let ((result '()))
  297. (flet ((frob (type boundp)
  298. (when (funcall boundp symbol)
  299. (let ((doc (describe-definition symbol type)))
  300. (setf result (list* type doc result))))))
  301. (frob :VARIABLE #'boundp)
  302. (frob :FUNCTION #'fboundp)
  303. (frob :CLASS (lambda (x) (find-class x nil))))
  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. (defimplementation type-specifier-p (symbol)
  312. (or (subtypep nil symbol)
  313. (not (eq (type-specifier-arglist symbol) :not-available))))
  314. ;;; Debugging
  315. (eval-when (:compile-toplevel :load-toplevel :execute)
  316. (import
  317. '(si::*break-env*
  318. si::*ihs-top*
  319. si::*ihs-current*
  320. si::*ihs-base*
  321. #+frs si::*frs-base*
  322. #+frs si::*frs-top*
  323. si::*tpl-commands*
  324. si::*tpl-level*
  325. #+frs si::frs-top
  326. si::ihs-top
  327. si::ihs-fun
  328. si::ihs-env
  329. #+frs si::sch-frs-base
  330. si::set-break-env
  331. si::set-current-ihs
  332. si::tpl-commands)))
  333. (defun make-invoke-debugger-hook (hook)
  334. (when hook
  335. #'(lambda (condition old-hook)
  336. ;; Regard *debugger-hook* if set by user.
  337. (if *debugger-hook*
  338. nil ; decline, *DEBUGGER-HOOK* will be tried next.
  339. (funcall hook condition old-hook)))))
  340. (defimplementation install-debugger-globally (function)
  341. (setq *debugger-hook* function)
  342. (setq ext:*invoke-debugger-hook* (make-invoke-debugger-hook function))
  343. )
  344. (defimplementation call-with-debugger-hook (hook fun)
  345. (let ((*debugger-hook* hook)
  346. (ext:*invoke-debugger-hook* (make-invoke-debugger-hook hook)))
  347. (funcall fun))
  348. )
  349. (defvar *backtrace* '())
  350. ;;; Commented out; it's not clear this is a good way of doing it. In
  351. ;;; particular because it makes errors stemming from this file harder
  352. ;;; to debug, and given the "young" age of CLASP's swank backend, that's
  353. ;;; a bad idea.
  354. ;; (defun in-swank-package-p (x)
  355. ;; (and
  356. ;; (symbolp x)
  357. ;; (member (symbol-package x)
  358. ;; (list #.(find-package :swank)
  359. ;; #.(find-package :swank/backend)
  360. ;; #.(ignore-errors (find-package :swank-mop))
  361. ;; #.(ignore-errors (find-package :swank-loader))))
  362. ;; t))
  363. ;; (defun is-swank-source-p (name)
  364. ;; (setf name (pathname name))
  365. ;; (pathname-match-p
  366. ;; name
  367. ;; (make-pathname :defaults swank-loader::*source-directory*
  368. ;; :name (pathname-name name)
  369. ;; :type (pathname-type name)
  370. ;; :version (pathname-version name))))
  371. ;; (defun is-ignorable-fun-p (x)
  372. ;; (or
  373. ;; (in-swank-package-p (frame-name x))
  374. ;; (multiple-value-bind (file position)
  375. ;; (ignore-errors (si::bc-file (car x)))
  376. ;; (declare (ignore position))
  377. ;; (if file (is-swank-source-p file)))))
  378. (defimplementation call-with-debugging-environment (debugger-loop-fn)
  379. (declare (type function debugger-loop-fn))
  380. (let* ((*ihs-top* 0)
  381. (*ihs-current* *ihs-top*)
  382. #+frs (*frs-base* (or (sch-frs-base *frs-top* *ihs-base*) (1+ (frs-top))))
  383. #+frs (*frs-top* (frs-top))
  384. (*tpl-level* (1+ *tpl-level*)))
  385. (core:call-with-backtrace
  386. (lambda (raw-backtrace)
  387. (let ((*backtrace*
  388. (let ((backtrace (core::common-lisp-backtrace-frames
  389. raw-backtrace
  390. :gather-start-trigger
  391. (lambda (frame)
  392. (let ((function-name (core::backtrace-frame-function-name frame)))
  393. (and (symbolp function-name)
  394. (eq function-name 'core::universal-error-handler))))
  395. :gather-all-frames nil)))
  396. (unless backtrace
  397. (setq backtrace (core::common-lisp-backtrace-frames
  398. :gather-all-frames nil)))
  399. backtrace)))
  400. (declare (special *ihs-current*))
  401. (set-break-env)
  402. (set-current-ihs)
  403. (let ((*ihs-base* *ihs-top*))
  404. (funcall debugger-loop-fn)))))))
  405. (defimplementation compute-backtrace (start end)
  406. (subseq *backtrace* start
  407. (and (numberp end)
  408. (min end (length *backtrace*)))))
  409. (defun frame-name (frame)
  410. (let ((x (core::backtrace-frame-function-name frame)))
  411. (if (symbolp x)
  412. x
  413. (function-name x))))
  414. (defun frame-function (frame-number)
  415. (let ((x (core::backtrace-frame-function-name (elt *backtrace* frame-number))))
  416. (etypecase x
  417. (symbol
  418. (and (fboundp x)
  419. (fdefinition x)))
  420. (cons
  421. (if (eq (car x) 'cl:setf)
  422. (fdefinition x)
  423. nil))
  424. (function
  425. x))))
  426. (defimplementation print-frame (frame stream)
  427. (if (core::backtrace-frame-arguments frame)
  428. (format stream "(~a~{ ~s~})" (core::backtrace-frame-print-name frame)
  429. (coerce (core::backtrace-frame-arguments frame) 'list))
  430. (format stream "~a" (core::backtrace-frame-print-name frame))))
  431. (defimplementation frame-source-location (frame-number)
  432. (let* ((address (core::backtrace-frame-return-address (elt *backtrace* frame-number)))
  433. (code-source-location (ext::code-source-position address)))
  434. (format t "code-source-location ~s~%" code-source-location)
  435. ;; (core::source-info-backtrace *backtrace*)
  436. (make-location (list :file (namestring (ext::code-source-line-source-pathname code-source-location)))
  437. (list :line (ext::code-source-line-line-number code-source-location))
  438. '(:align t))))
  439. #+clasp-working
  440. (defimplementation frame-catch-tags (frame-number)
  441. (third (elt *backtrace* frame-number)))
  442. (defun ihs-frame-id (frame-number)
  443. (- (core:ihs-top) frame-number))
  444. (defimplementation frame-locals (frame-number)
  445. (let* ((frame (elt *backtrace* frame-number))
  446. (env nil) ; no env yet
  447. (locals (loop for x = env then (core:get-parent-environment x)
  448. while x
  449. nconc (loop for name across (core:environment-debug-names x)
  450. for value across (core:environment-debug-values x)
  451. collect (list :name name :id 0 :value value)))))
  452. (nconc
  453. (loop for arg across (core::backtrace-frame-arguments frame)
  454. for i from 0
  455. collect (list :name (intern (format nil "ARG~d" i) :cl-user)
  456. :id 0
  457. :value arg))
  458. locals)))
  459. (defimplementation frame-var-value (frame-number var-number)
  460. (let* ((frame (elt *backtrace* frame-number))
  461. (env nil)
  462. (args (core::backtrace-frame-arguments frame)))
  463. (if (< var-number (length args))
  464. (svref args var-number)
  465. (elt (frame-locals frame-number) var-number))))
  466. (defimplementation disassemble-frame (frame-number)
  467. (let ((fun (frame-function frame-number)))
  468. (disassemble fun)))
  469. (defimplementation eval-in-frame (form frame-number)
  470. (let* ((frame (elt *backtrace* frame-number))
  471. (raw-arg-values (coerce (core::backtrace-frame-arguments frame) 'list)))
  472. (if (and (= (length raw-arg-values) 2) (core:vaslistp (car raw-arg-values)))
  473. (let* ((arg-values (core:list-from-va-list (car raw-arg-values)))
  474. (bindings (append (loop for i from 0 for value in arg-values collect `(,(intern (core:bformat nil "ARG%d" i) :cl-user) ',value))
  475. (list (list (intern "NEXT-METHODS" :cl-user) (cadr raw-arg-values))))))
  476. (eval
  477. `(let (,@bindings) ,form)))
  478. (let* ((arg-values raw-arg-values)
  479. (bindings (loop for i from 0 for value in arg-values collect `(,(intern (core:bformat nil "ARG%d" i) :cl-user) ',value))))
  480. (eval
  481. `(let (,@bindings) ,form))))))
  482. #+clasp-working
  483. (defimplementation gdb-initial-commands ()
  484. ;; These signals are used by the GC.
  485. #+linux '("handle SIGPWR noprint nostop"
  486. "handle SIGXCPU noprint nostop"))
  487. #+clasp-working
  488. (defimplementation command-line-args ()
  489. (loop for n from 0 below (si:argc) collect (si:argv n)))
  490. ;;;; Inspector
  491. ;;; FIXME: Would be nice if it was possible to inspect objects
  492. ;;; implemented in C.
  493. ;;;; Definitions
  494. (defun make-file-location (file file-position)
  495. ;; File positions in CL start at 0, but Emacs' buffer positions
  496. ;; start at 1. We specify (:ALIGN T) because the positions comming
  497. ;; from CLASP point at right after the toplevel form appearing before
  498. ;; the actual target toplevel form; (:ALIGN T) will DTRT in that case.
  499. (make-location `(:file ,(namestring (translate-logical-pathname file)))
  500. `(:position ,(1+ file-position))
  501. `(:align t)))
  502. (defun make-buffer-location (buffer-name start-position &optional (offset 0))
  503. (make-location `(:buffer ,buffer-name)
  504. `(:offset ,start-position ,offset)
  505. `(:align t)))
  506. (defun translate-location (location)
  507. (make-location (list :file (namestring (ext:source-location-pathname location)))
  508. (list :position (ext:source-location-offset location))
  509. '(:align t)))
  510. (defimplementation find-definitions (name)
  511. (loop for kind in ext:*source-location-kinds*
  512. for locations = (ext:source-location name kind)
  513. when locations
  514. nconc (loop for location in locations
  515. collect (list kind (translate-location location)))))
  516. (defun source-location (object)
  517. (let ((location (ext:source-location object t)))
  518. (when location
  519. (translate-location (car location)))))
  520. (defimplementation find-source-location (object)
  521. (or (source-location object)
  522. (make-error-location "Source definition of ~S not found." object)))
  523. ;;;; Profiling
  524. #+profile
  525. (progn
  526. (defimplementation profile (fname)
  527. (when fname (eval `(profile:profile ,fname))))
  528. (defimplementation unprofile (fname)
  529. (when fname (eval `(profile:unprofile ,fname))))
  530. (defimplementation unprofile-all ()
  531. (profile:unprofile-all)
  532. "All functions unprofiled.")
  533. (defimplementation profile-report ()
  534. (profile:report))
  535. (defimplementation profile-reset ()
  536. (profile:reset)
  537. "Reset profiling counters.")
  538. (defimplementation profiled-functions ()
  539. (profile:profile))
  540. (defimplementation profile-package (package callers methods)
  541. (declare (ignore callers methods))
  542. (eval `(profile:profile ,(package-name (find-package package)))))
  543. ) ; #+profile (progn ...
  544. ;;;; Threads
  545. #+threads
  546. (progn
  547. (defvar *thread-id-counter* 0)
  548. (defparameter *thread-id-map* (make-hash-table))
  549. (defvar *thread-id-map-lock*
  550. (mp:make-lock :name "thread id map lock"))
  551. (defimplementation spawn (fn &key name)
  552. (mp:process-run-function name fn))
  553. (defimplementation thread-id (target-thread)
  554. (block thread-id
  555. (mp:with-lock (*thread-id-map-lock*)
  556. ;; Does TARGET-THREAD have an id already?
  557. (maphash (lambda (id thread-pointer)
  558. (let ((thread (si:weak-pointer-value thread-pointer)))
  559. (cond ((not thread)
  560. (remhash id *thread-id-map*))
  561. ((eq thread target-thread)
  562. (return-from thread-id id)))))
  563. *thread-id-map*)
  564. ;; TARGET-THREAD not found in *THREAD-ID-MAP*
  565. (let ((id (incf *thread-id-counter*))
  566. (thread-pointer (si:make-weak-pointer target-thread)))
  567. (setf (gethash id *thread-id-map*) thread-pointer)
  568. id))))
  569. (defimplementation find-thread (id)
  570. (mp:with-lock (*thread-id-map-lock*)
  571. (let* ((thread-ptr (gethash id *thread-id-map*))
  572. (thread (and thread-ptr (si:weak-pointer-value thread-ptr))))
  573. (unless thread
  574. (remhash id *thread-id-map*))
  575. thread)))
  576. (defimplementation thread-name (thread)
  577. (mp:process-name thread))
  578. (defimplementation thread-status (thread)
  579. (if (mp:process-active-p thread)
  580. "RUNNING"
  581. "STOPPED"))
  582. (defimplementation make-lock (&key name)
  583. (mp:make-lock :name name :recursive t))
  584. (defimplementation call-with-lock-held (lock function)
  585. (declare (type function function))
  586. (mp:with-lock (lock) (funcall function)))
  587. (defimplementation current-thread ()
  588. mp:*current-process*)
  589. (defimplementation all-threads ()
  590. (mp:all-processes))
  591. (defimplementation interrupt-thread (thread fn)
  592. (mp:interrupt-process thread fn))
  593. (defimplementation kill-thread (thread)
  594. (mp:process-kill thread))
  595. (defimplementation thread-alive-p (thread)
  596. (mp:process-active-p thread))
  597. (defvar *mailbox-lock* (mp:make-lock :name "mailbox lock"))
  598. (defvar *mailboxes* (list))
  599. (declaim (type list *mailboxes*))
  600. (defstruct (mailbox (:conc-name mailbox.))
  601. thread
  602. (mutex (mp:make-lock :name "SLIMELCK"))
  603. (cvar (mp:make-condition-variable))
  604. (queue '() :type list))
  605. (defun mailbox (thread)
  606. "Return THREAD's mailbox."
  607. (mp:with-lock (*mailbox-lock*)
  608. (or (find thread *mailboxes* :key #'mailbox.thread)
  609. (let ((mb (make-mailbox :thread thread)))
  610. (push mb *mailboxes*)
  611. mb))))
  612. (defimplementation wake-thread (thread)
  613. (let* ((mbox (mailbox thread))
  614. (mutex (mailbox.mutex mbox)))
  615. (format t "About to with-lock in wake-thread~%")
  616. (mp:with-lock (mutex)
  617. (format t "In wake-thread~%")
  618. (mp:condition-variable-broadcast (mailbox.cvar mbox)))))
  619. (defimplementation send (thread message)
  620. (let* ((mbox (mailbox thread))
  621. (mutex (mailbox.mutex mbox)))
  622. (swank::log-event "clasp.lisp: send message ~a mutex: ~a~%" message mutex)
  623. (swank::log-event "clasp.lisp: (lock-owner mutex) -> ~a~%" (mp:lock-owner mutex))
  624. (swank::log-event "clasp.lisp: (lock-count mutex) -> ~a~%" (mp:lock-count mutex))
  625. (mp:with-lock (mutex)
  626. (swank::log-event "clasp.lisp: in with-lock (lock-owner mutex) -> ~a~%" (mp:lock-owner mutex))
  627. (swank::log-event "clasp.lisp: in with-lock (lock-count mutex) -> ~a~%" (mp:lock-count mutex))
  628. (setf (mailbox.queue mbox)
  629. (nconc (mailbox.queue mbox) (list message)))
  630. (swank::log-event "clasp.lisp: send about to broadcast~%")
  631. (mp:condition-variable-broadcast (mailbox.cvar mbox)))))
  632. (defimplementation receive-if (test &optional timeout)
  633. (slime-dbg "Entered receive-if")
  634. (let* ((mbox (mailbox (current-thread)))
  635. (mutex (mailbox.mutex mbox)))
  636. (slime-dbg "receive-if assert")
  637. (assert (or (not timeout) (eq timeout t)))
  638. (loop
  639. (slime-dbg "receive-if check-slime-interrupts")
  640. (check-slime-interrupts)
  641. (slime-dbg "receive-if with-lock")
  642. (mp:with-lock (mutex)
  643. (let* ((q (mailbox.queue mbox))
  644. (tail (member-if test q)))
  645. (when tail
  646. (setf (mailbox.queue mbox) (nconc (ldiff q tail) (cdr tail)))
  647. (return (car tail))))
  648. (slime-dbg "receive-if when (eq")
  649. (when (eq timeout t) (return (values nil t)))
  650. (slime-dbg "receive-if condition-variable-timedwait")
  651. (mp:condition-variable-wait (mailbox.cvar mbox) mutex) ; timedwait 0.2
  652. (slime-dbg "came out of condition-variable-timedwait")
  653. (core:check-pending-interrupts)))))
  654. ) ; #+threads (progn ...
  655. (defmethod emacs-inspect ((object core:cxx-object))
  656. (let ((encoded (core:encode object)))
  657. (loop for (key . value) in encoded
  658. append (list (string key) ": " (list :value value) (list :newline)))))