package bes.injector;/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Represents, and communicates changes to, a worker's work state - there are three non-actively-working * states (STOP_SIGNALLED, STOPPED, AND SPINNING) and two working states: WORKING, and (ASSIGNED), the last * being represented by a non-static instance with its "assigned" executor set. * * STOPPED: indicates the worker is descheduled, and whilst accepts work in this state (causing it to * be rescheduled) it will generally not be considered for work until all other worker threads are busy. * In this state we should be present in the injector.descheduled collection, and should be parked * valid transitions -> (ASSIGNED)|SPINNING * * STOP_SIGNALLED: the worker has been asked to deschedule itself, but has not yet done so; only entered from a SPINNING * state, and generally communicated by and to itself, but maybe set from any worker. this state may be * preempted and replaced with (ASSIGNED) or SPINNING * In this state we should be present in the injector.descheduled collection * valid transitions -> (ASSIGNED)|STOPPED|SPINNING * * SPINNING: indicates the worker has no work to perform, so is performing friendly wait-based-spinning * until it either is (ASSIGNED) some work (by itself or another thread), or sent STOP_SIGNALLED * In this state we _may_ be in the injector.spinning collection (but only if we are in the middle of a sleep) * valid transitions -> (ASSIGNED)|STOP_SIGNALLED|SPINNING * * (ASSIGNED): asks the worker to perform some work against the specified executor, and preassigns a task permit * from that executor so that in this state there is always work to perform. * In general a worker assigns itself this state, but sometimes it may assign another worker the state * either if there is work outstanding and no-spinning threads, or there is a race to self-assign * valid transition -> WORKING * * WORKING: indicates the worker is actively processing an executor's task queue; in this state it accepts * no state changes/communications, except from itself; it usually exits this mode into SPINNING, * but if work is immediately available on another executor it self-triggers (ASSIGNED) * valid transitions -> SPINNING|(ASSIGNED) */ final class Work { static final Work STOP_SIGNALLED = new Work(); static final Work STOPPED = new Work(); static final Work SPINNING = new Work(); static final Work WORKING = new Work(); static final Work DEAD = new Work(); final InjectionExecutor assigned; Work(InjectionExecutor executor) { this.assigned = executor; } private Work() { this.assigned = null; } boolean canAssign(boolean self) { // we can assign work if there isn't new work already assigned (or we're dead) and either // 1) we are assigning to ourselves // 2) the worker we are assigning to is not already in the middle of WORKING return !(isDead() | isAssigned()) && (self || !isWorking()); } boolean isSpinning() { return this == Work.SPINNING; } boolean isWorking() { return this == Work.WORKING; } boolean isStop() { return this == Work.STOP_SIGNALLED; } boolean isStopped() { return this == Work.STOPPED; } boolean isDead() { return this == Work.DEAD; } boolean isAssigned() { return assigned != null; } }