pthread eller pipewire, kumulativ minnesläcka?

C, C++, Pascal, Assembly, Raspberry, Java, Matlab, Python, BASIC, SQL, PHP, etc.
Användarvisningsbild
Marta
EF Sponsor
Inlägg: 6953
Blev medlem: 30 mars 2005, 01:19:59
Ort: Landskrona
Kontakt:

pthread eller pipewire, kumulativ minnesläcka?

Inlägg av Marta »

I ett tillägg till min editor för min telegrafiträning har jag tidigare använt pulse audio och en blockerande funktion för att sända tecknen, så ingen extra thread behövdes. I versionen portad till Wayland blev det strul. Mellan varje tecken kom ett skarpt skrapande ljud. Därför skrev jag om detta till native pw, vilket fungerar.

Däremot säger valgrind att det förloras minne, 288 bytes för varje textblock som sänds. Det innefattar att skapa en thread med pthread_create. Denna initierar pw, sänder texten och avslutar pw. Därefter pthread_exit som sista rad i threaden. Programmet terminerar inte när textblocket är slut, så pthread kan avsluta utan att bli avbruten.

Vet inte om det är pthread eller pipwire som binder upp minne. valgrind visar inga referenser till pw, endast till pthread. Är där något speciellt som skall göras i samband med att pthread används?

Kod: Markera allt

==5020== 288 bytes in 1 blocks are possibly lost in loss record 5 of 13
==5020==    at 0x48455EF: calloc (vg_replace_malloc.c:1328)
==5020==    by 0x4010AE2: calloc (rtld-malloc.h:44)
==5020==    by 0x4010AE2: allocate_dtv (dl-tls.c:375)
==5020==    by 0x40114DD: _dl_allocate_tls (dl-tls.c:634)
==5020==    by 0x4BDBBFE: allocate_stack (allocatestack.c:423)
==5020==    by 0x4BDBBFE: pthread_create@@GLIBC_2.34 (pthread_create.c:650)
==5020==    by 0x12CF7F: PwStart (in /home/marta/wayland/wl_tideq/tideq)
==5020==    by 0x1256A6: Morse (edpwmorse.c:129)
==5020==    by 0x11A999: DoCommand (edcommand.c:260)
==5020==    by 0x10FA09: keyPressOut (edwlmain.c:1391)
==5020==    by 0x10FB71: keyboard_key_handler (edwlmain.c:815)
==5020==    by 0x4D39F79: ??? (in /usr/lib/x86_64-linux-gnu/libffi.so.8.1.2)
==5020==    by 0x4D3940D: ??? (in /usr/lib/x86_64-linux-gnu/libffi.so.8.1.2)
==5020==    by 0x4D39B0C: ffi_call (in /usr/lib/x86_64-linux-gnu/libffi.so.8.1.2)
agehall
Inlägg: 427
Blev medlem: 12 augusti 2020, 19:27:54

Re: pthread eller pipewire, kumulativ minnesläcka?

Inlägg av agehall »

Startar du en tråd per tecken?

Jag tycker det ser ut som att det är pthread_create() som allokerar minne till något. Det borde släppas när tråden dör.
Användarvisningsbild
Marta
EF Sponsor
Inlägg: 6953
Blev medlem: 30 mars 2005, 01:19:59
Ort: Landskrona
Kontakt:

Re: pthread eller pipewire, kumulativ minnesläcka?

Inlägg av Marta »

Nej, inte en thread per tecken. Thread skapas när sändning startas. När textavsnittet är lut görs en pw_main_loop_quit inifrån pw's callbackför att fylla på med samples. Det får pw_main_loop_run att släppa så pw kan avslutas och seda terminerar dena thread.

År osäker på om pw tas ner på rätt sätt med alla egendomligheter där är när det sätts upp. En del av uppsätningen, den som har med buffers att göra, är svart magi p.g.a. bristfällig dokumentation.

