-
Notifications
You must be signed in to change notification settings - Fork 56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
roseusでresetしないとone-shot-subscribeが使えない #666
Comments
僕も一緒にデバッグしていたのですが、「resetに効果がありそう」というところまでしか分からず、根本的な解決理由が分かりませんでした。 |
Ok, this was actually quite interesting to take a look at, and I think I have figured it out. The problem revolves around the fact that the Particularly, there are three aspects creating this bug:
Try the following:
There are a few possible solutions to this, but I would just reject cases in which |
(I would also like to add some self-advertising and say that with a proper exception handling framework we could for example ensure that the topic has been unsubscribed before proceeding to the next repl) |
Thank you very much for the explanation. I understand the root of the problem a little better now. As I understand it, the function
Excuse me, but I have an additional question: I would like to know the difference between the following two cases.
|
Here is an annotated example. ;;;; Create a "pointer-closure"
eus$ (let (a) (defvar fn #'(lambda () (setq a 1))))
;; fn
eus$ fn
;; (lambda-closure nil 94458722936800 0 nil (setq a 1))
;;;; Observe that any occurence of `(let (a) ...)' will lead to the same pointer location
eus$ (let (a) #'(lambda () nil))
;; (lambda-closure nil 94458722936800 0 nil nil)
eus$ (let (a) #'(lambda () nil))
;; (lambda-closure nil 94458722936800 0 nil nil)
eus$ (let (a) (sys:list-all-bindings))
;; ((a))
;;;; Enter a new repl
eus$ (let (a) (error "this"))
;; eus 0 error: this in (error "this")
;;;; The lexical environment of the time of the error is preserved
;;;; (which is what allows for dynamic-eval debugging)
E1-eus$ (sys:list-all-bindings)
;; ((a))
;;;; Now I'm not sure why, but in this new repl the allocation for `(let (a) ...)' goes to a different pointer
E1-eus$ (let (a) #'(lambda () nil))
;; (lambda-closure nil 94458722937456 0 nil nil)
E1-eus$ (let (a) #'(lambda () nil))
;; (lambda-closure nil 94458722937456 0 nil nil)
E1-eus$ (let (a) (sys:list-all-bindings))
;; ((a) (a))
;;;; So when we invoke the function the value is set on the second environment
;;;; But since value references point to the first value it always remains null
E1-eus$ (let (a) (funcall fn) (sys:list-all-bindings))
;; ((a) (a . 1))
;;;; Reset to the original repl
E1-eus$ reset
;;;; There are no active environments and frame allocation goes to the same pointer as before
eus$ (sys:list-all-bindings)
;; nil
eus$ (let (a) #'(lambda () nil))
;; (lambda-closure nil 94458722936800 0 nil nil)
;;;; So if we recreate the `(let (a) ...)' environment and invoke the function everything goes well
;;;; (this is why calling one-shot-subscribe here works even with an outdated callback)
eus$ (let (a) (funcall fn) (sys:list-all-bindings))
;; ((a . 1))
;;;; I am not sure how this works as well, but pointer allocation also seems to work differently for nested frames
;;;; Note that the pointer for the same active `(let (a) ...)' environment is different
eus$ (let (b) (let (a) #'(lambda () nil)))
;; (lambda-closure nil 94458722936856 0 nil nil)
;;;; So what happens here is that the original frame at 94458722936800 is not active anymore,
;;;; and since the symbol `a' cannot be located at any dynamic frame the global value is set instead.
;;;; (for all I know the process could easily segfault at this time, but probably we have some fail safe code identifying that the frame is not active and reallocating to a global environment?)
eus$ (let (b) (let (a) (funcall fn) (sys:list-all-bindings)))
;; ((a) (b))
eus$ a
;; 1 |
@Affonso-Gui After talking to @pazeshun, I learned that similar problems have been reported before. We have also discovered a more bad bug behavior. We believe this is fatal because the bug occurs without using
Here is a summary of the current problems.
In response to these problems, @YoheiKakiuchi gave me the following advices.
Currently, I think
I am working on the following branch to modify one-shot-subscribe. I will create PR if these solutions seems good. |
Some more problems:
A few drawbacks to your solution:
My solution for problems 1-4:
My solution for problems 5-6: (defclass my-sub :slots (topic msgtype msg))
(defmethod my-sub
(:init (_topic _msgtype)
(setq topic _topic)
(setq msgtype _msgtype)
self)
(:update (_msg) (setq msg _msg))
(:get () msg))
(defun my-one-shot (topic msgtype)
(let ((sub (instance my-sub :init topic msgtype)))
(ros::subscribe topic msgtype #'send sub :update)
(while (not (send sub :get))
(ros::spin-once))
(send sub :get))) The subscriber registered by this code is EDIT: Yes, I completely oversaw how topic and msgtype are not actually required by the helper class... |
Thank you for your advice! I commited your solutions in #667 Excuse me, but I have another question.
I think problem 5. is similar to the following case.
Then how can I reproduce problem 6.? |
I'll check that PR right away. Yes, problem 6 is hard to reproduce because |
After revisiting this issue I actually have some corrections on the annotated example:
What happens here is that the new bind frame is allocated on top of the vsp, meaning that the more stacks we have the bigger the address will be. The address depends on the order of the frames, and not on the variables. (let (a)
(print (third #'(lambda ())))
(let (b)
(print (third #'(lambda ())))
(let (c)
(print (third #'(lambda ()))))))
94786309311104
94786309311160
94786309311216
(let (a)
(print (- (third #'(lambda ())) 94786309311104))
(let (b)
(print (- (third #'(lambda ())) 94786309311104))
(let (c)
(print (- (third #'(lambda ())) 94786309311104))
(let (d)
(print (- (third #'(lambda ())) 94786309311104))))))
0
56
112
168
It is not that the original frame is not active anymore, but rather that the address is now used by a different frame, in this case the The reverse order works as expected: eus$ (let (a) (let (b) (funcall fn) (sys:list-all-bindings)))
;; ((b) (a . 1))
There is a fail safe structure that forces global framing (https://github.com/euslisp/EusLisp/blob/master/lisp/c/eval.c#L1586-L1587), but it is not the case for this example. |
Fetchで音声認識をさせているときにone-shot-subscribeが返ってこないことがありました。かんたんなケースで再現させたのが以下になります。
one-shot-subscribeを呼んでトピックを待っている最中にCtrl-cで止めてもう一度one-shot-subscribeを起動するとsubscribeされない。
Ctrl-cの後にresetを入れると正しくsubscribeされる。
resetにはどのような効果があるのか知りたいです。
@708yamaguchi
再現コード
ターミナル1
ターミナル2
The text was updated successfully, but these errors were encountered: