aboutsummaryrefslogtreecommitdiffstats
path: root/src/alloc.c
diff options
context:
space:
mode:
authorDaniel Colascione2015-03-02 02:23:09 -0800
committerDaniel Colascione2015-03-02 15:39:01 -0800
commit9d8d0658147dfe5a90e2fb07ff666f35b1162d6e (patch)
tree6d593ab42386348b1842688c75f892db45c5b59e /src/alloc.c
parentb149ecd8aa3aa9c179dd5496f64e1f50750414fa (diff)
downloademacs-9d8d0658147dfe5a90e2fb07ff666f35b1162d6e.tar.gz
emacs-9d8d0658147dfe5a90e2fb07ff666f35b1162d6e.zip
Add support for finalizers
+2015-03-02 Daniel Colascione <dancol@dancol.org> + + * NEWS: Mention finalizers. + 2015-02-09 Gareth Rees <gdr@garethrees.org> (tiny change) * NEWS.24: Fix typo (bug#19820) diff --git a/src/ChangeLog b/src/ChangeLog index 4aa64c1..2f04d0b 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,21 @@ +2015-03-02 Daniel Colascione <dancol@dancol.org> + + * print.c (print_object): Print finalizers. + + * alloc.c: + (finalizers, doomed_finalizers): New variables. + (init_finalizer_list, finalizer_insert, unchain_finalizer) + (mark_finalizer_list, queue_doomed_finalizers) + (run_finalizer_handler, run_finalizer_function, run_finalizers): + New functions. + (garbage_collect_1, mark_object, sweep_misc) + (init_alloc_once, syms_of_alloc): Support finalizers. + (gc-precise-p): New Lisp variable. + + * lisp.h (Lisp_Misc_Type): New value Lisp_Misc_Finalizer. + (FINALIZERP, XFINALIZER): New functions. + (Lisp_Finalizer): New structure. + 2015-02-28 Paul Eggert <eggert@cs.ucla.edu> * character.c (alphabeticp, decimalnump): Avoid undefined behavior diff --git a/test/ChangeLog b/test/ChangeLog index cf1b2c1..684e98f 100644 --- a/test/ChangeLog +++ b/test/ChangeLog @@ -1,3 +1,9 @@ +2015-03-02 Daniel Colascione <dancol@dancol.org> + + * automated/finalizer-tests.el (finalizer-basic) + (finalizer-circular-reference, finalizer-cross-reference) + (finalizer-error): New tests. + 2015-03-01 Michael Albinus <michael.albinus@gmx.de> * automated/vc-tests.el (vc-test--create-repo): Add check for
Diffstat (limited to 'src/alloc.c')
-rw-r--r--src/alloc.c172
1 files changed, 167 insertions, 5 deletions
diff --git a/src/alloc.c b/src/alloc.c
index 9aa94b8a559..eec53e7d844 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -441,6 +441,15 @@ mmap_lisp_allowed_p (void)
441 return pointers_fit_in_lispobj_p () && !might_dump; 441 return pointers_fit_in_lispobj_p () && !might_dump;
442} 442}
443 443
444/* Head of a circularly-linked list of extant finalizers. */
445static struct Lisp_Finalizer finalizers;
446
447/* Head of a circularly-linked list of finalizers that must be invoked
448 because we deemed them unreachable. This list must be global, and
449 not a local inside garbage_collect_1, in case we GC again while
450 running finalizers. */
451static struct Lisp_Finalizer doomed_finalizers;
452
444 453
445/************************************************************************ 454/************************************************************************
446 Malloc 455 Malloc
@@ -3695,6 +3704,131 @@ make_event_array (ptrdiff_t nargs, Lisp_Object *args)
3695 } 3704 }
3696} 3705}
3697 3706
3707static void
3708init_finalizer_list (struct Lisp_Finalizer *head)
3709{
3710 head->prev = head->next = head;
3711}
3712
3713/* Insert FINALIZER before ELEMENT. */
3714
3715static void
3716finalizer_insert (struct Lisp_Finalizer *element,
3717 struct Lisp_Finalizer* finalizer)
3718{
3719 eassert (finalizer->prev == NULL);
3720 eassert (finalizer->next == NULL);
3721 finalizer->next = element;
3722 finalizer->prev = element->prev;
3723 finalizer->prev->next = finalizer;
3724 element->prev = finalizer;
3725}
3726
3727static void
3728unchain_finalizer (struct Lisp_Finalizer *finalizer)
3729{
3730 if (finalizer->prev != NULL) {
3731 eassert (finalizer->next != NULL);
3732 finalizer->prev->next = finalizer->next;
3733 finalizer->next->prev = finalizer->prev;
3734 finalizer->prev = finalizer->next = NULL;
3735 }
3736}
3737
3738static void
3739mark_finalizer_list (struct Lisp_Finalizer *head)
3740{
3741 for (struct Lisp_Finalizer *finalizer = head->next;
3742 finalizer != head;
3743 finalizer = finalizer->next)
3744 {
3745 finalizer->base.gcmarkbit = 1;
3746 mark_object (finalizer->function);
3747 }
3748}
3749
3750/* Move doomed finalizers in list SRC onto list DEST. A doomed
3751 finalizer is one that is not GC-reachable and whose
3752 finalizer->function is non-nil. (We reset finalizer->function to
3753 before attempting to run it.) */
3754
3755static void
3756queue_doomed_finalizers (struct Lisp_Finalizer *dest,
3757 struct Lisp_Finalizer *src)
3758{
3759 struct Lisp_Finalizer* finalizer = src->next;
3760 while (finalizer != src)
3761 {
3762 struct Lisp_Finalizer *next = finalizer->next;
3763 if (!finalizer->base.gcmarkbit && !NILP (finalizer->function))
3764 {
3765 unchain_finalizer (finalizer);
3766 finalizer_insert (dest, finalizer);
3767 }
3768
3769 finalizer = next;
3770 }
3771}
3772
3773static Lisp_Object
3774run_finalizer_handler (Lisp_Object args)
3775{
3776 add_to_log ("finalizer failed: %S", args, Qnil);
3777 return Qnil;
3778}
3779
3780static void
3781run_finalizer_function (Lisp_Object function)
3782{
3783 struct gcpro gcpro1;
3784 ptrdiff_t count = SPECPDL_INDEX ();
3785
3786 GCPRO1 (function);
3787 specbind (Qinhibit_quit, Qt);
3788 internal_condition_case_1 (call0, function, Qt, run_finalizer_handler);
3789 unbind_to (count, Qnil);
3790 UNGCPRO;
3791}
3792
3793static void
3794run_finalizers (struct Lisp_Finalizer* finalizers)
3795{
3796 struct Lisp_Finalizer* finalizer;
3797 Lisp_Object function;
3798 struct gcpro gcpro1;
3799
3800 while (finalizers->next != finalizers) {
3801 finalizer = finalizers->next;
3802 eassert (finalizer->base.type == Lisp_Misc_Finalizer);
3803 unchain_finalizer (finalizer);
3804 function = finalizer->function;
3805 if (!NILP (function))
3806 {
3807 finalizer->function = Qnil;
3808 run_finalizer_function (function);
3809 }
3810 }
3811}
3812
3813DEFUN ("make-finalizer", Fmake_finalizer, Smake_finalizer, 1, 1, 0,
3814 doc: /* Make a finalizer that will run FUNCTION.
3815FUNCTION will be called after garbage collection when the returned
3816finalizer object becomes unreachable. If the finalizer object is
3817reachable only through references from finalizer objects, it does not
3818count as reachable for the purpose of deciding whether to run
3819FUNCTION. FUNCTION will be run once per finalizer object. */)
3820 (Lisp_Object function)
3821{
3822 Lisp_Object val;
3823 struct Lisp_Finalizer *finalizer;
3824
3825 val = allocate_misc (Lisp_Misc_Finalizer);
3826 finalizer = XFINALIZER (val);
3827 finalizer->function = function;
3828 finalizer->prev = finalizer->next = NULL;
3829 finalizer_insert (&finalizers, finalizer);
3830 return val;
3831}
3698 3832
3699 3833
3700/************************************************************************ 3834/************************************************************************
@@ -5613,9 +5747,9 @@ garbage_collect_1 (void *end)
5613 mark_stack (end); 5747 mark_stack (end);
5614#endif 5748#endif
5615 5749
5616 /* Everything is now marked, except for the data in font caches 5750 /* Everything is now marked, except for the data in font caches,
5617 and undo lists. They're compacted by removing an items which 5751 undo lists, and finalizers. The first two are compacted by
5618 aren't reachable otherwise. */ 5752 removing an items which aren't reachable otherwise. */
5619 5753
5620 compact_font_caches (); 5754 compact_font_caches ();
5621 5755
@@ -5628,6 +5762,16 @@ garbage_collect_1 (void *end)
5628 mark_object (BVAR (nextb, undo_list)); 5762 mark_object (BVAR (nextb, undo_list));
5629 } 5763 }
5630 5764
5765 /* Now pre-sweep finalizers. Here, we add any unmarked finalizers
5766 to doomed_finalizers so we can run their associated functions
5767 after GC. It's important to scan finalizers at this stage so
5768 that we can be sure that unmarked finalizers are really
5769 unreachable except for references from their associated functions
5770 and from other finalizers. */
5771
5772 queue_doomed_finalizers (&doomed_finalizers, &finalizers);
5773 mark_finalizer_list (&doomed_finalizers);
5774
5631 gc_sweep (); 5775 gc_sweep ();
5632 5776
5633 /* Clear the mark bits that we set in certain root slots. */ 5777 /* Clear the mark bits that we set in certain root slots. */
@@ -5728,6 +5872,9 @@ garbage_collect_1 (void *end)
5728 } 5872 }
5729#endif 5873#endif
5730 5874
5875 /* GC is complete: now we can run our finalizer callbacks. */
5876 run_finalizers (&doomed_finalizers);
5877
5731 if (!NILP (Vpost_gc_hook)) 5878 if (!NILP (Vpost_gc_hook))
5732 { 5879 {
5733 ptrdiff_t gc_count = inhibit_garbage_collection (); 5880 ptrdiff_t gc_count = inhibit_garbage_collection ();
@@ -6364,7 +6511,12 @@ mark_object (Lisp_Object arg)
6364 6511
6365 case Lisp_Misc_Overlay: 6512 case Lisp_Misc_Overlay:
6366 mark_overlay (XOVERLAY (obj)); 6513 mark_overlay (XOVERLAY (obj));
6367 break; 6514 break;
6515
6516 case Lisp_Misc_Finalizer:
6517 XMISCANY (obj)->gcmarkbit = 1;
6518 mark_object (XFINALIZER (obj)->function);
6519 break;
6368 6520
6369 default: 6521 default:
6370 emacs_abort (); 6522 emacs_abort ();
@@ -6746,6 +6898,8 @@ sweep_misc (void)
6746 { 6898 {
6747 if (mblk->markers[i].m.u_any.type == Lisp_Misc_Marker) 6899 if (mblk->markers[i].m.u_any.type == Lisp_Misc_Marker)
6748 unchain_marker (&mblk->markers[i].m.u_marker); 6900 unchain_marker (&mblk->markers[i].m.u_marker);
6901 if (mblk->markers[i].m.u_any.type == Lisp_Misc_Finalizer)
6902 unchain_finalizer (&mblk->markers[i].m.u_finalizer);
6749 /* Set the type of the freed object to Lisp_Misc_Free. 6903 /* Set the type of the freed object to Lisp_Misc_Free.
6750 We could leave the type alone, since nobody checks it, 6904 We could leave the type alone, since nobody checks it,
6751 but this might catch bugs faster. */ 6905 but this might catch bugs faster. */
@@ -7115,11 +7269,14 @@ init_alloc_once (void)
7115{ 7269{
7116 /* Even though Qt's contents are not set up, its address is known. */ 7270 /* Even though Qt's contents are not set up, its address is known. */
7117 Vpurify_flag = Qt; 7271 Vpurify_flag = Qt;
7272 gc_precise_p = (GC_MARK_STACK == GC_USE_GCPROS_AS_BEFORE);
7118 7273
7119 purebeg = PUREBEG; 7274 purebeg = PUREBEG;
7120 pure_size = PURESIZE; 7275 pure_size = PURESIZE;
7121 7276
7122 verify_alloca (); 7277 verify_alloca ();
7278 init_finalizer_list (&finalizers);
7279 init_finalizer_list (&doomed_finalizers);
7123 7280
7124#if GC_MARK_STACK || defined GC_MALLOC_CHECK 7281#if GC_MARK_STACK || defined GC_MALLOC_CHECK
7125 mem_init (); 7282 mem_init ();
@@ -7254,7 +7411,11 @@ do hash-consing of the objects allocated to pure space. */);
7254 doc: /* Accumulated time elapsed in garbage collections. 7411 doc: /* Accumulated time elapsed in garbage collections.
7255The time is in seconds as a floating point value. */); 7412The time is in seconds as a floating point value. */);
7256 DEFVAR_INT ("gcs-done", gcs_done, 7413 DEFVAR_INT ("gcs-done", gcs_done,
7257 doc: /* Accumulated number of garbage collections done. */); 7414 doc: /* Accumulated number of garbage collections done. */);
7415
7416 DEFVAR_BOOL ("gc-precise-p", gc_precise_p,
7417 doc: /* Non-nil means GC stack marking is precise.
7418Useful mainly for automated GC tests. Build time constant.*/);
7258 7419
7259 defsubr (&Scons); 7420 defsubr (&Scons);
7260 defsubr (&Slist); 7421 defsubr (&Slist);
@@ -7267,6 +7428,7 @@ The time is in seconds as a floating point value. */);
7267 defsubr (&Smake_bool_vector); 7428 defsubr (&Smake_bool_vector);
7268 defsubr (&Smake_symbol); 7429 defsubr (&Smake_symbol);
7269 defsubr (&Smake_marker); 7430 defsubr (&Smake_marker);
7431 defsubr (&Smake_finalizer);
7270 defsubr (&Spurecopy); 7432 defsubr (&Spurecopy);
7271 defsubr (&Sgarbage_collect); 7433 defsubr (&Sgarbage_collect);
7272 defsubr (&Smemory_limit); 7434 defsubr (&Smemory_limit);