aboutsummaryrefslogtreecommitdiffstats
path: root/fnet/src/vespa/fnet/scheduler.h
blob: d9a65efde3495f807bb19deb9a28992b01cfb16b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#pragma once

#include <vespa/vespalib/util/time.h>
#include <mutex>
#include <condition_variable>

class FNET_Task;

/**
 * An object of this class handles scheduling of @ref FNET_Task
 * objects. A task may be scheduled to be performed in a given number
 * of seconds. A scheduled task may also be unscheduled to cancel the
 * performing of that task. A scheduler object does not have its own
 * thread, but depends on being invoked regularely to perform pending
 * tasks.
 **/
class FNET_Scheduler
{
public:
    using clock = vespalib::steady_clock;
    static const vespalib::duration tick_ms;

    enum scheduler_constants {
        NUM_SLOTS   = 4096,
        SLOTS_MASK  = 4095,
        SLOTS_SHIFT =   12
    };

private:
    std::mutex              _lock;
    std::condition_variable _cond;
    FNET_Task              *_slots[NUM_SLOTS + 1];
    vespalib::steady_time   _next;
    vespalib::steady_time   _now;
    vespalib::steady_time  *_sampler;
    uint32_t                _currIter;
    uint32_t                _currSlot;
    FNET_Task              *_currPt;
    FNET_Task              *_tailPt;
    FNET_Task              *_performing;
    bool                    _waitTask;

    FNET_Scheduler(const FNET_Scheduler &);
    FNET_Scheduler &operator=(const FNET_Scheduler &);

    FNET_Task *GetTask() { return _currPt; }

    void FirstTask(uint32_t slot);
    void NextTask();
    void AdjustCurrPt();
    void AdjustTailPt();
    void LinkIn(FNET_Task *task);
    void LinkOut(FNET_Task *task);
    bool IsPerforming(FNET_Task *task) { return task == _performing; }
    void BeforeTask(std::unique_lock<std::mutex> &guard, FNET_Task *task);
    void AfterTask(std::unique_lock<std::mutex> &guard);
    void WaitTask(std::unique_lock<std::mutex> &guard, FNET_Task *task);
    void PerformTasks(std::unique_lock<std::mutex> &guard, uint32_t slot, uint32_t iter);
    bool IsActive(FNET_Task *task);

public:

    /**
     * Construct a scheduler.
     *
     * @param sampler if given, this object will be used to obtain the
     *                time when the @ref CheckTasks method is invoked. If a
     *                sampler is not given, time sampling will be
     *                handled internally. The sampler will also be used by
     *                the constructor to init internal variables.
     **/
    FNET_Scheduler(vespalib::steady_time *sampler = nullptr);
    virtual ~FNET_Scheduler();


    /**
     * Schedule a task to be performed in the given amount of
     * seconds.
     *
     * @param task the task to be scheduled.
     * @param seconds the number of seconds until the task
     *                should be performed.
     **/
    void Schedule(FNET_Task *task, double seconds);


    /**
     * Schedule a task to be performed as soon as possible.
     *
     * @param task the task to be scheduled.
     **/
    void ScheduleNow(FNET_Task *task);


    /**
     * Unschedule the given task. If the task is currently being
     * performed, this method will block until the task is
     * completed. This means that a task trying to unschedule itself
     * will result in a deadlock.
     *
     * @param task the task to unschedule.
     **/
    void Unschedule(FNET_Task *task);


    /**
     * This method does the same as the @ref Unschedule method, but also
     * makes sure that the task may not be scheduled in the future.
     **/
    void Kill(FNET_Task *task);


    /**
     * Print all currently scheduled tasks to the given file stream
     * (default is stdout). This method may be used for debugging.
     *
     * @param dst where to print the contents of this scheduler
     **/
    void Print(FILE *dst = stdout);


    /**
     * Perform pending tasks. This method should be invoked regularly.
     **/
    void CheckTasks();
};