Tyvärr kommer jag inte på någon bättre lösning än pthread för att hålla igång både wayland och pw samtidigt. Det skall visst finnas en inbyggd funktion i pw för att köra mainloop som en egen thread. Det kanske skulle fungera bättre, men hittar inte hur. Finns ju bara skitdokumentation som autogenereras från kommentarer i koden till pw.
agehall
Inlägg: 427
Blev medlem: 12 augusti 2020, 19:27:54

Re: pthread eller pipewire, kumulativ minnesläcka?

Inlägg av agehall »

Avslutar du tråden när ditt program avslutas? Om du returnerar från funktionen du startar tråden med så kommer pthread_exit() anropas automatiskt. I huvudtråden kan du sedan köra pthread_join() för att få returvärdet från tråden och säkerställa att den är avslutad. Då borde alla resurser allokerade av pthread_create() släppas tycker jag.
Användarvisningsbild
Marta
EF Sponsor
Inlägg: 6953
Blev medlem: 30 mars 2005, 01:19:59
Ort: Landskrona
Kontakt:

Re: pthread eller pipewire, kumulativ minnesläcka?

Inlägg av Marta »

Nu blir jag ungefär 100% yr. Threaden startas med phread_create i slutet av en kedja som börjar i en callback från wayland när en tangent trycks ner, denna avslutas sedan och threaden sänder sedan ett textblock. Så var skulle pthread_join() placeras? Känns helt irrelevant i det här sammanhanget.

När pw's callback för att hämta fler ljudsamples når textens slut får den tillbaka -1 som #samples och kör då pw_main_loop_quit(), varvid pw_main_loop_run släpper och threaden avslutas.

Med hela pw-härket utkommenterat läcker det knappt 300 bytes oavsett hur många gånger threaden körs. Med pw inkluderat läcker mycket mer och dessutom kumulativt.

Här är hela härket. Grunden till det kommer från pw's homepage. Heter där example4 eller något åt det hållet.

Kod: Markera allt

#include <pthread.h>

#include <spa/param/audio/format-utils.h>
 
#include <pipewire/pipewire.h>
 
#define DEFAULT_RATE            8000
#define DEFAULT_CHANNELS        1
#define DEFAULT_VOLUME          0.7


typedef struct{
               int nsamples;
               int idx;
               char samples[65536];
               }cwbufT;

typedef void fillRtnT(cwbufT* cwbuf);

pthread_t cwtid;

fillRtnT* fillRtn;
extern volatile bool morseRunning;

static struct pw_main_loop *loop;
static struct pw_stream *stream;
                                              //1300 27 1.5
static const struct spa_pod *params[1];
static uint8_t buffer[16384];
static struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));



// [on_process]
static void on_process(void *userdata){
  struct pw_buffer *b;
  struct spa_buffer *buf;
  int i, c, n_frames, stride;
  char *dst;
  static cwbufT cwbuf;

  static int t=0;

  if ((b = pw_stream_dequeue_buffer(stream)) == NULL) {  //get a pw buffer
    pw_log_warn("out of buffers: %m");
    return;
  };

  buf = b->buffer;                              //get audio buf
  if ((dst = buf->datas[0].data) == NULL)       //buf ok?
    return;                                     //no-do nothing

  n_frames = buf->datas[0].maxsize;             //ge avail size
  //printf("bufsize %d,   ", n_frames);
//  if (b->requested)                           //adj. to requested size, removed
//    n_frames = SPA_MIN(b->requested, n_frames);
  //printf("   requested %d\n", b->requested);

  if (fillRtn && cwbuf.idx>=cwbuf.nsamples)     //buffer empty?
    fillRtn(&cwbuf);                            //yes, get a char as sound samples

  if (cwbuf.nsamples==-1){                      //all sent?
    memset(dst, 0x80, n_frames);                //yes, fill with silence
    //pw_main_loop_quit(loop);
  }else{
    i=cwbuf.nsamples-cwbuf.idx;                 //get remaining #samples
    if (n_frames>i)                             //room for all?
      n_frames=i;                               //no. limit to what there are
    memcpy(dst, &cwbuf.samples[cwbuf.idx], n_frames); //copy morse sound to buf
    cwbuf.idx+=n_frames;                        //move out idx

//    if (fillRtn && cwbuf.idx>=cwbuf.nsamples) //get more sound if all sent
//      fillRtn(&tut);
  };

  buf->datas[0].chunk->offset = 0;              //prepare to..
  buf->datas[0].chunk->stride = 1;
  buf->datas[0].chunk->size = n_frames;
  pw_stream_queue_buffer(stream, b);            //..submit buffer

  if (cwbuf.nsamples==-1)                       //all sent?
    pw_main_loop_quit(loop);                    //yes, stop

};//on_process


