Skip to content

Commit 2601a2e

Browse files
committed
Fix bugs when canceling pending resource requests.
1 parent 6663095 commit 2601a2e

File tree

7 files changed

+84
-33
lines changed

7 files changed

+84
-33
lines changed

SimSharp/Core/Resources/Events/PreemptiveRequest.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ namespace SimSharp {
2222
public sealed class PreemptiveRequest : Request, IComparable<PreemptiveRequest>, IComparable {
2323
public double Priority { get; private set; }
2424
public bool Preempt { get; private set; }
25+
public bool IsPreempted { get; internal set; }
2526

2627
public PreemptiveRequest(Simulation environment, Action<Event> callback, Action<Event> disposeCallback, double priority = 1, bool preempt = false)
2728
: base(environment, callback, disposeCallback) {

SimSharp/Core/Resources/PreemptiveResource.cs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ protected virtual void DoRequest(PreemptiveRequest request) {
117117
// MaxItems are the least important according to priorty, time, and preemption flag
118118
var preempt = Users.MaxItems(x => x).Last();
119119
if (preempt.CompareTo(request) > 0) {
120+
preempt.IsPreempted = true;
120121
Users.Remove(preempt);
121122
preempt.Owner?.Interrupt(new Preempted(request.Owner, preempt.Time));
122123
}
@@ -129,9 +130,8 @@ protected virtual void DoRequest(PreemptiveRequest request) {
129130

130131
protected virtual void DoRelease(Release release) {
131132
var req = (PreemptiveRequest)release.Request;
132-
if (!Users.Remove(req)) {
133-
RequestQueue.TryRemove(req);
134-
}
133+
if (!Users.Remove(req) && !req.IsPreempted)
134+
throw new InvalidOperationException("Released request does not have a user.");
135135
release.Succeed();
136136
}
137137

@@ -150,13 +150,20 @@ protected virtual void TriggerRequest(Event @event = null) {
150150
protected virtual void TriggerRelease(Event @event = null) {
151151
while (ReleaseQueue.Count > 0) {
152152
var release = ReleaseQueue.Peek();
153-
DoRelease(release);
154-
if (release.IsTriggered) {
153+
if (release.Request.IsAlive) {
154+
if (!RequestQueue.TryRemove((PreemptiveRequest)release.Request))
155+
throw new InvalidOperationException("Failed to cancel a request.");
156+
release.Succeed();
155157
ReleaseQueue.Dequeue();
156-
TriggerWhenAny();
157-
TriggerWhenFull();
158-
TriggerWhenChange();
159-
} else break;
158+
} else {
159+
DoRelease(release);
160+
if (release.IsTriggered) {
161+
ReleaseQueue.Dequeue();
162+
TriggerWhenAny();
163+
TriggerWhenFull();
164+
TriggerWhenChange();
165+
} else break;
166+
}
160167
}
161168
}
162169

SimSharp/Core/Resources/PriorityResource.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,8 @@ protected virtual void DoRequest(Request request) {
113113
}
114114

115115
protected virtual void DoRelease(Release release) {
116-
if (!Users.Remove(release.Request)) {
117-
RequestQueue.TryRemove(release.Request);
118-
}
116+
if (!Users.Remove(release.Request))
117+
throw new InvalidOperationException("Released request does not have a user.");
119118
release.Succeed();
120119
}
121120

@@ -134,6 +133,12 @@ protected virtual void TriggerRequest(Event @event = null) {
134133
protected virtual void TriggerRelease(Event @event = null) {
135134
while (ReleaseQueue.Count > 0) {
136135
var release = ReleaseQueue.Peek();
136+
if (release.Request.IsAlive) {
137+
if (!RequestQueue.TryRemove(release.Request))
138+
throw new InvalidOperationException("Failed to cancel a request.");
139+
release.Succeed();
140+
ReleaseQueue.Dequeue();
141+
}
137142
DoRelease(release);
138143
if (release.IsTriggered) {
139144
ReleaseQueue.Dequeue();

SimSharp/Core/Resources/Resource.cs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,8 @@ protected virtual void DoRequest(Request request) {
113113
}
114114

115115
protected virtual void DoRelease(Release release) {
116-
if (!Users.Remove(release.Request)) {
117-
var current = RequestQueue.First;
118-
while (current != null && current.Value != release.Request)
119-
current = current.Next;
120-
if (current != null) RequestQueue.Remove(current);
121-
}
116+
if (!Users.Remove(release.Request))
117+
throw new InvalidOperationException("Released request does not have a user.");
122118
release.Succeed();
123119
}
124120

@@ -137,13 +133,20 @@ protected virtual void TriggerRequest(Event @event = null) {
137133
protected virtual void TriggerRelease(Event @event = null) {
138134
while (ReleaseQueue.Count > 0) {
139135
var release = ReleaseQueue.Peek();
140-
DoRelease(release);
141-
if (release.IsTriggered) {
136+
if (release.Request.IsAlive) {
137+
if (!RequestQueue.Remove(release.Request))
138+
throw new InvalidOperationException("Failed to cancel a request.");
139+
release.Succeed();
142140
ReleaseQueue.Dequeue();
143-
TriggerWhenAny();
144-
TriggerWhenFull();
145-
TriggerWhenChange();
146-
} else break;
141+
} else {
142+
DoRelease(release);
143+
if (release.IsTriggered) {
144+
ReleaseQueue.Dequeue();
145+
TriggerWhenAny();
146+
TriggerWhenFull();
147+
TriggerWhenChange();
148+
} else break;
149+
}
147150
}
148151
}
149152

SimSharp/Core/Resources/ResourcePool.cs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -144,13 +144,20 @@ protected virtual void TriggerRequest(Event @event = null) {
144144
protected virtual void TriggerRelease(Event @event = null) {
145145
while (ReleaseQueue.Count > 0) {
146146
var release = ReleaseQueue.Peek();
147-
DoRelease(release);
148-
if (release.IsTriggered) {
147+
if (release.Request.IsAlive) {
148+
if (!RequestQueue.Remove((ResourcePoolRequest)release.Request))
149+
throw new InvalidOperationException("Failed to cancel a request.");
150+
release.Succeed();
149151
ReleaseQueue.Dequeue();
150-
TriggerWhenAny();
151-
TriggerWhenFull();
152-
TriggerWhenChange();
153-
} else break;
152+
} else {
153+
DoRelease(release);
154+
if (release.IsTriggered) {
155+
ReleaseQueue.Dequeue();
156+
TriggerWhenAny();
157+
TriggerWhenFull();
158+
TriggerWhenChange();
159+
} else break;
160+
}
154161
}
155162
}
156163

Tests/ResourceTest.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1332,5 +1332,26 @@ private IEnumerable<Event> TestWhenStarEventsPreemptiveResourceProcB(Simulation
13321332
yield return res.WhenFull();
13331333
Assert.Equal(8, env.NowD);
13341334
}
1335+
1336+
[Fact]
1337+
public void TestResourcePoolCanceledRequests() {
1338+
var env = new Simulation();
1339+
var pool = new ResourcePool(env, new object[] { 1, 2 });
1340+
env.Process(CancelResourcePoolProcess(env, pool));
1341+
env.Run();
1342+
Assert.False(pool.IsAvailable(x => x == null));
1343+
}
1344+
1345+
private IEnumerable<Event> CancelResourcePoolProcess(Simulation env, ResourcePool pool) {
1346+
var req1 = pool.Request(filter: x => x is int ? (int)x == 1 : false);
1347+
var req2 = pool.Request(filter: x => x is int ? (int)x == 2 : false);
1348+
var req3 = pool.Request(filter: x => x is int ? (int)x == 1 : false);
1349+
1350+
yield return req1;
1351+
yield return req2;
1352+
yield return pool.Release(req3); // cancel request
1353+
yield return pool.Release(req2);
1354+
yield return pool.Release(req1);
1355+
}
13351356
}
13361357
}

Tests/Tests.csproj

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,20 @@
1313
<Copyright>Andreas Beham</Copyright>
1414
</PropertyGroup>
1515

16+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
17+
<DefineConstants>DEBUG;TRACE</DefineConstants>
18+
</PropertyGroup>
19+
1620
<ItemGroup>
1721
<ProjectReference Include="..\SimSharp\SimSharp.csproj" />
1822
</ItemGroup>
1923

2024
<ItemGroup>
21-
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
22-
<PackageReference Include="xunit" Version="2.2.0" />
23-
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
25+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
26+
<PackageReference Include="xunit" Version="2.4.1" />
27+
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
28+
<PrivateAssets>all</PrivateAssets>
29+
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
30+
</PackageReference>
2431
</ItemGroup>
2532
</Project>

0 commit comments

Comments
 (0)