summaryrefslogtreecommitdiff
path: root/indra/llcommon/workqueue.cpp
blob: 15e292fb439be8057e4703d2800c7b13698a3f7a (plain)
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
/**
 * @file   workqueue.cpp
 * @author Nat Goodspeed
 * @date   2021-10-06
 * @brief  Implementation for WorkQueue.
 * 
 * $LicenseInfo:firstyear=2021&license=viewerlgpl$
 * Copyright (c) 2021, Linden Research, Inc.
 * $/LicenseInfo$
 */

// Precompiled header
#include "linden_common.h"
// associated header
#include "workqueue.h"
// STL headers
// std headers
// external library headers
// other Linden headers
#include "llerror.h"
#include "llexception.h"
#include "stringize.h"

LL::WorkQueue::WorkQueue(const std::string& name):
    super(makeName(name))
{
    // TODO: register for "LLApp" events so we can implicitly close() on
    // viewer shutdown.
}

void LL::WorkQueue::close()
{
    mQueue.close();
}

void LL::WorkQueue::runUntilClose()
{
    try
    {
        for (;;)
        {
            callWork(mQueue.pop());
        }
    }
    catch (const Queue::Closed&)
    {
    }
}

bool LL::WorkQueue::runPending()
{
    for (Work work; mQueue.tryPop(work); )
    {
        callWork(work);
    }
    return ! mQueue.done();
}

bool LL::WorkQueue::runOne()
{
    Work work;
    if (mQueue.tryPop(work))
    {
        callWork(work);
    }
    return ! mQueue.done();
}

bool LL::WorkQueue::runUntil(const TimePoint& until)
{
    // Should we subtract some slop to allow for typical Work execution time?
    // How much slop?
    Work work;
    while (TimePoint::clock::now() < until && mQueue.tryPopUntil(until, work))
    {
        callWork(work);
    }
    return ! mQueue.done();
}

std::string LL::WorkQueue::makeName(const std::string& name)
{
    if (! name.empty())
        return name;

    static thread_local U32 discriminator = 0;
    return STRINGIZE("WorkQueue" << discriminator++);
}

void LL::WorkQueue::callWork(const Queue::DataTuple& work)
{
    // ThreadSafeSchedule::pop() always delivers a tuple, even when
    // there's only one data field per item, as for us.
    callWork(std::get<0>(work));
}

void LL::WorkQueue::callWork(const Work& work)
{
    try
    {
        work();
    }
    catch (...)
    {
        // No matter what goes wrong with any individual work item, the worker
        // thread must go on! Log our own instance name with the exception.
        LOG_UNHANDLED_EXCEPTION(getKey());
    }
}

void LL::WorkQueue::error(const std::string& msg)
{
    LL_ERRS("WorkQueue") << msg << LL_ENDL;
}