Hello,
Context
We are developing an application with Smack 3.4.1.
In this application we have sevaral XMMPconnections,
that are used by many threads to send packets. (An estimated total 300.000 packets a minute. )
We think that we have encoutered possible racecondition in
org.jivesoftware.smack.PacketWriter
Scenario
A XMPPConncetion creates a PacketWriter.
The PacketWriter:
-> Uses an ArrayBlocklingQueue to manage the packets that need to be written (with a max size of 500).
-> starts a thread "Smack Packet Writer (" + connection.connectionCounterValue + ") ".
This thread use the method
org.jivesoftware.smack.PacketWriter.nextPacket()
to get the next packet.
/** * Returns the next available packet from the queue for writing. * * @return the next packet for writing. */ private Packet nextPacket() { Packet packet = null; // Wait until there's a packet or we're done. while (!done && (packet = queue.poll()) == null) { try{ synchronized (queue) { queue.wait(); } } catch (InterruptedException ie) { // Do nothing } } return packet; }
Other threads can use
org.jivesoftware.smack.PacketWriter.sendPacket(Packet)
(through to sendPacket(packet) method of XMPPConncection) to add packages to the queue.
/** * Sends the specified packet to the server. * * @param packet the packet to send. */ publicvoid sendPacket(Packet packet) { if (!done) { // Invoke interceptors for the new packet that is about to be sent. Interceptors // may modify the content of the packet. connection.firePacketInterceptors(packet); try{ queue.put(packet); } catch (InterruptedException ie) { log.log(Level.SEVERE, "Failed to queue packet to send to server: " + packet.toString(), ie); return; } synchronized (queue) { queue.notifyAll(); } // Process packet writer listeners. Note that we're using the sending // thread so it's expected that listeners are fast. connection.firePacketSendingListeners(packet); } }
Now, i think the following scenario is possible :
-> the queue.poll() method in nextpacket() returns null
-> context switches happen and the queue gets 500 queue.put(packet) in sendPacket(packet) from different threads
-> the 501the queue.put(packet) blocks ( the size of the queue is 500)
-> nextpacket() continues and starts waiting on a notification
-> a notification never happens because all the following queue.put(packet) are blocked...
We have encoutered a waiting smack writer (*) thread while we can verify , with a heap dump, that the queue in this writer thread is full...
Possible solution
In:
org.jivesoftware.smack.PacketWriter.nextPacket()
1. use a timed wait to ait for a notification
or (maybe better)
2. Use ArrayBlockingQueue.take() instead of ArrayBlockingQueue.poll()
I am relativly new to multi threading .
I hope i am on the correct path to pinpoint a possible bug and a solution.
If not, please correct me. ;-)
regards,
m_dh