~ubuntu-branches/ubuntu/oneiric/monodevelop/oneiric

« back to all changes in this revision

Viewing changes to contrib/NGit/NGit/ThreadSafeProgressMonitor.cs

  • Committer: Bazaar Package Importer
  • Author(s): Jo Shields
  • Date: 2011-06-27 17:03:13 UTC
  • mto: (1.8.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 54.
  • Revision ID: james.westby@ubuntu.com-20110627170313-6cvz3s19x6e9hqe9
ImportĀ upstreamĀ versionĀ 2.5.92+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
This code is derived from jgit (http://eclipse.org/jgit).
 
3
Copyright owners are documented in jgit's IP log.
 
4
 
 
5
This program and the accompanying materials are made available
 
6
under the terms of the Eclipse Distribution License v1.0 which
 
7
accompanies this distribution, is reproduced below, and is
 
8
available at http://www.eclipse.org/org/documents/edl-v10.php
 
9
 
 
10
All rights reserved.
 
11
 
 
12
Redistribution and use in source and binary forms, with or
 
13
without modification, are permitted provided that the following
 
14
conditions are met:
 
15
 
 
16
- Redistributions of source code must retain the above copyright
 
17
  notice, this list of conditions and the following disclaimer.
 
18
 
 
19
- Redistributions in binary form must reproduce the above
 
20
  copyright notice, this list of conditions and the following
 
21
  disclaimer in the documentation and/or other materials provided
 
22
  with the distribution.
 
23
 
 
24
- Neither the name of the Eclipse Foundation, Inc. nor the
 
25
  names of its contributors may be used to endorse or promote
 
26
  products derived from this software without specific prior
 
27
  written permission.
 
28
 
 
29
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 
30
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 
31
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 
32
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
33
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 
34
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
35
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 
36
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 
37
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 
38
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 
39
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 
40
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 
41
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
42
*/
 
43
 
 
44
using System;
 
45
using System.Threading;
 
46
using NGit;
 
47
using Sharpen;
 
48
 
 
49
namespace NGit
 
50
{
 
51
        /// <summary>
 
52
        /// Wrapper around the general
 
53
        /// <see cref="ProgressMonitor">ProgressMonitor</see>
 
54
        /// to make it thread safe.
 
55
        /// Updates to the underlying ProgressMonitor are made only from the thread that
 
56
        /// allocated this wrapper. Callers are responsible for ensuring the allocating
 
57
        /// thread uses
 
58
        /// <see cref="PollForUpdates()">PollForUpdates()</see>
 
59
        /// or
 
60
        /// <see cref="WaitForCompletion()">WaitForCompletion()</see>
 
61
        /// to
 
62
        /// update the underlying ProgressMonitor.
 
63
        /// Only
 
64
        /// <see cref="Update(int)">Update(int)</see>
 
65
        /// ,
 
66
        /// <see cref="IsCancelled()">IsCancelled()</see>
 
67
        /// , and
 
68
        /// <see cref="EndWorker()">EndWorker()</see>
 
69
        /// may be invoked from a worker thread. All other methods of the ProgressMonitor
 
70
        /// interface can only be called from the thread that allocates this wrapper.
 
71
        /// </summary>
 
72
        public class ThreadSafeProgressMonitor : ProgressMonitor
 
73
        {
 
74
                private readonly ProgressMonitor pm;
 
75
 
 
76
                private readonly ReentrantLock Lock;
 
77
 
 
78
                private readonly Sharpen.Thread mainThread;
 
79
 
 
80
                private readonly AtomicInteger workers;
 
81
 
 
82
                private readonly AtomicInteger pendingUpdates;
 
83
 
 
84
                private readonly Semaphore process;
 
85
 
 
86
                /// <summary>Wrap a ProgressMonitor to be thread safe.</summary>
 
87
                /// <remarks>Wrap a ProgressMonitor to be thread safe.</remarks>
 
88
                /// <param name="pm">the underlying monitor to receive events.</param>
 
89
                public ThreadSafeProgressMonitor(ProgressMonitor pm)
 
90
                {
 
91
                        this.pm = pm;
 
92
                        this.Lock = new ReentrantLock();
 
93
                        this.mainThread = Sharpen.Thread.CurrentThread();
 
94
                        this.workers = new AtomicInteger(0);
 
95
                        this.pendingUpdates = new AtomicInteger(0);
 
96
                        this.process = Sharpen.Extensions.CreateSemaphore(0);
 
97
                }
 
98
 
 
99
                public override void Start(int totalTasks)
 
100
                {
 
101
                        if (!IsMainThread())
 
102
                        {
 
103
                                throw new InvalidOperationException();
 
104
                        }
 
105
                        pm.Start(totalTasks);
 
106
                }
 
107
 
 
108
                public override void BeginTask(string title, int totalWork)
 
109
                {
 
110
                        if (!IsMainThread())
 
111
                        {
 
112
                                throw new InvalidOperationException();
 
113
                        }
 
114
                        pm.BeginTask(title, totalWork);
 
115
                }
 
116
 
 
117
                /// <summary>Notify the monitor a worker is starting.</summary>
 
118
                /// <remarks>Notify the monitor a worker is starting.</remarks>
 
119
                public virtual void StartWorker()
 
120
                {
 
121
                        StartWorkers(1);
 
122
                }
 
123
 
 
124
                /// <summary>Notify the monitor of workers starting.</summary>
 
125
                /// <remarks>Notify the monitor of workers starting.</remarks>
 
126
                /// <param name="count">the number of worker threads that are starting.</param>
 
127
                public virtual void StartWorkers(int count)
 
128
                {
 
129
                        workers.AddAndGet(count);
 
130
                }
 
131
 
 
132
                /// <summary>Notify the monitor a worker is finished.</summary>
 
133
                /// <remarks>Notify the monitor a worker is finished.</remarks>
 
134
                public virtual void EndWorker()
 
135
                {
 
136
                        if (workers.DecrementAndGet() == 0)
 
137
                        {
 
138
                                process.Release();
 
139
                        }
 
140
                }
 
141
 
 
142
                /// <summary>Non-blocking poll for pending updates.</summary>
 
143
                /// <remarks>
 
144
                /// Non-blocking poll for pending updates.
 
145
                /// This method can only be invoked by the same thread that allocated this
 
146
                /// ThreadSafeProgressMonior.
 
147
                /// </remarks>
 
148
                public virtual void PollForUpdates()
 
149
                {
 
150
                        //assert isMainThread();
 
151
                        DoUpdates();
 
152
                }
 
153
 
 
154
                /// <summary>Process pending updates and wait for workers to finish.</summary>
 
155
                /// <remarks>
 
156
                /// Process pending updates and wait for workers to finish.
 
157
                /// This method can only be invoked by the same thread that allocated this
 
158
                /// ThreadSafeProgressMonior.
 
159
                /// </remarks>
 
160
                /// <exception cref="System.Exception">
 
161
                /// if the main thread is interrupted while waiting for
 
162
                /// completion of workers.
 
163
                /// </exception>
 
164
                public virtual void WaitForCompletion()
 
165
                {
 
166
                        //assert isMainThread();
 
167
                        while (0 < workers.Get())
 
168
                        {
 
169
                                DoUpdates();
 
170
                                process.WaitOne();
 
171
                        }
 
172
                        DoUpdates();
 
173
                }
 
174
 
 
175
                private void DoUpdates()
 
176
                {
 
177
                        int cnt = pendingUpdates.GetAndSet(0);
 
178
                        if (0 < cnt)
 
179
                        {
 
180
                                pm.Update(cnt);
 
181
                        }
 
182
                }
 
183
 
 
184
                public override void Update(int completed)
 
185
                {
 
186
                        int old = pendingUpdates.GetAndAdd(completed);
 
187
                        if (IsMainThread())
 
188
                        {
 
189
                                DoUpdates();
 
190
                        }
 
191
                        else
 
192
                        {
 
193
                                if (old == 0)
 
194
                                {
 
195
                                        process.Release();
 
196
                                }
 
197
                        }
 
198
                }
 
199
 
 
200
                public override bool IsCancelled()
 
201
                {
 
202
                        Lock.Lock();
 
203
                        try
 
204
                        {
 
205
                                return pm.IsCancelled();
 
206
                        }
 
207
                        finally
 
208
                        {
 
209
                                Lock.Unlock();
 
210
                        }
 
211
                }
 
212
 
 
213
                public override void EndTask()
 
214
                {
 
215
                        if (!IsMainThread())
 
216
                        {
 
217
                                throw new InvalidOperationException();
 
218
                        }
 
219
                        pm.EndTask();
 
220
                }
 
221
 
 
222
                private bool IsMainThread()
 
223
                {
 
224
                        return Sharpen.Thread.CurrentThread() == mainThread;
 
225
                }
 
226
        }
 
227
}