summaryrefslogtreecommitdiffstats
path: root/src/usr/util/threadpool.C
blob: b51cca64291f5ff86390dc668cd3a34caa2b73b1 (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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/util/threadpool.C $                                   */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2012,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
#include <util/threadpool.H>
#include <sys/task.h>
#include <sys/misc.h>
#include <util/util_reasoncodes.H>
#include <errl/errlmanager.H>
#include <hbotcompid.H>

void Util::__Util_ThreadPool_Impl::ThreadPoolImpl::__init()
{
    // Initialize all member variables.
    iv_worklist.clear();
    mutex_init(&iv_mutex);
    sync_cond_init(&iv_condvar);
    iv_children.clear();
    iv_shutdown = false;
}

void Util::__Util_ThreadPool_Impl::ThreadPoolImpl::__insert(void* i_workItem)
{
    mutex_lock(&iv_mutex);

    // Insert item on to the work list and signal any worker thread that may
    // be waiting.
    iv_worklist.push_back(i_workItem);
    sync_cond_signal(&iv_condvar);

    mutex_unlock(&iv_mutex);
}

void* Util::__Util_ThreadPool_Impl::ThreadPoolImpl::__remove(order_fn_t fn)
{
    void* val = NULL;

    mutex_lock(&iv_mutex);
    do
    {
        // Wait until the worklist is empty or told to shutdown.
        while(iv_worklist.empty() && !iv_shutdown)
        {
            sync_cond_wait(&iv_condvar, &iv_mutex);
        }

        // If told to shutdown and no work remains, end thread.
        if (iv_worklist.empty() && iv_shutdown)
        {
            break;
        }

        // Otherwise, obtain next item from worklist, using order function
        // passed to us.
        worklist_itr_t itr = fn(iv_worklist.begin(), iv_worklist.end());

        val = *itr;
        iv_worklist.erase(itr);

    } while(0);

    mutex_unlock(&iv_mutex);

    return val;
}

void Util::__Util_ThreadPool_Impl::ThreadPoolImpl::__start(
        Util::__Util_ThreadPool_Impl::ThreadPoolImpl::start_fn_t fn,
        void* instance)
{
    mutex_lock(&iv_mutex);

    size_t thread_count = Util::ThreadPoolManager::getThreadCount();
    while(thread_count--)
    {
        // Create children and add to a queue for later joining (during
        // shutdown)
        iv_children.push_back(task_create(fn, instance));
    }

    mutex_unlock(&iv_mutex);
}

errlHndl_t Util::__Util_ThreadPool_Impl::ThreadPoolImpl::__shutdown()
{
    mutex_lock(&iv_mutex);

    int l_childRc = 0;
    void* l_childRetval = nullptr;
    errlHndl_t l_origError = nullptr;
    errlHndl_t l_errl = nullptr;

    // Set shutdown status and signal all children to release from their
    // condition variable.
    iv_shutdown = true;
    sync_cond_broadcast(&iv_condvar);

    // Join on all the children.
    while(!iv_children.empty())
    {
        tid_t child = iv_children.front();
        tid_t l_returnedTid = 0;
        iv_children.pop_front();

        mutex_unlock(&iv_mutex);
        l_returnedTid = task_wait_tid(child, &l_childRc, &l_childRetval);
        if(iv_checkChildRc &&
           ((l_returnedTid != child) ||
            (l_childRc != TASK_STATUS_EXITED_CLEAN)))
        {
            /**
             * @errortype
             * @moduleid         UTIL_MOD_TP_SHUTDOWN
             * @reasoncode       UTIL_RC_CHILD_TASK_FAILED
             * @userdata1        The return code of the child thread
             * @userdata2[0:31]  The returned task ID of the child thread
             * @userdata2[32:63] The original task ID of the child thread
             * @devdesc          The child thread of a thread pool returned an
             *                   error
             * @custdesc         A failure occurred during the IPL of the system
             */
            l_errl = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                             UTIL_MOD_TP_SHUTDOWN,
                                             UTIL_RC_CHILD_TASK_FAILED,
                                             l_childRc,
                                             TWO_UINT32_TO_UINT64(l_returnedTid,
                                                                  child),
                                             ERRORLOG::ErrlEntry::ADD_SW_CALLOUT
                                            );
            l_errl->collectTrace(UTIL_COMP_NAME);

            if(!l_origError)
            {
                l_origError = l_errl;
                l_errl = nullptr;
            }
            else
            {
                l_errl->plid(l_origError->plid());
                errlCommit(l_errl, UTIL_COMP_ID);
            }
        }
        mutex_lock(&iv_mutex);
    }

    mutex_unlock(&iv_mutex);
    return l_origError;
}

// Default thread count of one per HW thread.
size_t Util::ThreadPoolManager::cv_size = cpu_thread_count();
OpenPOWER on IntegriCloud