Skip to content

Commit 6b5a1fb

Browse files
DSheirerDennis Sheirer
andauthored
#1802 Traffic channels stuck in TEARDOWN. Resolves: (#1829)
1. Tuner channel processing runnables were being interruptibly shutdown, preventing the channel from clearing any owned locks (ie DMRTrafficChannelManager) causing thread deadlock and eventually causing out of memory situation or tying up all threads in the thread pool to the point that the application stopped processing any data. 2. DMR Traffic Channel Manager was erroneously processing non-owned traffic channel events. Co-authored-by: Dennis Sheirer <[email protected]>
1 parent 0491b08 commit 6b5a1fb

21 files changed

+122
-265
lines changed

src/main/java/io/github/dsheirer/channel/state/AbstractDecoderState.java

Lines changed: 59 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,20 @@
11
/*
2+
* *****************************************************************************
3+
* Copyright (C) 2014-2024 Dennis Sheirer
24
*
3-
* * ******************************************************************************
4-
* * Copyright (C) 2014-2019 Dennis Sheirer
5-
* *
6-
* * This program is free software: you can redistribute it and/or modify
7-
* * it under the terms of the GNU General Public License as published by
8-
* * the Free Software Foundation, either version 3 of the License, or
9-
* * (at your option) any later version.
10-
* *
11-
* * This program is distributed in the hope that it will be useful,
12-
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
13-
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14-
* * GNU General Public License for more details.
15-
* *
16-
* * You should have received a copy of the GNU General Public License
17-
* * along with this program. If not, see <http://www.gnu.org/licenses/>
18-
* * *****************************************************************************
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
199
*
10+
* This program 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
13+
* GNU General Public License for more details.
2014
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>
17+
* ****************************************************************************
2118
*/
2219

2320
package io.github.dsheirer.channel.state;
@@ -47,9 +44,37 @@ public abstract class AbstractDecoderState extends Module implements ActivitySum
4744
protected Broadcaster<IDecodeEvent> mDecodeEventBroadcaster = new Broadcaster<>();
4845
protected Listener<DecoderStateEvent> mDecoderStateListener;
4946
private DecoderStateEventListener mDecoderStateEventListener = new DecoderStateEventListener();
47+
private boolean mRunning;
5048

5149
public abstract DecoderType getDecoderType();
5250

51+
/**
52+
* Implements module start and sets the mRunning flag to true so that messages can be processed.
53+
*/
54+
@Override
55+
public void start()
56+
{
57+
mRunning = true;
58+
}
59+
60+
/**
61+
* Implements the module stop and sets the mRunning flag to false to stop message processing
62+
*/
63+
@Override
64+
public void stop()
65+
{
66+
mRunning = false;
67+
}
68+
69+
/**
70+
* Indicates if this module is running and can process/pass messages down to sub-class implementations.
71+
* @return true if running
72+
*/
73+
public boolean isRunning()
74+
{
75+
return mRunning;
76+
}
77+
5378
/**
5479
* Provides subclass reference to the decode event broadcaster
5580
*/
@@ -145,4 +170,22 @@ public void receive(DecoderStateEvent event)
145170
}
146171
}
147172

173+
/**
174+
* Message listener that only passes messages while we're running. This is important because each of the decoders
175+
* can process blocks of samples and that can result in additional messages being generated even after shutdown
176+
* and so we shut off the processing of decoded messages when we're commanded to stop. The sample processing thread
177+
* cannot be shutdown or forcefully interrupted because downstream decoder and channel states may have acquired
178+
* locks that have to be properly released.
179+
*/
180+
private class MessageListener implements Listener<IMessage>
181+
{
182+
@Override
183+
public void receive(IMessage message)
184+
{
185+
if(isRunning())
186+
{
187+
receive(message);
188+
}
189+
}
190+
}
148191
}

src/main/java/io/github/dsheirer/channel/state/AlwaysUnsquelchedDecoderState.java

Lines changed: 0 additions & 102 deletions
This file was deleted.

src/main/java/io/github/dsheirer/channel/state/DecoderState.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* *****************************************************************************
3-
* Copyright (C) 2014-2022 Dennis Sheirer
3+
* Copyright (C) 2014-2024 Dennis Sheirer
44
*
55
* This program is free software: you can redistribute it and/or modify
66
* it under the terms of the GNU General Public License as published by
@@ -54,6 +54,7 @@ public DecoderState()
5454
@Override
5555
public void start()
5656
{
57+
super.start();
5758
//Broadcast the existing identifiers (as add events) so that they can be received by external listeners
5859
mIdentifierCollection.broadcastIdentifiers();
5960
}

src/main/java/io/github/dsheirer/controller/channel/ChannelProcessingManager.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,8 @@ private void stopProcessing(Channel channel) throws ChannelException
636636
processingChain.removeFrequencyChangeListener(channel);
637637
channel.resetFrequencyCorrection();
638638

