src/audio/esd/SDL_esdaudio.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 03 Jun 2009 04:37:27 +0000
changeset 3162 dc1eb82ffdaa
parent 3068 b21348d47cab
child 3581 15eea7a1fa97
permissions -rw-r--r--
Von: Thomas Zimmermann
Betreff: [SDL] [PATCH] Make static variables const
Datum: Tue, 19 May 2009 19:45:37 +0200

Hi,

this is a set of simple changes which make some of SDL's internal static
arrays constant. The purpose is to shrink the number of write-able
static bytes and thus increase the number of memory pages shared between
SDL applications.

The patch set is against trunk@4513. Each of the attached patch files is
specific to a sub-system. The set is completed by a second mail, because
of the list's 40 KiB limit.

The files readelf-r4513.txt and readelf-const-patch.txt where made by
calling 'readelf -S libSDL.so'. They show the difference in ELF sections
without and with the patch. Some numbers measured on my x86-64:

Before

[13] .rodata PROGBITS 00000000000eaaa0 000eaaa0
0000000000008170 0000000000000000 A 0 0 32
[19] .data.rel.ro PROGBITS 00000000003045e0 001045e0
00000000000023d0 0000000000000000 WA 0 0 32
[23] .data PROGBITS 00000000003076e0 001076e0
0000000000004988 0000000000000000 WA 0 0 32

After

[13] .rodata PROGBITS 00000000000eaaa0 000eaaa0
0000000000009a50 0000000000000000 A 0 0 32
[19] .data.rel.ro PROGBITS 0000000000306040 00106040
0000000000002608 0000000000000000 WA 0 0 32
[23] .data PROGBITS 0000000000309360 00109360
0000000000002e88 0000000000000000 WA 0 0 32

The size of the write-able data section decreased considerably. Some
entries became const-after-relocation, while most of its content went
straight into the read-only data section.

