Probleme bei der Initialisierungsreihenfolge von globalen Objekten
-
Hallo Leutz, wie der Titel schon verlauten lässt habe ich womöglich ein Probleme mit der Initialisierungsreihenfolge von Objekten bzw mit der Boot Prozedur der PS2.
Das Problem ist das der Audio Stream nicht triggert weil ein Semaphore hängt.
Hier ist mal die komplette Audiostream.h#ifndef AUDIOSTREAM_H #define AUDIOSTREAM_H #ifdef __cplusplus #include <cstdlib> #else #include <stdlib.h> #endif #include <stdio.h> #include <kernel.h> #include <tamtypes.h> #include <cstdlib> // für free #include <cstdint> // Für uint8_t, uint32_t #include <cstddef> // Für NULL #include <cstring> // Für memcpy #define STACK_SIZE (32 * 1024) // 1. WICHTIG: Konstante definieren, damit sie überall bekannt ist #define AUDIO_BLOCK_SAMPLES 256 #define AUDIO_SAMPLE_RATE_EXACT 48000.0f #define AUDIO_SAMPLE_RATE (int)(AUDIO_SAMPLE_RATE_EXACT) #define MAX_AUDIO_MEMORY 6144 #define NUM_MASKS (((MAX_AUDIO_MEMORY / AUDIO_BLOCK_SAMPLES / 2) + 31) / 32) // 2. Forward Declarations class AudioStream; class AudioConnection; typedef struct audio_block_struct { uint8_t ref_count; uint16_t memory_pool_index; float data[AUDIO_BLOCK_SAMPLES]; } audio_block_t; class AudioConnection { public: AudioConnection(); AudioConnection(AudioStream &source, AudioStream &destination) : AudioConnection() { connect(source,destination); } AudioConnection(AudioStream &source, unsigned char sourceOutput, AudioStream &destination, unsigned char destinationInput) : AudioConnection() { connect(source,sourceOutput, destination,destinationInput); } friend class AudioStream; ~AudioConnection(); int disconnect(void); int connect(void); int connect(AudioStream &source, AudioStream &destination) { return connect(source,0,destination,0); }; int connect(AudioStream &source, unsigned char sourceOutput, AudioStream &destination, unsigned char destinationInput); protected: AudioStream* src; AudioStream* dst; unsigned char src_index; unsigned char dest_index; AudioConnection *next_dest; bool isConnected; }; class AudioStream { public: AudioStream(unsigned char ninput, audio_block_t **iqueue) : num_inputs(ninput), inputQueue(iqueue) { active = false; destination_list = NULL; for (int i=0; i < num_inputs; i++) { inputQueue[i] = NULL; } // add to a simple list, for update_all // TODO: replace with a proper data flow analysis in update_all if (first_update == NULL) { first_update = this; } else { AudioStream *p; for (p=first_update; p->next_update; p = p->next_update) ; p->next_update = this; } next_update = NULL; numConnections = 0; } static void initialize_memory(audio_block_t *data, unsigned int num); static void AudioNoInterrupts() { update_exceptions++; } static void AudioInterrupts() { if (update_exceptions > 0) update_exceptions--; } protected: bool active; friend class AudioConnection; static audio_block_t * allocate(void); static void release(audio_block_t * block); void transmit(audio_block_t *block, unsigned char index = 0); audio_block_t * receiveReadOnly(unsigned int index = 0); audio_block_t * receiveWritable(unsigned int index = 0); static bool update_setup(void); static void update_stop(void); static void update_all(void) { printf("DEBUG: update_all check! audioSemaID ist: %d (Adresse: %p)\n", audioSemaID, (void*)&audioSemaID); if(audioSemaID == -1 )return; SignalSema(audioSemaID); } uint8_t num_inputs; uint32_t numConnections; friend void software_isr(void* arg); friend u64 tick_cb(s32 id, u64 scheduled, u64 actual, void* arg, void* pc_val); private: static AudioConnection* unused; audio_block_t **inputQueue; static AudioStream *first_update; AudioStream *next_update; AudioConnection *destination_list; virtual void update(void) = 0; static audio_block_t *memory_pool; static uint32_t memory_pool_available_mask[NUM_MASKS]; static uint16_t memory_pool_first_mask; // Statistiken (optional) static uint16_t memory_used; static uint16_t memory_used_max; static volatile s32 audioSemaID; static bool update_scheduled; static u64 s_audio_ticks; static volatile uint32_t update_exceptions; }; #define AudioMemory(num) ({ \ static audio_block_t data[num]; \ AudioStream::initialize_memory(data, num); \ }) #endifAudioOutput:
#ifndef AUDIOOUTPUTSTREAM_H #define AUDIOOUTPUTSTREAM_H #ifdef __cplusplus #include <cstdlib> #else #include <stdlib.h> #endif #include <cstdint> #include "AudioStream.h" #define CHUNK_SIZE 2048 // Bytes pro audsrv_play_audio Aufruf #define RING_BUFFER_BLOCKS 8 class AudioOutputStream : public AudioStream { public: AudioOutputStream(void) : AudioStream(2, inputQueueArray) { begin(); } void begin(void); virtual void update(void); friend class AudioInputStream; protected: static bool update_responsibility; friend int fillbuffer(void *arg); private: static volatile int write_idx; static volatile int read_idx; static volatile int blocks_available; audio_block_t *inputQueueArray[2]; }; #endif // AUDIOOUTPUTSTREAM_H int fillbuffer(void *arg) { /* u32 sec, usec; TimerBusClock2USec(GetTimerSystemTime(), &sec, &usec); u32 now = usec; time_callback = now - last_time_callback; last_time_callback = now; */ if(AudioOutputStream::update_responsibility) { AudioStream::update_all(); AudioStream::update_all(); } // Wir brauchen 2048 Bytes, also genau 2 Audio-Blöcke (2 x 1024 Bytes) if (AudioOutputStream::blocks_available >= 2) { // Zeiger auf den aktuellen Startblock // (Da wir immer um 2 erhöhen, sind die nächsten 2048 Bytes garantiert am Stück im RAM) char *src_ptr = (char*)&ring_buffer[AudioOutputStream::read_idx * AUDIO_BLOCK_SAMPLES * 2]; // Ein einziger Aufruf für die vollen 2048 Bytes int played = audsrv_play_audio(src_ptr, CHUNK_SIZE); // audsrv_play_audio gibt die Anzahl der verarbeiteten Bytes zurück if (played > 0) { // Lese-Index um 2 Blöcke weiterschieben AudioOutputStream::read_idx = (AudioOutputStream::read_idx + 2) % RING_BUFFER_BLOCKS; DI(); AudioOutputStream::blocks_available -= 2; EI(); } } else { audsrv_play_audio(silence, CHUNK_SIZE); } return 0; } void AudioOutputStream::begin() { update_responsibility = update_setup();//this booting the IOP int ret; int err; printf("#Lade audsrv\n"); #ifdef _DTL_T10000 int modul_ret; ret = SifLoadModule("host:irx/libsd.irx", 0, NULL); printf("LIBSD loadmodule %d\n", ret); ret = SifLoadStartModule("host:irx/audsrv.irx", 0, NULL, &modul_ret); printf("AUDSRV SifLoad_ret: %d Modul_ret: %d\n", ret, modul_ret); #else ret = SifLoadModule("rom0:LIBSD", 0, NULL); printf("libsd loadmodule %d\n", ret); ret = SifLoadModule("host:audsrv.irx", 0, NULL); printf("audsrv loadmodule %d\n", ret); #endif // _DTL_T10000 ret = audsrv_init(); if (ret != 0) { printf("failed to initialize audsrv\n"); printf("audsrv returned error string: %s\n", audsrv_get_error_string()); return; } struct audsrv_fmt_t format; format.bits = 16; format.freq = AUDIO_SAMPLE_RATE; format.channels = 2; err = audsrv_set_format(&format); printf("set format returned %d\n", err); printf("audsrv returned error string: %s\n", audsrv_get_error_string()); audsrv_set_volume(MAX_VOLUME); err = audsrv_on_fillbuf(CHUNK_SIZE, fillbuffer, NULL); if (err != AUDSRV_ERR_NOERROR) { printf("audsrv_on_fillbuf failed with err=%d\n", err); } } void AudioOutputStream::update() { /* u32 sec, usec; TimerBusClock2USec(GetTimerSystemTime(), &sec, &usec); u32 now = usec; printf("Intervall update: %d\n",now - last_time_update); last_time_update = now; printf("Intervall callback: %d\n", time_callback); */ printf("AudioOutputStream::update()\n"); // 1. Check auf Buffer Overflow (optional, aber empfohlen) if (blocks_available >= RING_BUFFER_BLOCKS) return;In der main.cpp instanziiere ich globale Objecte.
AudioSynthWaveformSine sine1;
//AudioInputStream audioIn;
AudioOutputStream audioOut;
Audio_fftr FFT;AudioConnection patchCord0(sine1, 0, audioOut, 0);
AudioConnection patchCord1(sine1, 0, audioOut, 1);
AudioConnection patchCord2(sine1, 0, FFT, 0);und in der main Funktion kommt irwann erst
AudioMemory(32);
das widerum feuert void AudioStream::initialize_memory(audio_block_t *data, unsigned int num)#include "AudioStream.h" #include <timer.h> #include <stdio.h> #include "IOP_BOOT.h" audio_block_t * AudioStream::memory_pool; uint32_t AudioStream::memory_pool_available_mask[NUM_MASKS]; uint16_t AudioStream::memory_pool_first_mask; bool AudioStream::update_scheduled = false; uint16_t AudioStream::memory_used = 0; uint16_t AudioStream::memory_used_max = 0; AudioConnection* AudioStream::unused = NULL; AudioStream * AudioStream::first_update = NULL; static u8 threadStack[STACK_SIZE] __attribute__((aligned(16))); volatile s32 AudioStream::audioSemaID = -1; u64 AudioStream::s_audio_ticks = 0; volatile uint32_t AudioStream::update_exceptions = 0; void software_isr(void* arg) { while(1) { // 1. Der Thread wartet IMMER auf den Timer WaitSema(AudioStream::audioSemaID); // 2. Nur wenn keine Sperre vorliegt, wird gerechnet if (AudioStream::update_exceptions == 0) { AudioStream *p; for (p = AudioStream::first_update; p; p = p->next_update) { if (p->active) p->update(); } } EE_SYNC(); } } // Die Signatur entspricht exakt deinem typedef u64 tick_cb(s32 id, u64 scheduled, u64 actual, void* arg, void* pc_val) { // Signal an die Semaphore iSignalSema(AudioStream::audioSemaID); // WICHTIG: Damit es ein Intervall bleibt, geben wir den nächsten // Zeitpunkt basierend auf der GEPLANTEN Zeit zurück. // Das verhindert, dass sich kleine Verzögerungen aufsummieren (Drift). return AudioStream::s_audio_ticks; } void AudioStream::initialize_memory(audio_block_t *data, unsigned int num) { unsigned int i; unsigned int maxnum = MAX_AUDIO_MEMORY / AUDIO_BLOCK_SAMPLES / 2; if (num > maxnum) num = maxnum; // --- START CRITICAL SECTION --- DI(); memory_pool = data; memory_pool_first_mask = 0; for (i=0; i < NUM_MASKS; i++) { memory_pool_available_mask[i] = 0; } for (i=0; i < num; i++) { memory_pool_available_mask[i >> 5] |= (1 << (i & 0x1F)); } for (i=0; i < num; i++) { data[i].memory_pool_index = i; } EI(); // --- END CRITICAL SECTION --- // Ab hier sind Interrupts wieder an. Kernel-Calls sind jetzt sicher! ee_sema_t audioSema; memset(&audioSema, 0, sizeof(audioSema)); audioSema.init_count = 0; audioSema.max_count = 3; audioSema.option = 0; audioSemaID = CreateSema(&audioSema); printf("DEBUG: Frisch erstellt! audioSemaID ist jetzt: %d (Adresse: %p)\n", audioSemaID, (void*)&audioSemaID); fflush(stdout); ee_thread_t threadParam; memset(&threadParam, 0, sizeof(threadParam)); threadParam.func = (void*)software_isr; threadParam.stack = threadStack; threadParam.stack_size = STACK_SIZE; threadParam.gp_reg = &_gp; // Global Pointer der EE threadParam.initial_priority = 10; // Hohe Priorität als Main 16 s32 threadID = CreateThread(&threadParam); StartThread(threadID, NULL); printf("::initialize_memory %d\n", update_scheduled); if (update_scheduled == false) { update_setup(); float usec = 1e6 * AUDIO_BLOCK_SAMPLES / AUDIO_SAMPLE_RATE_EXACT; s_audio_ticks = USec2TimerBusClock(usec); s32 id = AllocTimerCounter(); SetTimerHandler(id, s_audio_ticks, tick_cb, &s_audio_ticks); StartTimerCounter(id); } }Die Sache ist nun das zuerst die globalen Objekte erstellt werden, das widerum feuert
void AudioOutputStream::begin()
{
update_responsibility = update_setup();//this booting the IOPdamit hällt AudioOutputStream die update_responsibility
fillbuffer feuert ab jetzt AudioStream::update_all();und hier geht es nicht weiter '
static void update_all(void) { //printf("DEBUG: update_all check! audioSemaID ist: %d (Adresse: %p)\n", audioSemaID, (void*)&audioSemaID); if(audioSemaID == -1 )return; SignalSema(audioSemaID); }if(audioSemaID == -1 ) wird nie true bzw false im dem Fall.
initialize_memory wird aufgerufen wenn auch etwas später
weil ich sehe ja diese Ausgabe:
ee_sema_t audioSema;
memset(&audioSema, 0, sizeof(audioSema));
audioSema.init_count = 0;
audioSema.max_count = 3;
audioSema.option = 0;
audioSemaID = CreateSema(&audioSema);
printf("DEBUG: Frisch erstellt! audioSemaID ist jetzt: %d (Adresse: %p)\n", audioSemaID, (void*)&audioSemaID);
fflush(stdout);Die einzige logische Idee, die ich habe ist, es gibt zwei instanzen von audioSemaID
Leider kann ich die Speicheradressen nicht ausgeben
soballt printf in static void update_all(void) feuert wird das print in
initialize_memory verschluckt.Das Passiert weil die Ausgaben über den IOP laufen und wenn man da in eienr Schleife zu oft Ausgaben macht, geht das ein oder ander unter.
Vorallem wenn man mit zwei Threads auf dem EE ausgaben machnen will. Das ist ein Nerviges Problem bei der Playstation 2.Ich habe noch einen älteren Code wo ich noch keine Bildausgabe habe, da funktioert das audio. Das erklärt aber nicht weshalb audioSemaID nie > -1 wird.
-
Ich habe ein paar formelle Anmerkungen:
- Der Code ist weiten teils nicht richtig eingerückt bzw. formatiert.
@D_Key sagte in Probleme bei der Initialisierungsreihenfolge von globalen Objekten:
Objecte
- Entweder Englisch (Objects) oder Deutsch (Objekte), aber nicht beides mixen.
@D_Key sagte in Probleme bei der Initialisierungsreihenfolge von globalen Objekten:
PS2
- Damit kenne ich mich leider nicht aus, aber hast du mal die KI gefragt? Prädestiniert dafür...
Nur überflogen: Vermutlich gibt es einen Mutex-Lock (RAII) irgendwo.
-
Jo, Race Conditions ... https://share.google/aimode/8Ri2k2s1jHnqyTZLI
-
Ein Rassenkonflikt

-
Die Formulierung ist mir auch aufgestoßen
er hat aber wohl einfach "Race Conditions" 1:1 übersetzt.. Hoffe, der Lösungsvorschlag ist dagegen richtig.. 
-
Es gibt noch einen Klopper:
https://www.reddit.com/r/cursedchemistry/comments/1vhgo1m/a_tool_used_to_rephrase_plagiarised_text_changed/