Re: [AD] Patch to fix race condition

[ Thread Index | Date Index | More lists.liballeg.org/allegro-developers Archives ]


On 2010-02-28, Trent Gamblin <trent@xxxxxxxxxx> wrote:
> This is a rather lazy fix for this particular problem...
> Right now loading the system driver loads allegro5.cfg
> which tries which tries to open the file which loads
> the file interface which initializes pthreads which prints
> out a string in debug mode which tries to read a value
> from the partially loaded system configuration. The easy
> fix is I just commented out that ALLEGRO_DEBUG call,
> but perhaps the whole idea is flawed... anyway here's
> a patch.

How about adding an explicit way to load configuration files without
invoking TLS, i.e. add these

    ALLEGRO_FILE *al_fopen_stdio(const char *path, const char *mode)
    ALLEGRO_CONFIG *al_load_config_file_stdio(const char *filename)

Also maybe
al_set_standard_file_interface -> al_set_stdio_file_interface

The following patch is untested.

Peter


diff --git a/docs/src/refman/config.txt b/docs/src/refman/config.txt
index c81e558..e548ebf 100644
--- a/docs/src/refman/config.txt
+++ b/docs/src/refman/config.txt
@@ -23,15 +23,26 @@ See also: [al_create_config], [al_load_config_file]
 
 ## API: al_load_config_file
 
-Read a configuration file from disk.
+Read a configuration file.
 Returns NULL on error.  The configuration structure should be destroyed
 with [al_destroy_config].
 
-See also: [al_save_config_file]
+This function calls [al_fopen] so is affected by the current file interface.
+
+See also: [al_save_config_file], [al_load_config_file_stdio],
+[al_set_new_file_interface]
+
+## API: al_load_config_file_stdio
+
+Like [al_load_config_file] but always tries to open a file on disk rather than
+going through the file interface.  That is, it calls [al_fopen_stdio] instead
+of [al_fopen].  Usually you would want to use [al_load_config_file].
+
+See also: [al_load_config_file], [al_set_new_file_interface]
 
 ## API: al_save_config_file
 
-Write out a configuration file to disk.
+Write out a configuration file.
 Returns true on success, false on error.
 
 See also: [al_load_config_file]
diff --git a/docs/src/refman/file.txt b/docs/src/refman/file.txt
index c2ecc31..3072b2b 100644
--- a/docs/src/refman/file.txt
+++ b/docs/src/refman/file.txt
@@ -55,7 +55,7 @@ Newline translations can be useful for text files but is disastrous for binary
 files.  To avoid this behaviour you need to open file streams in binary mode
 by using a mode argument containing a "b", e.g. "rb", "wb".
 
-See also: [al_set_new_file_interface].
+See also: [al_set_new_file_interface], [al_fopen_stdio].
 
 ## API: al_fclose
 
@@ -286,6 +286,15 @@ native end-of-line sequences, e.g. CR/LF instead of LF.
 
 ## Standard I/O specific routines
 
+## API: al_fopen_stdio
+
+Like [al_fopen] but always tries to open a file on disk rather than going
+through the file interface.  That is, it it unaffected by
+[al_set_new_file_interface].
+Usually you would want to use [al_fopen] instead.
+
+See also: [al_set_new_file_interface], [al_fopen]
+
 ### API: al_fopen_fd
 
 Create an [ALLEGRO_FILE] object that operates on an open file descriptor using