static const struct pw_stream_events stream_events = {  //pw stream listener
  PW_VERSION_STREAM_EVENTS,
  .process = on_process,
};
 


static void* cwthread(void* args){
  int argc=0;

  pw_init(&argc, NULL);                         //some magic setup

  loop = pw_main_loop_new(NULL);                //get a main loop
  if (!loop)
    puts("loop tilted");


  stream = pw_stream_new_simple(                //get an audio stream
                    pw_main_loop_get_loop(loop),
                    "audio-src",
                    pw_properties_new(
                      PW_KEY_MEDIA_TYPE, "Audio",
                      PW_KEY_MEDIA_CATEGORY, "Playback",
                      PW_KEY_MEDIA_ROLE, "Music",
                      NULL),
                    &stream_events,
                    NULL);
  if (!stream)
    puts("stream tilted");
                                                //set data format
  params[0] = spa_format_audio_raw_build(
                    &b,
                    SPA_PARAM_EnumFormat,
                    &SPA_AUDIO_INFO_RAW_INIT(
                    //.format = SPA_AUDIO_FORMAT_S16,
                    .format = SPA_AUDIO_FORMAT_U8,
                    .channels = DEFAULT_CHANNELS,
                    .rate = DEFAULT_RATE ));

  pw_stream_connect(stream,                     //attach stream
                    PW_DIRECTION_OUTPUT,
                    PW_ID_ANY,
                    PW_STREAM_FLAG_AUTOCONNECT |
                    PW_STREAM_FLAG_MAP_BUFFERS |
                    PW_STREAM_FLAG_RT_PROCESS,
                    params, 1);

  pw_main_loop_run(loop);                       //do it



  pw_stream_destroy(stream);                    //take down pw
  pw_main_loop_destroy(loop);
  pw_deinit();
  morseRunning=false;
  pthread_exit(NULL);                           //some thread magic
};


void PwStart(){

  //pw_main_loop_run(data.loop);
  pthread_create(&cwtid,NULL,&cwthread, NULL);  //start the cw tx thread

};
sm5tfx
Inlägg: 114
Blev medlem: 20 juli 2011, 14:28:41
Ort: Gnällbältet

Re: pthread eller pipewire, kumulativ minnesläcka?

Inlägg av sm5tfx »

Marta skrev:Threaden startas med phread_create i slutet av en kedja som börjar i en callback från wayland när en tangent trycks ner, denna avslutas sedan och threaden sänder sedan ett textblock. Så var skulle pthread_join() placeras?
man pthread_join skrev: The pthread_join() function waits for the thread specified by thread to terminate. If that thread has already terminated, then pthread_join() returns immediately.
[---]
Failure to join with a thread that is joinable (i.e., one that is not detached), produces a "zombie thread". Avoid doing this, since each zombie thread consumes some system resources, and when enough zombie threads have accumulated, it will no longer be possible to create new threads (or processes).
Om du inte är intresserad av trådens exit-status, kan du anropa pthread_detatch() direkt efter pthread_create():
The pthread_detach() function marks the thread identified by thread as detached. When a detached thread terminates, its resources are automatically released back to the system without the need for another thread to join with the terminated thread.
Användarvisningsbild
Marta
EF Sponsor
Inlägg: 6953
Blev medlem: 30 mars 2005, 01:19:59
Ort: Landskrona
Kontakt:

Re: pthread eller pipewire, kumulativ minnesläcka?

Inlägg av Marta »

Tackar så mycket för hjälpen. Nu terminerar threaden utan att lämna kvar något lost memory. Däremot finns det kvar en "still reachable" som jag antar är pw som åstadkommer.
Skriv svar