Skip to content
Permalink
Browse files

Switch destructors to using a linked list with backreferences.

This changes the complexity of _al_unregister_destructor from O(N) to O(1).

The backreferences will increase the memory used, but hopefully not
significantly so.

Fixes #640
  • Loading branch information...
SiegeLordEx authored and SiegeLord committed Jun 26, 2016
1 parent 6074080 commit bd166530082f1e6bdb34bd03d3fbc82143bcd761
@@ -6,6 +6,7 @@
#define AINTERN_AUDIO_H

#include "allegro5/allegro.h"
#include "allegro5/internal/aintern_list.h"
#include "allegro5/internal/aintern_vector.h"
#include "../allegro_audio.h"

@@ -116,6 +117,8 @@ struct ALLEGRO_VOICE {
ALLEGRO_MUTEX *mutex;
ALLEGRO_COND *cond;

_AL_LIST_ITEM *dtor_item;

ALLEGRO_AUDIO_DRIVER *driver;
/* XXX shouldn't there only be one audio driver active
* at a time?
@@ -147,6 +150,7 @@ struct ALLEGRO_SAMPLE {
/* Whether `buffer' needs to be freed when the sample
* is destroyed, or when `buffer' changes.
*/
_AL_LIST_ITEM *dtor_item;
};

/* Read some samples into a mixer buffer.
@@ -232,6 +236,7 @@ struct ALLEGRO_SAMPLE_INSTANCE {
sample_parent_t parent;
/* The object that this sample is attached to, if any.
*/
_AL_LIST_ITEM *dtor_item;
};

void _al_kcm_destroy_sample(ALLEGRO_SAMPLE_INSTANCE *sample, bool unregister);
@@ -308,6 +313,8 @@ struct ALLEGRO_AUDIO_STREAM {
* streams don't need to be fed by the user.
*/

_AL_LIST_ITEM *dtor_item;

void *extra;
/* Extra data for use by the flac/vorbis addons. */
};
@@ -337,6 +344,7 @@ struct ALLEGRO_MIXER {
/* Vector of ALLEGRO_SAMPLE_INSTANCE*. Holds the list of
* streams being mixed together.
*/
_AL_LIST_ITEM *dtor_item;
};

