unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Catch arbitrary signal and throw it later in C
@ 2023-04-13  7:24 Yuan Fu
  2023-04-13  7:33 ` Ruijie Yu via Emacs development discussions.
  0 siblings, 1 reply; 8+ messages in thread
From: Yuan Fu @ 2023-04-13  7:24 UTC (permalink / raw)
  To: emacs-devel

Say I have an arbitrary Lisp function func, and need to evaluate it in C. But after evaluating the function, I need to do some clean up (freeing something). Would be be possible to catch any signal thrown by evaluating the function func, and throw it after cleaning up?

I’m aware of safe_call and internal_condition_case_n. In particular, what I described can probably be implemented with internal_condition_case_n with a handler. But I wonder if there are better/existing ways to do this?

The real scenarios is this: treesit-search-forward and friends takes a PRED argument, which can be either a regexp string or a predicate function. In the meantime, treesit-search-forward and friends need to clean up a tree-sitter cursor object before they return. So if this predicate function signals in the middle of treesit-search-forward, the tree-sitter cursor would be leaked. I can slap on a safe_call when evaluating the predicate function, but I think throwing the signal would be more user-friendly. (Plus safe_call will say “An error occurred during redisplay”, which isn’t necessarily true)

Yuan





^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Catch arbitrary signal and throw it later in C
  2023-04-13  7:24 Catch arbitrary signal and throw it later in C Yuan Fu
@ 2023-04-13  7:33 ` Ruijie Yu via Emacs development discussions.
  2023-04-13  8:12   ` Yuan Fu
  0 siblings, 1 reply; 8+ messages in thread
From: Ruijie Yu via Emacs development discussions. @ 2023-04-13  7:33 UTC (permalink / raw)
  To: Yuan Fu; +Cc: emacs-devel


Yuan Fu <casouri@gmail.com> writes:

> Say I have an arbitrary Lisp function func, and need to evaluate it in C. But
> after evaluating the function, I need to do some clean up (freeing
> something). Would be be possible to catch any signal thrown by evaluating the
> function func, and throw it after cleaning up?

Isn't `unwind-protect' (or its internal C functionalities) what you
want, or is it not suitable in Emacs-C land?  This macro is defined in
C, FTR.

-- 
Best,


RY



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Catch arbitrary signal and throw it later in C
  2023-04-13  7:33 ` Ruijie Yu via Emacs development discussions.
@ 2023-04-13  8:12   ` Yuan Fu
  2023-04-13  8:20     ` Eli Zaretskii
                       ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Yuan Fu @ 2023-04-13  8:12 UTC (permalink / raw)
  To: Ruijie Yu; +Cc: emacs-devel



> On Apr 13, 2023, at 12:33 AM, Ruijie Yu <ruijie@netyu.xyz> wrote:
> 
> 
> Yuan Fu <casouri@gmail.com> writes:
> 
>> Say I have an arbitrary Lisp function func, and need to evaluate it in C. But
>> after evaluating the function, I need to do some clean up (freeing
>> something). Would be be possible to catch any signal thrown by evaluating the
>> function func, and throw it after cleaning up?
> 
> Isn't `unwind-protect' (or its internal C functionalities) what you
> want, or is it not suitable in Emacs-C land?  This macro is defined in
> C, FTR.

unwind-protect (and its internal C counterpart) pushes the cleanup form onto specpdl. Supposingly that form is later eval’ed? I want to run some C code which obviously it doesn’t support. I need to understand how this whole unwinding thing work before I can maybe modify or write something that does what I want. Hopefully some one can enlighten me :-)

Yuan


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Catch arbitrary signal and throw it later in C
  2023-04-13  8:12   ` Yuan Fu
@ 2023-04-13  8:20     ` Eli Zaretskii
  2023-04-13  8:22     ` Po Lu
  2023-04-13  8:24     ` Andreas Schwab
  2 siblings, 0 replies; 8+ messages in thread
From: Eli Zaretskii @ 2023-04-13  8:20 UTC (permalink / raw)
  To: Yuan Fu; +Cc: ruijie, emacs-devel

> From: Yuan Fu <casouri@gmail.com>
> Date: Thu, 13 Apr 2023 01:12:37 -0700
> Cc: emacs-devel@gnu.org
> 
> > Isn't `unwind-protect' (or its internal C functionalities) what you
> > want, or is it not suitable in Emacs-C land?  This macro is defined in
> > C, FTR.
> 
> unwind-protect (and its internal C counterpart) pushes the cleanup form onto specpdl. Supposingly that form is later eval’ed?

It is evaluated when you call unbind_to (which you must, when you use
record_unwind_protect etc.).



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Catch arbitrary signal and throw it later in C
  2023-04-13  8:12   ` Yuan Fu
  2023-04-13  8:20     ` Eli Zaretskii