Best regards, Thomas
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2009 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 /* Allow access to an ESD network stream mixing buffer */
    25 
    26 #include <sys/types.h>
    27 #include <unistd.h>
    28 #include <signal.h>
    29 #include <errno.h>
    30 #include <esd.h>
    31 
    32 #include "SDL_timer.h"
    33 #include "SDL_audio.h"
    34 #include "../SDL_audiomem.h"
    35 #include "../SDL_audio_c.h"
    36 #include "SDL_esdaudio.h"
    37 
    38 #ifdef SDL_AUDIO_DRIVER_ESD_DYNAMIC
    39 #include "SDL_name.h"
    40 #include "SDL_loadso.h"
    41 #else
    42 #define SDL_NAME(X)	X
    43 #endif
    44 
    45 /* The tag name used by ESD audio */
    46 #define ESD_DRIVER_NAME		"esd"
    47 
    48 #ifdef SDL_AUDIO_DRIVER_ESD_DYNAMIC
    49 
    50 static const char *esd_library = SDL_AUDIO_DRIVER_ESD_DYNAMIC;
    51 static void *esd_handle = NULL;
    52 
    53 static int (*SDL_NAME(esd_open_sound)) (const char *host);
    54 static int (*SDL_NAME(esd_close)) (int esd);
    55 static int (*SDL_NAME(esd_play_stream)) (esd_format_t format, int rate,
    56                                          const char *host, const char *name);
    57 
    58 #define SDL_ESD_SYM(x) { #x, (void **) (char *) &SDL_NAME(x) }
    59 static struct
    60 {
    61     const char *name;
    62     void **func;
    63 } const esd_functions[] = {
    64     SDL_ESD_SYM(esd_open_sound),
    65     SDL_ESD_SYM(esd_close), SDL_ESD_SYM(esd_play_stream),
    66 };
    67 
    68 #undef SDL_ESD_SYM
    69 
    70 static void
    71 UnloadESDLibrary()
    72 {
    73     if (esd_handle != NULL) {
    74         SDL_UnloadObject(esd_handle);
    75         esd_handle = NULL;
    76     }
    77 }
    78 
    79 static int
    80 LoadESDLibrary(void)
    81 {
    82     int i, retval = -1;
    83 
    84     if (esd_handle == NULL) {
    85         esd_handle = SDL_LoadObject(esd_library);
    86         if (esd_handle) {
    87             retval = 0;
    88             for (i = 0; i < SDL_arraysize(esd_functions); ++i) {
    89                 *esd_functions[i].func =
    90                     SDL_LoadFunction(esd_handle, esd_functions[i].name);
    91                 if (!*esd_functions[i].func) {
    92                     retval = -1;
    93                     UnloadESDLibrary();
    94                     break;
    95                 }
    96             }
    97         }
    98     }
    99     return retval;
   100 }
   101 
   102 #else
   103 
   104 static void
   105 UnloadESDLibrary()
   106 {
   107     return;
   108 }
   109 
   110 static int
   111 LoadESDLibrary(void)
   112 {
   113     return 0;
   114 }
   115 
   116 #endif /* SDL_AUDIO_DRIVER_ESD_DYNAMIC */
   117 
   118 
   119 /* This function waits until it is possible to write a full sound buffer */
   120 static void
   121 ESD_WaitDevice(_THIS)
   122 {
   123     Sint32 ticks;
   124 
   125     /* Check to see if the thread-parent process is still alive */
   126     {
   127         static int cnt = 0;
   128         /* Note that this only works with thread implementations 
   129            that use a different process id for each thread.
   130          */
   131         /* Check every 10 loops */
   132         if (this->hidden->parent && (((++cnt) % 10) == 0)) {
   133             if (kill(this->hidden->parent, 0) < 0 && errno == ESRCH) {
   134                 this->enabled = 0;
   135             }
   136         }
   137     }
   138 
   139     /* Use timer for general audio synchronization */
   140     ticks =
   141         ((Sint32) (this->hidden->next_frame - SDL_GetTicks())) - FUDGE_TICKS;
   142     if (ticks > 0) {
   143         SDL_Delay(ticks);
   144     }
   145 }
   146 
   147 static void
   148 ESD_PlayDevice(_THIS)
   149 {
   150     int written = 0;
   151 
   152     /* Write the audio data, checking for EAGAIN on broken audio drivers */
   153     do {
   154         written = write(this->hidden->audio_fd,
   155                         this->hidden->mixbuf, this->hidden->mixlen);
   156         if ((written < 0) && ((errno == 0) || (errno == EAGAIN))) {
   157             SDL_Delay(1);       /* Let a little CPU time go by */
   158         }
   159     } while ((written < 0) &&
   160              ((errno == 0) || (errno == EAGAIN) || (errno == EINTR)));
   161 
   162     /* Set the next write frame */
   163     this->hidden->next_frame += this->hidden->frame_ticks;
   164 
   165     /* If we couldn't write, assume fatal error for now */
   166     if (written < 0) {
   167         this->enabled = 0;
   168     }
   169 }
   170 
   171 static Uint8 *
   172 ESD_GetDeviceBuf(_THIS)
   173 {
   174     return (this->hidden->mixbuf);
   175 }
   176 
   177 static void
   178 ESD_CloseDevice(_THIS)
   179 {
   180     if (this->hidden != NULL) {
   181         if (this->hidden->mixbuf != NULL) {
   182             SDL_FreeAudioMem(this->hidden->mixbuf);
   183             this->hidden->mixbuf = NULL;
   184         }
   185         if (this->hidden->audio_fd >= 0) {
   186             SDL_NAME(esd_close) (this->hidden->audio_fd);
   187             this->hidden->audio_fd = -1;
   188         }
   189 
   190         SDL_free(this->hidden);
   191         this->hidden = NULL;
   192     }
   193 }
   194 
   195 /* Try to get the name of the program */
   196 static char *
   197 get_progname(void)
   198 {
   199     char *progname = NULL;
   200 #ifdef __LINUX__
   201     FILE *fp;
   202     static char temp[BUFSIZ];
   203 
   204     SDL_snprintf(temp, SDL_arraysize(temp), "/proc/%d/cmdline", getpid());
   205     fp = fopen(temp, "r");
   206     if (fp != NULL) {
   207         if (fgets(temp, sizeof(temp) - 1, fp)) {
   208             progname = SDL_strrchr(temp, '/');
   209             if (progname == NULL) {
   210                 progname = temp;
   211             } else {
   212                 progname = progname + 1;
   213             }
   214         }
   215         fclose(fp);
   216     }
   217 #endif
   218     return (progname);
   219 }
   220 
   221 
   222 static int
   223 ESD_OpenDevice(_THIS, const char *devname, int iscapture)
   224 {
   225     esd_format_t format = (ESD_STREAM | ESD_PLAY);
   226     SDL_AudioFormat test_format = 0;
   227     int found = 0;
   228 
   229     /* Initialize all variables that we clean on shutdown */
   230     this->hidden = (struct SDL_PrivateAudioData *)
   231         SDL_malloc((sizeof *this->hidden));
   232     if (this->hidden == NULL) {
   233         SDL_OutOfMemory();
   234         return 0;
   235     }
   236     SDL_memset(this->hidden, 0, (sizeof *this->hidden));
   237     this->hidden->audio_fd = -1;
   238 
   239     /* Convert audio spec to the ESD audio format */
   240     /* Try for a closest match on audio format */
   241     for (test_format = SDL_FirstAudioFormat(this->spec.format);
   242          !found && test_format; test_format = SDL_NextAudioFormat()) {
   243 #ifdef DEBUG_AUDIO
   244         fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
   245 #endif
   246         found = 1;
   247         switch (test_format) {
   248         case AUDIO_U8:
   249             format |= ESD_BITS8;
   250             break;
   251         case AUDIO_S16SYS:
   252             format |= ESD_BITS16;
   253             break;
   254         default:
   255             found = 0;
   256             break;
   257         }
   258     }
   259 
   260     if (!found) {
   261         ESD_CloseDevice(this);
   262         SDL_SetError("Couldn't find any hardware audio formats");
   263         return 0;
   264     }
   265 
   266     if (this->spec.channels == 1) {
   267         format |= ESD_MONO;
   268     } else {
   269         format |= ESD_STEREO;
   270     }
   271 #if 0
   272     this->spec.samples = ESD_BUF_SIZE;  /* Darn, no way to change this yet */
   273 #endif
   274 
   275     /* Open a connection to the ESD audio server */
   276     this->hidden->audio_fd =
   277         SDL_NAME(esd_play_stream) (format, this->spec.freq, NULL,
   278                                    get_progname());
   279 
   280     if (this->hidden->audio_fd < 0) {
   281         ESD_CloseDevice(this);
   282         SDL_SetError("Couldn't open ESD connection");
   283         return 0;
   284     }
   285 
   286     /* Calculate the final parameters for this audio specification */
   287     SDL_CalculateAudioSpec(&this->spec);
   288     this->hidden->frame_ticks =
   289         (float) (this->spec.samples * 1000) / this->spec.freq;
   290     this->hidden->next_frame = SDL_GetTicks() + this->hidden->frame_ticks;
   291 
   292     /* Allocate mixing buffer */
   293     this->hidden->mixlen = this->spec.size;
   294     this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
   295     if (this->hidden->mixbuf == NULL) {
   296         ESD_CloseDevice(this);
   297         SDL_OutOfMemory();
   298         return 0;
   299     }
   300     SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
   301 
   302     /* Get the parent process id (we're the parent of the audio thread) */
   303     this->hidden->parent = getpid();
   304 
   305     /* We're ready to rock and roll. :-) */
   306     return 1;
   307 }
   308 
   309 static void
   310 ESD_Deinitialize(void)
   311 {
   312     UnloadESDLibrary();
   313 }
   314 
   315 static int
   316 ESD_Init(SDL_AudioDriverImpl * impl)
   317 {
   318     if (LoadESDLibrary() < 0) {
   319         return 0;
   320     } else {
   321         int connection = 0;
   322 
   323         /* Don't start ESD if it's not running */
   324         if (SDL_getenv("ESD_NO_SPAWN") == NULL) {
   325             SDL_putenv("ESD_NO_SPAWN=1");
   326         }
   327 
   328         connection = SDL_NAME(esd_open_sound) (NULL);
   329         if (connection < 0) {
   330             UnloadESDLibrary();
   331             SDL_SetError("ESD: esd_open_sound failed (no audio server?)");
   332             return 0;
   333         }
   334         SDL_NAME(esd_close) (connection);
   335     }
   336 
   337     /* Set the function pointers */
   338     impl->OpenDevice = ESD_OpenDevice;
   339     impl->PlayDevice = ESD_PlayDevice;
   340     impl->WaitDevice = ESD_WaitDevice;
   341     impl->GetDeviceBuf = ESD_GetDeviceBuf;
   342     impl->CloseDevice = ESD_CloseDevice;
   343     impl->Deinitialize = ESD_Deinitialize;
   344     impl->OnlyHasDefaultOutputDevice = 1;
   345 
   346     return 2;                   /* return 2 (definitely have a "device"). */
   347 }
   348 
   349 
   350 AudioBootStrap ESD_bootstrap = {
   351     ESD_DRIVER_NAME, "Enlightened Sound Daemon", ESD_Init, 0
   352 };
   353 
   354 /* vi: set ts=4 sw=4 expandtab: */