blob: f4951aa33a52377e985045f556613c2057bc4258 [file] [log] [blame]
Felix Meschbergerd5761072009-08-31 14:16:22 +00001/*
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19package org.apache.felix.cm.impl;
20
21
22import java.util.LinkedList;
23
24import org.osgi.service.log.LogService;
25
26
27/**
28 * The <code>UpdateThread</code> is the thread used to update managed services
29 * and managed service factories as well as to send configuration events.
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000030 */
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +000031public class UpdateThread implements Runnable
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000032{
33
34 // the configuration manager on whose behalf this thread is started
35 // (this is mainly used for logging)
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +000036 private final ConfigurationManager configurationManager;
37
Felix Meschberger4b26df92011-02-01 12:41:45 +000038 // the thread group into which the worker thread will be placed
39 private final ThreadGroup workerThreadGroup;
40
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +000041 // the thread's base name
42 private final String workerBaseName;
Felix Meschbergerd5761072009-08-31 14:16:22 +000043
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000044 // the queue of Runnable instances to be run
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +000045 private final LinkedList updateTasks;
46
47 // the actual thread
Felix Meschberger4b26df92011-02-01 12:41:45 +000048 private Thread worker;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000049
50
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +000051 public UpdateThread( final ConfigurationManager configurationManager, final ThreadGroup tg, final String name )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000052 {
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000053 this.configurationManager = configurationManager;
Felix Meschberger4b26df92011-02-01 12:41:45 +000054 this.workerThreadGroup = tg;
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +000055 this.workerBaseName = name;
56
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000057 this.updateTasks = new LinkedList();
58 }
59
60
61 // waits on Runnable instances coming into the queue. As instances come
62 // in, this method calls the Runnable.run method, logs any exception
63 // happening and keeps on waiting for the next Runnable. If the Runnable
64 // taken from the queue is this thread instance itself, the thread
65 // terminates.
66 public void run()
67 {
68 for ( ;; )
69 {
70 Runnable task;
71 synchronized ( updateTasks )
72 {
73 while ( updateTasks.isEmpty() )
74 {
75 try
76 {
77 updateTasks.wait();
78 }
79 catch ( InterruptedException ie )
80 {
81 // don't care
82 }
83 }
84
85 task = ( Runnable ) updateTasks.removeFirst();
86 }
87
88 // return if the task is this thread itself
89 if ( task == this )
90 {
91 return;
92 }
93
94 // otherwise execute the task, log any issues
95 try
96 {
Felix Meschbergerd5761072009-08-31 14:16:22 +000097 // set the thread name indicating the current task
Felix Meschberger4b26df92011-02-01 12:41:45 +000098 Thread.currentThread().setName( workerBaseName + " (" + task + ")" );
Felix Meschbergerd5761072009-08-31 14:16:22 +000099
Felix Meschberger4f269292011-10-21 13:52:31 +0000100 configurationManager.log( LogService.LOG_DEBUG, "Running task {0}", new Object[]
101 { task } );
Felix Meschberger58992482010-08-25 18:16:00 +0000102
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000103 task.run();
104 }
105 catch ( Throwable t )
106 {
107 configurationManager.log( LogService.LOG_ERROR, "Unexpected problem executing task", t );
108 }
Felix Meschbergerd5761072009-08-31 14:16:22 +0000109 finally
110 {
111 // reset the thread name to "idle"
Felix Meschberger4b26df92011-02-01 12:41:45 +0000112 Thread.currentThread().setName( workerBaseName );
Felix Meschbergerd5761072009-08-31 14:16:22 +0000113 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000114 }
115 }
116
Felix Meschberger4b26df92011-02-01 12:41:45 +0000117 /**
118 * Starts processing the queued tasks. This method does nothing if the
119 * worker has already been started.
120 */
121 synchronized void start()
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000122 {
Felix Meschberger4b26df92011-02-01 12:41:45 +0000123 if ( this.worker == null )
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +0000124 {
Felix Meschberger4b26df92011-02-01 12:41:45 +0000125 Thread workerThread = new Thread( workerThreadGroup, this, workerBaseName );
126 workerThread.setDaemon( true );
127 workerThread.start();
128 this.worker = workerThread;
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +0000129 }
Felix Meschberger4b26df92011-02-01 12:41:45 +0000130 }
131
132
133 /**
134 * Terminates the worker thread and waits for the thread to have processed
135 * all outstanding events up to and including the termination job. All
136 * jobs {@link #schedule(Runnable) scheduled} after termination has been
137 * initiated will not be processed any more. This method does nothing if
138 * the worker thread is not currently active.
139 * <p>
140 * If the worker thread does not terminate within 5 seconds it is killed
141 * by calling the (deprecated) <code>Thread.stop()</code> method. It may
142 * be that the worker thread may be blocked by a deadlock (it should not,
143 * though). In this case hope is that <code>Thread.stop()</code> will be
144 * able to released that deadlock at the expense of one or more tasks to
145 * not be executed any longer.... In any case an ERROR message is logged
146 * with the LogService in this situation.
147 */
148 synchronized void terminate()
149 {
150 if ( this.worker != null )
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +0000151 {
Felix Meschberger4b26df92011-02-01 12:41:45 +0000152 Thread workerThread = this.worker;
153 this.worker = null;
154
155 schedule( this );
156
157 // wait for all updates to terminate (<= 10 seconds !)
158 try
159 {
160 workerThread.join( 5000 );
161 }
162 catch ( InterruptedException ie )
163 {
164 // don't really care
165 }
166
167 if ( workerThread.isAlive() )
168 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000169 this.configurationManager.log( LogService.LOG_ERROR,
170 "Worker thread {0} did not terminate within 5 seconds; trying to kill", new Object[]
171 { workerBaseName } );
Felix Meschberger4b26df92011-02-01 12:41:45 +0000172 workerThread.stop();
173 }
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +0000174 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000175 }
176
177
178 // queue the given runnable to be run as soon as possible
179 void schedule( Runnable update )
180 {
181 synchronized ( updateTasks )
182 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000183 configurationManager.log( LogService.LOG_DEBUG, "Scheduling task {0}", new Object[]
184 { update } );
Felix Meschberger432e3872008-03-07 14:58:57 +0000185
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000186 // append to the task queue
187 updateTasks.add( update );
Felix Meschbergerd5761072009-08-31 14:16:22 +0000188
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000189 // notify the waiting thread
190 updateTasks.notifyAll();
191 }
192 }
193}