@ 2023-04-13  8:22     ` Po Lu
  2023-04-13 22:18       ` Yuan Fu
  2023-04-13  8:24     ` Andreas Schwab
  2 siblings, 1 reply; 8+ messages in thread
From: Po Lu @ 2023-04-13  8:22 UTC (permalink / raw)
  To: Yuan Fu; +Cc: Ruijie Yu, emacs-devel

Yuan Fu <casouri@gmail.com> writes:

> unwind-protect (and its internal C counterpart) pushes the cleanup
> form onto specpdl. Supposingly that form is later eval’ed? I want to
> run some C code which obviously it doesn’t support. I need to
> understand how this whole unwinding thing work before I can maybe
> modify or write something that does what I want. Hopefully some one
> can enlighten me :-)

Typically, you do this:

  specpdl_ref count;
  struct localcontext context;

  count = SPECPDL_INDEX ();
  record_unwind_protect_ptr (cleanup_func, &context);

  /* Code which may signal.  */

  unbind_to (count, Qnil);

where cleanup_func is:

  void
  cleanup_func (void *arg)

Once a signal happens between the `record_unwind_protect_ptr', and
`unbind_to', `cleanup_func' will be called with `&context' as an
argument.  This happens before any longjmp, so it is safe to use
references to variables with automatic storage duration within unwind
protects you record.

Note that `record_unwind_protect_ptr' itself may also signal if the
specpdl is full, calling the unwind function in the process.

If your cleanup function needs arguments that aren't pointers, you can
also use `record_unwind_protect_int', `record_unwind_protect', or
`record_unwind_protect_void'.

Saving a signal, only to throw it again later, is not something we do in
Emacs.  I suggest you make your cleanup code work as described above.



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Catch arbitrary signal and throw it later in C
  2023-04-13  8:12   ` Yuan Fu
  2023-04-13  8:20     ` Eli Zaretskii
  2023-04-13  8:22     ` Po Lu
@ 2023-04-13  8:24     ` Andreas Schwab
  2 siblings, 0 replies; 8+ messages in thread
From: Andreas Schwab @ 2023-04-13  8:24 UTC (permalink / raw)
  To: Yuan Fu; +Cc: Ruijie Yu, emacs-devel

The internal counterpart of unwind-protect is record_unwind_protect.  It
does exactly what you need.

-- 
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Catch arbitrary signal and throw it later in C
  2023-04-13  8:22     ` Po Lu
@ 2023-04-13 22:18       ` Yuan Fu
  2023-04-13 23:48         ` Po Lu
  0 siblings, 1 reply; 8+ messages in thread
From: Yuan Fu @ 2023-04-13 22:18 UTC (permalink / raw)
  To: Po Lu; +Cc: Ruijie Yu, emacs-devel



> On Apr 13, 2023, at 1:22 AM, Po Lu <luangruo@yahoo.com> wrote:
> 
> Yuan Fu <casouri@gmail.com> writes:
> 
>> unwind-protect (and its internal C counterpart) pushes the cleanup
>> form onto specpdl. Supposingly that form is later eval’ed? I want to
>> run some C code which obviously it doesn’t support. I need to
>> understand how this whole unwinding thing work before I can maybe
>> modify or write something that does what I want. Hopefully some one
>> can enlighten me :-)
> 
> Typically, you do this:
> 
>  specpdl_ref count;
>  struct localcontext context;
> 
>  count = SPECPDL_INDEX ();
>  record_unwind_protect_ptr (cleanup_func, &context);
> 
>  /* Code which may signal.  */
> 
>  unbind_to (count, Qnil);
> 
> where cleanup_func is:
> 
>  void
>  cleanup_func (void *arg)
> 
> Once a signal happens between the `record_unwind_protect_ptr', and
> `unbind_to', `cleanup_func' will be called with `&context' as an
> argument.  This happens before any longjmp, so it is safe to use
> references to variables with automatic storage duration within unwind
> protects you record.
> 
> Note that `record_unwind_protect_ptr' itself may also signal if the
> specpdl is full, calling the unwind function in the process.
> 
> If your cleanup function needs arguments that aren't pointers, you can
> also use `record_unwind_protect_int', `record_unwind_protect', or
> `record_unwind_protect_void'.

Thanks, this is very clear and helpful. So the signal routine will unwind the pdl and run my cleanup function, right? And if no signal happens, my cleanup function is removed from the pdl by unbind_to.

> 
> Saving a signal, only to throw it again later, is not something we do in
> Emacs.  I suggest you make your cleanup code work as described above.

Right. What you’ve shown is actually exactly what I need. As long as the cleanup runs and the signal is thrown, I’m good.

Yuan


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Catch arbitrary signal and throw it later in C
  2023-04-13 22:18       ` Yuan Fu
@ 2023-04-13 23:48         ` Po Lu
  0 siblings, 0 replies; 8+ messages in thread
From: Po Lu @ 2023-04-13 23:48 UTC (permalink / raw)
  To: Yuan Fu; +Cc: Ruijie Yu, emacs-devel

Yuan Fu <casouri@gmail.com> writes:

> Thanks, this is very clear and helpful. So the signal routine will
> unwind the pdl and run my cleanup function, right? And if no signal
> happens, my cleanup function is removed from the pdl by unbind_to.

The cleanup function is still run in that case.  If you don't want it to
be run, you have to call:

  clear_unwind_protect (count);

prior to calling `unbind_to'.



^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2023-04-13 23:48 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-04-13  7:24 Catch arbitrary signal and throw it later in C Yuan Fu
2023-04-13  7:33 ` Ruijie Yu via Emacs development discussions.
2023-04-13  8:12   ` Yuan Fu
2023-04-13  8:20     ` Eli Zaretskii
2023-04-13  8:22     ` Po Lu
2023-04-13 22:18       ` Yuan Fu
2023-04-13 23:48         ` Po Lu
2023-04-13  8:24     ` Andreas Schwab

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).