639+
//Notify all processing chains that this channel is shutting down so that if this is a traffic channel,
640+
//the owning parent channel's traffic channel manager can cleanup it's accounting.
639641
mChannelEventBroadcaster.broadcast(new ChannelEvent(channel, ChannelEvent.Event.NOTIFICATION_PROCESSING_STOP));
640642
mChannelEventBroadcaster.removeListener(processingChain);
641643

src/main/java/io/github/dsheirer/module/decode/analog/AnalogDecoderState.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* *****************************************************************************
3-
* Copyright (C) 2014-2023 Dennis Sheirer
3+
* Copyright (C) 2014-2024 Dennis Sheirer
44
*
55
* This program is free software: you can redistribute it and/or modify
66
* it under the terms of the GNU General Public License as published by
@@ -145,11 +145,10 @@ private void endCallEvent()
145145
@Override
146146
public void start()
147147
{
148+
super.start();
148149
getIdentifierCollection().update(getChannelNameIdentifier());
149150
}
150151

151-
@Override
152-
public void stop() {}
153152
@Override
154153
public void init() {}
155154
@Override

src/main/java/io/github/dsheirer/module/decode/dcs/DCSDecoderState.java

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* *****************************************************************************
3-
* Copyright (C) 2014-2023 Dennis Sheirer
3+
* Copyright (C) 2014-2024 Dennis Sheirer
44
*
55
* This program is free software: you can redistribute it and/or modify
66
* it under the terms of the GNU General Public License as published by
@@ -115,9 +115,4 @@ public String getActivitySummary()
115115
public void init()
116116
{
117117
}
118-
119-
@Override
120-
public void stop()
121-
{
122-
}
123118
}

src/main/java/io/github/dsheirer/module/decode/dmr/DMRDecoderState.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1472,6 +1472,8 @@ public void receiveDecoderStateEvent(DecoderStateEvent event)
14721472
@Override
14731473
public void start()
14741474
{
1475+
super.start();
1476+
14751477
//Change the default (45-second) traffic channel timeout to 1 second
14761478
if(mChannel.isTrafficChannel())
14771479
{
@@ -1483,9 +1485,4 @@ public void start()
14831485
public void init()
14841486
{
14851487
}
1486-
1487-
@Override
1488-
public void stop()
1489-
{
1490-
}
14911488
}

src/main/java/io/github/dsheirer/module/decode/dmr/DMRTrafficChannelManager.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,9 @@ private void createTrafficChannels()
201201
}
202202

203203
mAvailableTrafficChannels.addAll(trafficChannelList);
204+
205+
//Keep track of the complete list so that we can check channel events to determine if the channel event
206+
//is for a traffic channel owned by this traffic channel manager.
204207
mAllocatedTrafficChannels = Collections.unmodifiableList(trafficChannelList);
205208
}
206209
}
@@ -795,15 +798,19 @@ else if(!decodeEvent2.getDetails().endsWith(CHANNEL_START_REJECTED))
795798
}
796799

797800
/**
798-
* Process traffic channel processing stop or processing start rejected events.
801+
/**
802+
* Process channel events from the ChannelProcessingManager to account for owned child traffic channels.
803+
* Note: this method sees events for ALL channels and not just DMR channels managed by this instance.
804+
*
799805
* @param channelEvent to process
800806
*/
801807
@Override
802808
public synchronized void receive(ChannelEvent channelEvent)
803809
{
804810
Channel channel = channelEvent.getChannel();
805811

806-
if(channel.isTrafficChannel())
812+
//Only process the event if it's one of the traffic channels managed by this instance.
813+
if(mAllocatedTrafficChannels.contains(channel))
807814
{
808815
switch(channelEvent.getEvent())
809816
{

src/main/java/io/github/dsheirer/module/decode/fleetsync2/Fleetsync2DecoderState.java

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* *****************************************************************************
3-
* Copyright (C) 2014-2023 Dennis Sheirer
3+
* Copyright (C) 2014-2024 Dennis Sheirer
44
*
55
* This program is free software: you can redistribute it and/or modify
66
* it under the terms of the GNU General Public License as published by
@@ -53,20 +53,7 @@ public DecoderType getDecoderType()
5353
}
5454

5555
@Override
56-
public void start()
57-
{
58-
}
59-
60-
@Override
61-
public void stop()
62-
{
63-
}
64-
65-
@Override
66-
public void init()
67-
{
68-
69-
}
56+
public void init() {}
7057

7158
@Override
7259
public void receive(IMessage message)

src/main/java/io/github/dsheirer/module/decode/lj1200/LJ1200DecoderState.java

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* *****************************************************************************
3-
* Copyright (C) 2014-2023 Dennis Sheirer
3+
* Copyright (C) 2014-2024 Dennis Sheirer
44
*
55
* This program is free software: you can redistribute it and/or modify
66
* it under the terms of the GNU General Public License as published by
@@ -150,20 +150,5 @@ public void reset()
150150
}
151151

152152
@Override
153-
public void start()
154-
{
155-
156-
}
157-
158-
@Override
159-
public void stop()
160-
{
161-
162-
}
163-
164-
@Override
165-
public void init()
166-
{
167-
168-
}
153+
public void init() {}
169154
}

0 commit comments

Comments
 (0)