extern void _al_kcm_mixer_rejig_sample_matrix(ALLEGRO_MIXER *mixer,
@@ -362,9 +370,9 @@ void _al_kcm_emit_stream_events(ALLEGRO_AUDIO_STREAM *stream);

void _al_kcm_init_destructors(void);
void _al_kcm_shutdown_destructors(void);
void _al_kcm_register_destructor(char const *name, void *object,
_AL_LIST_ITEM *_al_kcm_register_destructor(char const *name, void *object,
void (*func)(void*));
void _al_kcm_unregister_destructor(void *object);
void _al_kcm_unregister_destructor(_AL_LIST_ITEM *dtor_item);
void _al_kcm_foreach_destructor(
void (*callback)(void *object, void (*func)(void *), void *udata),
void *userdata);
@@ -53,19 +53,19 @@ void _al_kcm_shutdown_destructors(void)
/* _al_kcm_register_destructor:
* Register an object to be destroyed.
*/
void _al_kcm_register_destructor(char const *name, void *object,
_AL_LIST_ITEM *_al_kcm_register_destructor(char const *name, void *object,
void (*func)(void*))
{
_al_register_destructor(kcm_dtors, name, object, func);
return _al_register_destructor(kcm_dtors, name, object, func);
}


/* _al_kcm_unregister_destructor:
* Unregister an object to be destroyed.
*/
void _al_kcm_unregister_destructor(void *object)
void _al_kcm_unregister_destructor(_AL_LIST_ITEM *dtor_item)
{
_al_unregister_destructor(kcm_dtors, object);
_al_unregister_destructor(kcm_dtors, dtor_item);
}


@@ -178,7 +178,7 @@ ALLEGRO_SAMPLE_INSTANCE *al_create_sample_instance(ALLEGRO_SAMPLE *sample_data)
spl->mutex = NULL;
spl->parent.u.ptr = NULL;

_al_kcm_register_destructor("sample_instance", spl,
spl->dtor_item = _al_kcm_register_destructor("sample_instance", spl,
(void (*)(void *))al_destroy_sample_instance);

return spl;
@@ -200,7 +200,7 @@ void _al_kcm_destroy_sample(ALLEGRO_SAMPLE_INSTANCE *spl, bool unregister)
{
if (spl) {
if (unregister) {
_al_kcm_unregister_destructor(spl);
_al_kcm_unregister_destructor(spl->dtor_item);
}

_al_kcm_detach_from_parent(spl);
@@ -667,7 +667,7 @@ ALLEGRO_MIXER *al_create_mixer(unsigned int freq,

_al_vector_init(&mixer->streams, sizeof(ALLEGRO_SAMPLE_INSTANCE *));

_al_kcm_register_destructor("mixer", mixer, (void (*)(void *)) al_destroy_mixer);
mixer->dtor_item = _al_kcm_register_destructor("mixer", mixer, (void (*)(void *)) al_destroy_mixer);

return mixer;
}
@@ -678,7 +678,7 @@ ALLEGRO_MIXER *al_create_mixer(unsigned int freq,
void al_destroy_mixer(ALLEGRO_MIXER *mixer)
{
if (mixer) {
_al_kcm_unregister_destructor(mixer);
_al_kcm_unregister_destructor(mixer->dtor_item);
_al_kcm_destroy_sample(&mixer->ss, false);
}
}
@@ -153,7 +153,7 @@ ALLEGRO_SAMPLE *al_create_sample(void *buf, unsigned int samples,
spl->buffer.ptr = buf;
spl->free_buf = free_buf;

_al_kcm_register_destructor("sample", spl, (void (*)(void *)) al_destroy_sample);
spl->dtor_item = _al_kcm_register_destructor("sample", spl, (void (*)(void *)) al_destroy_sample);

return spl;
}
@@ -184,7 +184,7 @@ void al_destroy_sample(ALLEGRO_SAMPLE *spl)
if (spl) {
_al_kcm_foreach_destructor(stop_sample_instances_helper,
al_get_sample_data(spl));
_al_kcm_unregister_destructor(spl);
_al_kcm_unregister_destructor(spl->dtor_item);

if (spl->free_buf && spl->buffer.ptr) {
al_free(spl->buffer.ptr);
@@ -135,7 +135,7 @@ ALLEGRO_AUDIO_STREAM *al_create_audio_stream(size_t fragment_count,
al_init_user_event_source(&stream->spl.es);

/* This can lead to deadlocks on shutdown, hence we don't do it. */
/* _al_kcm_register_destructor(stream, (void (*)(void *)) al_destroy_audio_stream); */
/* stream->dtor_item = _al_kcm_register_destructor(stream, (void (*)(void *)) al_destroy_audio_stream); */

return stream;
}
@@ -150,7 +150,7 @@ void al_destroy_audio_stream(ALLEGRO_AUDIO_STREAM *stream)
stream->unload_feeder(stream);
}
/* See commented out call to _al_kcm_register_destructor. */
/* _al_kcm_unregister_destructor(stream); */
/* _al_kcm_unregister_destructor(stream->dtor_item); */
_al_kcm_detach_from_parent(&stream->spl);

al_destroy_user_event_source(&stream->spl.es);
@@ -94,7 +94,7 @@ ALLEGRO_VOICE *al_create_voice(unsigned int freq,
return NULL;
}

_al_kcm_register_destructor("voice", voice,
voice->dtor_item = _al_kcm_register_destructor("voice", voice,
(void (*)(void *)) al_destroy_voice);

return voice;
@@ -106,7 +106,7 @@ ALLEGRO_VOICE *al_create_voice(unsigned int freq,
void al_destroy_voice(ALLEGRO_VOICE *voice)
{
if (voice) {
_al_kcm_unregister_destructor(voice);
_al_kcm_unregister_destructor(voice->dtor_item);

al_detach_voice(voice);
ASSERT(al_get_voice_playing(voice) == false);
@@ -2,6 +2,7 @@
#define __al_included_allegro5_allegro_font_h

#include "allegro5/allegro.h"
#include "allegro5/internal/aintern_list.h"

#if (defined ALLEGRO_MINGW32) || (defined ALLEGRO_MSVC) || (defined ALLEGRO_BCC32)
#ifndef ALLEGRO_STATICLINK
@@ -54,6 +55,7 @@ struct ALLEGRO_FONT
int height;
ALLEGRO_FONT *fallback;
ALLEGRO_FONT_VTABLE *vtable;
_AL_LIST_ITEM *dtor_item;
};

/* text- and font-related stuff */
@@ -284,7 +284,7 @@ ALLEGRO_FONT *al_grab_font_from_bitmap(ALLEGRO_BITMAP *bmp,
if (unmasked)
al_destroy_bitmap(unmasked);

_al_register_destructor(_al_dtor_list, "font", f,
f->dtor_item = _al_register_destructor(_al_dtor_list, "font", f,
(void (*)(void *))al_destroy_font);

return f;
@@ -359,7 +359,7 @@ void al_destroy_font(ALLEGRO_FONT *f)
if (!f)
return;

_al_unregister_destructor(_al_dtor_list, f);
_al_unregister_destructor(_al_dtor_list, f->dtor_item);

f->vtable->destroy(f);
}
@@ -1,6 +1,7 @@
#ifndef __al_included_allegro_aintern_native_dialog_h
#define __al_included_allegro_aintern_native_dialog_h

#include "allegro5/internal/aintern_list.h"
#include "allegro5/internal/aintern_vector.h"
#include "allegro5/internal/aintern_native_dialog_cfg.h"

@@ -41,6 +42,8 @@ struct ALLEGRO_NATIVE_DIALOG
bool is_active;
void *window;
void *async_queue;

_AL_LIST_ITEM *dtor_item;
};

extern bool _al_init_native_dialog_addon(void);
@@ -56,7 +56,7 @@ ALLEGRO_FILECHOOSER *al_create_native_file_dialog(
fc->fc_patterns = al_ustr_new(patterns);
fc->flags = mode;

_al_register_destructor(_al_dtor_list, "native_dialog", fc,
fc->dtor_item = _al_register_destructor(_al_dtor_list, "native_dialog", fc,
(void (*)(void *))al_destroy_native_file_dialog);

return (ALLEGRO_FILECHOOSER *)fc;
@@ -100,7 +100,7 @@ void al_destroy_native_file_dialog(ALLEGRO_FILECHOOSER *dialog)
if (!fd)
return;

_al_unregister_destructor(_al_dtor_list, fd);
_al_unregister_destructor(_al_dtor_list, fd->dtor_item);

al_ustr_free(fd->title);
al_destroy_path(fd->fc_initial_path);
@@ -80,7 +80,7 @@ ALLEGRO_TEXTLOG *al_open_native_text_log(char const *title, int flags)
return NULL;
}

_al_register_destructor(_al_dtor_list, "textlog", textlog,
textlog->dtor_item = _al_register_destructor(_al_dtor_list, "textlog", textlog,
(void (*)(void *))al_close_native_text_log);

return (ALLEGRO_TEXTLOG *)textlog;
@@ -111,7 +111,7 @@ void al_close_native_text_log(ALLEGRO_TEXTLOG *textlog)
al_lock_mutex(dialog->tl_text_mutex);
}

_al_unregister_destructor(_al_dtor_list, dialog);
_al_unregister_destructor(_al_dtor_list, dialog->dtor_item);
}

al_ustr_free(dialog->title);
@@ -918,7 +918,7 @@ ALLEGRO_FONT *al_load_ttf_font_stretch_f(ALLEGRO_FILE *file,
f->vtable = &vt;
f->data = data;

_al_register_destructor(_al_dtor_list, "ttf_font", f,
f->dtor_item = _al_register_destructor(_al_dtor_list, "ttf_font", f,
(void (*)(void *))al_destroy_font);

return f;
@@ -6,6 +6,7 @@
#include "allegro5/display.h"
#include "allegro5/render_state.h"
#include "allegro5/transformations.h"
#include "allegro5/internal/aintern_list.h"

#ifdef __cplusplus
extern "C" {
@@ -97,6 +98,8 @@ struct ALLEGRO_BITMAP
/* Extra data for display bitmaps, like texture id and so on. */
void *extra;

_AL_LIST_ITEM *dtor_item;

/* set_target_bitmap and lock_bitmap mark bitmaps as dirty for preservation */
bool dirty;
};
@@ -1,6 +1,8 @@
#ifndef __al_included_allegro5_aintern_dtor_h
#define __al_included_allegro5_aintern_dtor_h

#include "allegro5/internal/aintern_list.h"

#ifdef __cplusplus
extern "C" {
#endif
@@ -14,9 +16,9 @@ AL_FUNC(void, _al_push_destructor_owner, (void));
AL_FUNC(void, _al_pop_destructor_owner, (void));
AL_FUNC(void, _al_run_destructors, (_AL_DTOR_LIST *dtors));
AL_FUNC(void, _al_shutdown_destructors, (_AL_DTOR_LIST *dtors));
AL_FUNC(void, _al_register_destructor, (_AL_DTOR_LIST *dtors, char const *name,
AL_FUNC(_AL_LIST_ITEM*, _al_register_destructor, (_AL_DTOR_LIST *dtors, char const *name,
void *object, void (*func)(void*)));
AL_FUNC(void, _al_unregister_destructor, (_AL_DTOR_LIST *dtors, void *object));
AL_FUNC(void, _al_unregister_destructor, (_AL_DTOR_LIST *dtors, _AL_LIST_ITEM* dtor_item));
AL_FUNC(void, _al_foreach_destructor, (_AL_DTOR_LIST *dtors,
void (*callback)(void *object, void (*func)(void *), void *udata),
void *userdata));
@@ -1,6 +1,7 @@
#ifndef __al_included_allegro5_internal_aintern_shader_h
#define __al_included_allegro5_internal_aintern_shader_h

#include "allegro5/internal/aintern_list.h"
#include "allegro5/internal/aintern_vector.h"

#ifdef __cplusplus
@@ -42,6 +43,7 @@ struct ALLEGRO_SHADER
ALLEGRO_SHADER_PLATFORM platform;
ALLEGRO_SHADER_INTERFACE *vt;
_AL_VECTOR bitmaps; /* of ALLEGRO_BITMAP pointers */
_AL_LIST_ITEM *dtor_item;
};

/* In most cases you should use _al_set_bitmap_shader_field. */
@@ -188,7 +188,7 @@ ALLEGRO_BITMAP *al_create_bitmap(int w, int h)
al_get_new_bitmap_format(), al_get_new_bitmap_flags(),
al_get_new_bitmap_depth(), al_get_new_bitmap_samples());
if (bitmap) {
_al_register_destructor(_al_dtor_list, "bitmap", bitmap,
bitmap->dtor_item = _al_register_destructor(_al_dtor_list, "bitmap", bitmap,
(void (*)(void *))al_destroy_bitmap);
}

@@ -217,7 +217,7 @@ void al_destroy_bitmap(ALLEGRO_BITMAP *bitmap)

_al_set_bitmap_shader_field(bitmap, NULL);

_al_unregister_destructor(_al_dtor_list, bitmap);
_al_unregister_destructor(_al_dtor_list, bitmap->dtor_item);

if (!al_is_sub_bitmap(bitmap)) {
ALLEGRO_DISPLAY* disp = _al_get_bitmap_display(bitmap);
@@ -468,7 +468,7 @@ ALLEGRO_BITMAP *al_create_sub_bitmap(ALLEGRO_BITMAP *parent,
bitmap->yofs = y;
bitmap->memory = NULL;

_al_register_destructor(_al_dtor_list, "sub_bitmap", bitmap,
bitmap->dtor_item = _al_register_destructor(_al_dtor_list, "sub_bitmap", bitmap,
(void (*)(void *))al_destroy_bitmap);

return bitmap;

0 comments on commit bd16653

Please sign in to comment.
You can’t perform that action at this time.