Search code examples
segmentation-faultarraysthreadpoolvala

Data corruption in Vala with ThreadPool


I'm currently working on a project that requires me to queue network packets to be processed. I have a ThreadPool with a maximum of 25 threads that processes these packets when they are available. However, when passing the packet data (encapsulated in a class) to the thread_proc method associated with the ThreadPool, the data is being corrupted. I declare my ThreadPool variable like so:

pool = new ThreadPool<Packet>((Func<Packet>)thread_proc, 25, false);

This is the thread method that checks the available packets:

void* run()
{
    while (true)
    {
        var packet = packets.poll();

        try
        {
            pool.push(packet);
        }
        catch (ThreadError e)
        {
            error(e.message);
        }
    }

    return null;
}

"packets" is a BlockingQueue (custom blocking queue using a mutex) of the following class:

class Packet : Object
{
    public unowned ClientHandler client;
    public uint8[] data;
    public int index;
    public int size;

    public Packet(ClientHandler client, uint8[] data, int index, int size)
    {
        this.client = client;
        this.data = data;
        this.index = index;
        this.size = size;
    }
}

The above class is what contains the actual packet data (the "data" var). By the time the Packet instance gets around to thread_proc, the variable values are all wrong...

Any help as to why this is happening and a possible solution would be much appreciated. Thank you in advance.

~ Michael K.


Solution

  • I just pushed a commit to valac git which will let Vala automatically manage the data. It would have broken backwards compatibility, so you'll have to use the new constructor (ThreadPool.with_owned_data) and method (add instead of push).

    If you want to avoid a dependency on valac git, you can just do a packet.ref () before pushing it, then packet.unref () at the end of your callback (thread_proc). There is an example at https://bugzilla.gnome.org/attachment.cgi?id=214884.

    Note that casting thread_proc in the ThreadPool constructor could break the new memory management stuff. Frankly, you should really just avoid casting delegates... it's a great way to get in trouble. It's much better to just fix your function (thread_proc in this case) to have the correct signature.