diff --git a/include/allegro5/config.h b/include/allegro5/config.h
index 6d39511..03a2f00 100644
--- a/include/allegro5/config.h
+++ b/include/allegro5/config.h
@@ -15,6 +15,7 @@ AL_FUNC(void, al_set_config_value, (ALLEGRO_CONFIG *config, const char *section,
 AL_FUNC(void, al_add_config_comment, (ALLEGRO_CONFIG *config, const char *section, const char *comment));
 AL_FUNC(const char*, al_get_config_value, (const ALLEGRO_CONFIG *config, const char *section, const char *key));
 AL_FUNC(ALLEGRO_CONFIG*, al_load_config_file, (const char *filename));
+AL_FUNC(ALLEGRO_CONFIG*, al_load_config_file_stdio, (const char *filename));
 AL_FUNC(bool, al_save_config_file, (const ALLEGRO_CONFIG *config, const char *filename));
 AL_FUNC(void, al_merge_config_into, (ALLEGRO_CONFIG *master, const ALLEGRO_CONFIG *add));
 AL_FUNC(ALLEGRO_CONFIG *, al_merge_config, (const ALLEGRO_CONFIG *cfg1, const ALLEGRO_CONFIG *cfg2));
diff --git a/include/allegro5/file.h b/include/allegro5/file.h
index d80d6de..d54fe89 100644
--- a/include/allegro5/file.h
+++ b/include/allegro5/file.h
@@ -76,6 +76,7 @@ AL_FUNC(ALLEGRO_USTR *, al_fget_ustr, (ALLEGRO_FILE *f));
 AL_FUNC(int, al_fputs, (ALLEGRO_FILE *f, const char *p));
 
 /* Specific to stdio backend. */
+AL_FUNC(ALLEGRO_FILE*, al_fopen_stdio, (const char *path, const char *mode));
 AL_FUNC(ALLEGRO_FILE*, al_fopen_fd, (int fd, const char *mode));
 AL_FUNC(ALLEGRO_FILE*, al_make_temp_file, (const char *tmpl,
       ALLEGRO_PATH **ret_path));
diff --git a/src/config.c b/src/config.c
index 79107f9..2b531e6 100644
--- a/src/config.c
+++ b/src/config.c
@@ -329,9 +329,7 @@ static bool readline(ALLEGRO_FILE *file, ALLEGRO_USTR *line)
 }
 
 
-/* Function: al_load_config_file
- */
-ALLEGRO_CONFIG *al_load_config_file(const char *filename)
+static ALLEGRO_CONFIG *load_config_file(ALLEGRO_FILE *file)
 {
    ALLEGRO_CONFIG *config;
    ALLEGRO_CONFIG_SECTION *current_section = NULL;
@@ -339,16 +337,9 @@ ALLEGRO_CONFIG *al_load_config_file(const char *filename)
    ALLEGRO_USTR *section;
    ALLEGRO_USTR *key;
    ALLEGRO_USTR *value;
-   ALLEGRO_FILE *file;
 
-   file = al_fopen(filename, "r");
-   if (!file) {
-      return NULL;
-   }
-   
    config = al_create_config();
    if (!config) {
-      al_fclose(file);
       return NULL;
    }
 
@@ -393,8 +384,42 @@ ALLEGRO_CONFIG *al_load_config_file(const char *filename)
    al_ustr_free(key);
    al_ustr_free(value);
 
+   return config;
+}
+
+
+/* Function: al_load_config_file
+ */
+ALLEGRO_CONFIG *al_load_config_file(const char *filename)
+{
+   ALLEGRO_CONFIG *config;
+   ALLEGRO_FILE *file;
+
+   file = al_fopen(filename, "r");
+   if (!file) {
+      return NULL;
+   }
+
+   config = load_config_file(file);
    al_fclose(file);
+   return config;
+}
+
+
+/* Function: al_load_config_file_stdio
+ */
+ALLEGRO_CONFIG *al_load_config_file_stdio(const char *filename)
+{
+   ALLEGRO_CONFIG *config;
+   ALLEGRO_FILE *file;
 
+   file = al_fopen_stdio(filename, "r");
+   if (!file) {
+      return NULL;
+   }
+
+   config = load_config_file(file);
+   al_fclose(file);
    return config;
 }
 
diff --git a/src/file_stdio.c b/src/file_stdio.c
index 2dd2435..0f727fd 100644
--- a/src/file_stdio.c
+++ b/src/file_stdio.c
@@ -87,7 +87,9 @@ ALLEGRO_FILE *al_fopen_fd(int fd, const char *mode)
 }
 
 
-static ALLEGRO_FILE *file_stdio_fopen(const char *path, const char *mode)
+/* Function: al_fopen_stdio
+ */
+ALLEGRO_FILE *al_fopen_stdio(const char *path, const char *mode)
 {
    FILE *fp;
    ALLEGRO_FILE_STDIO *f;
@@ -256,7 +258,7 @@ Error:
 
 const struct ALLEGRO_FILE_INTERFACE _al_file_interface_stdio =
 {
-   file_stdio_fopen,
+   al_fopen_stdio,
    file_stdio_fclose,
    file_stdio_fread,
    file_stdio_fwrite,
diff --git a/src/system_new.c b/src/system_new.c
index 70e961d..1880b62 100644
--- a/src/system_new.c
+++ b/src/system_new.c
@@ -107,17 +107,20 @@ static void read_allegro_cfg(void)
    /* We cannot use any logging in this function as it would cause the
     * logging system to be initialised before all the relevant config files
     * have been read in.
+    *
+    * We use al_load_config_file_stdio instad of al_load_config_file to avoid
+    * using any TLS while TLS might not be fully set up.
     */
 
 #if defined ALLEGRO_UNIX && !defined ALLEGRO_GP2XWIZ && !defined ALLEGRO_IPHONE
    ALLEGRO_CONFIG *temp;
    ALLEGRO_PATH *path;
 
-   active_sysdrv->config = al_load_config_file("/etc/allegro5rc");
+   active_sysdrv->config = al_load_config_file_stdio("/etc/allegro5rc");
 
    path = _al_unix_get_path(ALLEGRO_USER_HOME_PATH);
    al_set_path_filename(path, "allegro5rc");
-   temp = al_load_config_file(al_path_cstr(path, '/'));
+   temp = al_load_config_file_stdio(al_path_cstr(path, '/'));
    if (temp) {
       if (active_sysdrv->config) {
          al_merge_config_into(active_sysdrv->config, temp);
@@ -129,7 +132,7 @@ static void read_allegro_cfg(void)
    }
    al_free_path(path);
 
-   temp = al_load_config_file("allegro5.cfg");
+   temp = al_load_config_file_stdio("allegro5.cfg");
    if (temp) {
       if (active_sysdrv->config) {
          al_merge_config_into(active_sysdrv->config, temp);
@@ -140,7 +143,7 @@ static void read_allegro_cfg(void)
       }
    }
 #else
-   active_sysdrv->config = al_load_config_file("allegro5.cfg");
+   active_sysdrv->config = al_load_config_file_stdio("allegro5.cfg");
 #endif
 }
 
diff --git a/src/tls.c b/src/tls.c
index 96b3971..055ddf0 100644
--- a/src/tls.c
+++ b/src/tls.c
@@ -754,21 +754,20 @@ ALLEGRO_MEMORY_BLENDER _al_get_memory_blender()
 
 
 /* Function: al_get_new_file_interface
- * FIXME: added a work-around for the situation where TLS has not yet been
- * initialised when this function is called. This may happen if Allegro
- * tries to load a configuration file before the system has been
- * initialised. Should probably rethink the logic here...
  */
 const ALLEGRO_FILE_INTERFACE *al_get_new_file_interface(void)
 {
    thread_local_state *tls;
 
-   if ((tls = tls_get()) == NULL)
+   if ((tls = tls_get()) == NULL) {
       return &_al_file_interface_stdio;
+   }
 
    /* FIXME: this situation should never arise because tls_ has the stdio
     * interface set as a default, but it arises on OS X if
     * pthread_getspecific() is called before pthreads_thread_init()...
+    *
+    * Does this still happen? --pw
     */
    if (tls->new_file_interface)
       return tls->new_file_interface;





Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/