1/*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 /**
17 * @file task.h
18 *
19 * @brief Declares the task interfaces in C++.
20 *
21 * @since 10
22 * @version 1.0
23 */
24#ifndef FFRT_API_CPP_TASK_H
25#define FFRT_API_CPP_TASK_H
26#include <string>
27#include <vector>
28#include <functional>
29#include "c/task.h"
30
31namespace ffrt {
32class task_attr : public ffrt_task_attr_t {
33public:
34#if __has_builtin(__builtin_FUNCTION)
35    task_attr(const char* func = __builtin_FUNCTION())
36    {
37        ffrt_task_attr_init(this);
38        ffrt_task_attr_set_name(this, func);
39    }
40#else
41    task_attr()
42    {
43        ffrt_task_attr_init(this);
44    }
45#endif
46
47    ~task_attr()
48    {
49        ffrt_task_attr_destroy(this);
50    }
51
52    task_attr(const task_attr&) = delete;
53    task_attr& operator=(const task_attr&) = delete;
54
55    /**
56     * @brief Sets a task name.
57     *
58     * @param name Indicates a pointer to the task name.
59     * @since 10
60     * @version 1.0
61     */
62    inline task_attr& name(const char* name)
63    {
64        ffrt_task_attr_set_name(this, name);
65        return *this;
66    }
67
68    /**
69     * @brief Obtains the task name.
70     *
71     * @return Returns a pointer to the task name.
72     * @since 10
73     * @version 1.0
74     */
75    inline const char* name() const
76    {
77        return ffrt_task_attr_get_name(this);
78    }
79
80    /**
81     * @brief Sets the QoS for this task.
82     *
83     * @param qos Indicates the QoS.
84     * @since 10
85     * @version 1.0
86     */
87    inline task_attr& qos(qos qos_)
88    {
89        ffrt_task_attr_set_qos(this, qos_);
90        return *this;
91    }
92
93    /**
94     * @brief Obtains the QoS of this task.
95     *
96     * @return Returns the QoS.
97     * @since 10
98     * @version 1.0
99     */
100    inline int qos() const
101    {
102        return ffrt_task_attr_get_qos(this);
103    }
104
105    /**
106     * @brief Sets the delay time for this task.
107     *
108     * @param delay_us Indicates the delay time, in microseconds.
109     * @since 10
110     * @version 1.0
111     */
112    inline task_attr& delay(uint64_t delay_us)
113    {
114        ffrt_task_attr_set_delay(this, delay_us);
115        return *this;
116    }
117
118    /**
119     * @brief Obtains the delay time of this task.
120     *
121     * @return Returns the delay time.
122     * @since 10
123     * @version 1.0
124     */
125    inline uint64_t delay() const
126    {
127        return ffrt_task_attr_get_delay(this);
128    }
129
130    /**
131     * @brief Sets the priority for this task.
132     *
133     * @param priority Indicates the execute priority of concurrent queue task.
134     * @since 12
135     * @version 1.0
136     */
137    inline task_attr& priority(ffrt_queue_priority_t prio)
138    {
139        ffrt_task_attr_set_queue_priority(this, prio);
140        return *this;
141    }
142
143    /**
144     * @brief Obtains the priority of this task.
145     *
146     * @return Returns the priority of concurrent queue task.
147     * @since 12
148     * @version 1.0
149     */
150    inline ffrt_queue_priority_t priority() const
151    {
152        return ffrt_task_attr_get_queue_priority(this);
153    }
154
155    /**
156     * @brief Sets the stack size for this task.
157     *
158     * @param size Indicates the task stack size, unit is byte.
159     * @since 12
160     * @version 1.0
161     */
162    inline task_attr& stack_size(uint64_t size)
163    {
164        ffrt_task_attr_set_stack_size(this, size);
165        return *this;
166    }
167
168    /**
169     * @brief Obtains the stack size of this task.
170     *
171     * @return Returns task stack size, unit is byte.
172     * @since 12
173     * @version 1.0
174     */
175    inline uint64_t stack_size() const
176    {
177        return ffrt_task_attr_get_stack_size(this);
178    }
179};
180
181class task_handle {
182public:
183    task_handle() : p(nullptr)
184    {
185    }
186    task_handle(ffrt_task_handle_t p) : p(p)
187    {
188    }
189
190    ~task_handle()
191    {
192        if (p) {
193            ffrt_task_handle_destroy(p);
194        }
195    }
196
197    task_handle(task_handle const&) = delete;
198    task_handle& operator=(task_handle const&) = delete;
199
200    inline task_handle(task_handle&& h)
201    {
202        *this = std::move(h);
203    }
204
205    inline task_handle& operator=(task_handle&& h)
206    {
207        if (this != &h) {
208            if (p) {
209                ffrt_task_handle_destroy(p);
210            }
211            p = h.p;
212            h.p = nullptr;
213        }
214        return *this;
215    }
216
217    inline operator void* () const
218    {
219        return p;
220    }
221
222private:
223    ffrt_task_handle_t p = nullptr;
224};
225
226struct dependence : ffrt_dependence_t {
227    dependence(const void* d)
228    {
229        type = ffrt_dependence_data;
230        ptr = d;
231    }
232    dependence(const task_handle& h)
233    {
234        type = ffrt_dependence_task;
235        ptr = h;
236        ffrt_task_handle_inc_ref(const_cast<ffrt_task_handle_t>(ptr));
237    }
238
239    dependence(const dependence& other)
240    {
241        (*this) = other;
242    }
243
244    dependence(dependence&& other)
245    {
246        (*this) = std::move(other);
247    }
248
249    dependence& operator=(const dependence& other)
250    {
251        if (this != &other) {
252            type = other.type;
253            ptr = other.ptr;
254            if (type == ffrt_dependence_task) {
255                ffrt_task_handle_inc_ref(const_cast<ffrt_task_handle_t>(ptr));
256            }
257        }
258        return *this;
259    }
260
261    dependence& operator=(dependence&& other)
262    {
263        if (this != &other) {
264            type = other.type;
265            ptr = other.ptr;
266            other.ptr = nullptr;
267        }
268        return *this;
269    }
270
271    ~dependence()
272    {
273        if (type == ffrt_dependence_task && ptr) {
274            ffrt_task_handle_dec_ref(const_cast<ffrt_task_handle_t>(ptr));
275        }
276    }
277};
278
279template<class T>
280struct function {
281    ffrt_function_header_t header;
282    T closure;
283};
284
285template<class T>
286void exec_function_wrapper(void* t)
287{
288    auto f = reinterpret_cast<function<std::decay_t<T>>*>(t);
289    f->closure();
290}
291
292template<class T>
293void destroy_function_wrapper(void* t)
294{
295    auto f = reinterpret_cast<function<std::decay_t<T>>*>(t);
296    f->closure = nullptr;
297}
298
299template<class T>
300inline ffrt_function_header_t* create_function_wrapper(T&& func,
301    ffrt_function_kind_t kind = ffrt_function_kind_general)
302{
303    using function_type = function<std::decay_t<T>>;
304    static_assert(sizeof(function_type) <= ffrt_auto_managed_function_storage_size,
305        "size of function must be less than ffrt_auto_managed_function_storage_size");
306
307    auto p = ffrt_alloc_auto_managed_function_storage_base(kind);
308    auto f = new (p)function_type;
309    f->header.exec = exec_function_wrapper<T>;
310    f->header.destroy = destroy_function_wrapper<T>;
311    f->closure = std::forward<T>(func);
312    return reinterpret_cast<ffrt_function_header_t*>(f);
313}
314
315/**
316 * @brief Submits a task without input and output dependencies.
317 *
318 * @param func Indicates a task executor function closure.
319 * @param attr Indicates a task attribute.
320 * @since 10
321 * @version 1.0
322 */
323static inline void submit(std::function<void()>&& func, const task_attr& attr = {})
324{
325    return ffrt_submit_base(create_function_wrapper(std::move(func)), nullptr, nullptr, &attr);
326}
327
328/**
329 * @brief Submits a task with input dependencies only.
330 *
331 * @param func Indicates a task executor function closure.
332 * @param in_deps Indicates a pointer to the input dependencies.
333 * @param attr Indicates a task attribute.
334 * @since 10
335 * @version 1.0
336 */
337static inline void submit(std::function<void()>&& func, std::initializer_list<dependence> in_deps,
338    const task_attr& attr = {})
339{
340    ffrt_deps_t in{static_cast<uint32_t>(in_deps.size()), in_deps.begin()};
341    return ffrt_submit_base(create_function_wrapper(std::move(func)), &in, nullptr, &attr);
342}
343
344/**
345 * @brief Submits a task with input and output dependencies.
346 *
347 * @param func Indicates a task executor function closure.
348 * @param in_deps Indicates a pointer to the input dependencies.
349 * @param out_deps Indicates a pointer to the output dependencies.
350 * @param attr Indicates a task attribute.
351 * @since 10
352 * @version 1.0
353 */
354static inline void submit(std::function<void()>&& func, std::initializer_list<dependence> in_deps,
355    std::initializer_list<dependence> out_deps, const task_attr& attr = {})
356{
357    ffrt_deps_t in{static_cast<uint32_t>(in_deps.size()), in_deps.begin()};
358    ffrt_deps_t out{static_cast<uint32_t>(out_deps.size()), out_deps.begin()};
359    return ffrt_submit_base(create_function_wrapper(std::move(func)), &in, &out, &attr);
360}
361
362/**
363 * @brief Submits a task with input dependencies only.
364 *
365 * @param func Indicates a task executor function closure.
366 * @param in_deps Indicates a pointer to the input dependencies.
367 * @param attr Indicates a task attribute.
368 * @since 10
369 * @version 1.0
370 */
371static inline void submit(std::function<void()>&& func, const std::vector<dependence>& in_deps,
372    const task_attr& attr = {})
373{
374    ffrt_deps_t in{static_cast<uint32_t>(in_deps.size()), in_deps.data()};
375    return ffrt_submit_base(create_function_wrapper(std::move(func)), &in, nullptr, &attr);
376}
377
378/**
379 * @brief Submits a task with input and output dependencies.
380 *
381 * @param func Indicates a task executor function closure.
382 * @param in_deps Indicates a pointer to the input dependencies.
383 * @param out_deps Indicates a pointer to the output dependencies.
384 * @param attr Indicates a task attribute.
385 * @since 10
386 * @version 1.0
387 */
388static inline void submit(std::function<void()>&& func, const std::vector<dependence>& in_deps,
389    const std::vector<dependence>& out_deps, const task_attr& attr = {})
390{
391    ffrt_deps_t in{static_cast<uint32_t>(in_deps.size()), in_deps.data()};
392    ffrt_deps_t out{static_cast<uint32_t>(out_deps.size()), out_deps.data()};
393    return ffrt_submit_base(create_function_wrapper(std::move(func)), &in, &out, &attr);
394}
395
396/**
397 * @brief Submits a task without input and output dependencies.
398 *
399 * @param func Indicates a task executor function closure.
400 * @param attr Indicates a task attribute.
401 * @since 10
402 * @version 1.0
403 */
404static inline void submit(const std::function<void()>& func, const task_attr& attr = {})
405{
406    return ffrt_submit_base(create_function_wrapper(func), nullptr, nullptr, &attr);
407}
408
409/**
410 * @brief Submits a task with input dependencies only.
411 *
412 * @param func Indicates a task executor function closure.
413 * @param in_deps Indicates a pointer to the input dependencies.
414 * @param attr Indicates a task attribute.
415 * @since 10
416 * @version 1.0
417 */
418static inline void submit(const std::function<void()>& func, std::initializer_list<dependence> in_deps,
419    const task_attr& attr = {})
420{
421    ffrt_deps_t in{static_cast<uint32_t>(in_deps.size()), in_deps.begin()};
422    return ffrt_submit_base(create_function_wrapper(func), &in, nullptr, &attr);
423}
424
425/**
426 * @brief Submits a task with input and output dependencies.
427 *
428 * @param func Indicates a task executor function closure.
429 * @param in_deps Indicates a pointer to the input dependencies.
430 * @param out_deps Indicates a pointer to the output dependencies.
431 * @param attr Indicates a task attribute.
432 * @since 10
433 * @version 1.0
434 */
435static inline void submit(const std::function<void()>& func, std::initializer_list<dependence> in_deps,
436    std::initializer_list<dependence> out_deps, const task_attr& attr = {})
437{
438    ffrt_deps_t in{static_cast<uint32_t>(in_deps.size()), in_deps.begin()};
439    ffrt_deps_t out{static_cast<uint32_t>(out_deps.size()), out_deps.begin()};
440    return ffrt_submit_base(create_function_wrapper(func), &in, &out, &attr);
441}
442
443/**
444 * @brief Submits a task with input dependencies only.
445 *
446 * @param func Indicates a task executor function closure.
447 * @param in_deps Indicates a pointer to the input dependencies.
448 * @param attr Indicates a task attribute.
449 * @since 10
450 * @version 1.0
451 */
452static inline void submit(const std::function<void()>& func, const std::vector<dependence>& in_deps,
453    const task_attr& attr = {})
454{
455    ffrt_deps_t in{static_cast<uint32_t>(in_deps.size()), in_deps.data()};
456    return ffrt_submit_base(create_function_wrapper(func), &in, nullptr, &attr);
457}
458
459/**
460 * @brief Submits a task with input and output dependencies.
461 *
462 * @param func Indicates a task executor function closure.
463 * @param in_deps Indicates a pointer to the input dependencies.
464 * @param out_deps Indicates a pointer to the output dependencies.
465 * @param attr Indicates a task attribute.
466 * @since 10
467 * @version 1.0
468 */
469static inline void submit(const std::function<void()>& func, const std::vector<dependence>& in_deps,
470    const std::vector<dependence>& out_deps, const task_attr& attr = {})
471{
472    ffrt_deps_t in{static_cast<uint32_t>(in_deps.size()), in_deps.data()};
473    ffrt_deps_t out{static_cast<uint32_t>(out_deps.size()), out_deps.data()};
474    return ffrt_submit_base(create_function_wrapper(func), &in, &out, &attr);
475}
476
477/**
478 * @brief Submits a task without input and output dependencies, and obtains a task handle.
479 *
480 * @param func Indicates a task executor function closure.
481 * @param attr Indicates a task attribute.
482 * @return Returns a non-null task handle if the task is submitted;
483           returns a null pointer otherwise.
484 * @since 10
485 * @version 1.0
486 */
487static inline task_handle submit_h(std::function<void()>&& func, const task_attr& attr = {})
488{
489    return ffrt_submit_h_base(create_function_wrapper(std::move(func)), nullptr, nullptr, &attr);
490}
491
492/**
493 * @brief Submits a task with input dependencies only, and obtains a task handle.
494 *
495 * @param func Indicates a task executor function closure.
496 * @param in_deps Indicates a pointer to the input dependencies.
497 * @param attr Indicates a task attribute.
498 * @return Returns a non-null task handle if the task is submitted;
499           returns a null pointer otherwise.
500 * @since 10
501 * @version 1.0
502 */
503static inline task_handle submit_h(std::function<void()>&& func, std::initializer_list<dependence> in_deps,
504    const task_attr& attr = {})
505{
506    ffrt_deps_t in{static_cast<uint32_t>(in_deps.size()), in_deps.begin()};
507    return ffrt_submit_h_base(create_function_wrapper(std::move(func)), &in, nullptr, &attr);
508}
509
510/**
511 * @brief Submits a task with input and output dependencies, and obtains a task handle.
512 *
513 * @param func Indicates a task executor function closure.
514 * @param in_deps Indicates a pointer to the input dependencies.
515 * @param out_deps Indicates a pointer to the output dependencies.
516 * @param attr Indicates a task attribute.
517 * @return Returns a non-null task handle if the task is submitted;
518           returns a null pointer otherwise.
519 * @since 10
520 * @version 1.0
521 */
522static inline task_handle submit_h(std::function<void()>&& func, std::initializer_list<dependence> in_deps,
523    std::initializer_list<dependence> out_deps, const task_attr& attr = {})
524{
525    ffrt_deps_t in{static_cast<uint32_t>(in_deps.size()), in_deps.begin()};
526    ffrt_deps_t out{static_cast<uint32_t>(out_deps.size()), out_deps.begin()};
527    return ffrt_submit_h_base(create_function_wrapper(std::move(func)), &in, &out, &attr);
528}
529
530/**
531 * @brief Submits a task with input dependencies only, and obtains a task handle.
532 *
533 * @param func Indicates a task executor function closure.
534 * @param in_deps Indicates a pointer to the input dependencies.
535 * @param attr Indicates a task attribute.
536 * @return Returns a non-null task handle if the task is submitted;
537           returns a null pointer otherwise.
538 * @since 10
539 * @version 1.0
540 */
541static inline task_handle submit_h(std::function<void()>&& func, const std::vector<dependence>& in_deps,
542    const task_attr& attr = {})
543{
544    ffrt_deps_t in{static_cast<uint32_t>(in_deps.size()), in_deps.data()};
545    return ffrt_submit_h_base(create_function_wrapper(std::move(func)), &in, nullptr, &attr);
546}
547
548/**
549 * @brief Submits a task with input and output dependencies, and obtains a task handle.
550 *
551 * @param func Indicates a task executor function closure.
552 * @param in_deps Indicates a pointer to the input dependencies.
553 * @param out_deps Indicates a pointer to the output dependencies.
554 * @param attr Indicates a task attribute.
555 * @return Returns a non-null task handle if the task is submitted;
556           returns a null pointer otherwise.
557 * @since 10
558 * @version 1.0
559 */
560static inline task_handle submit_h(std::function<void()>&& func, const std::vector<dependence>& in_deps,
561    const std::vector<dependence>& out_deps, const task_attr& attr = {})
562{
563    ffrt_deps_t in{static_cast<uint32_t>(in_deps.size()), in_deps.data()};
564    ffrt_deps_t out{static_cast<uint32_t>(out_deps.size()), out_deps.data()};
565    return ffrt_submit_h_base(create_function_wrapper(std::move(func)), &in, &out, &attr);
566}
567
568/**
569 * @brief Submits a task without input and output dependencies, and obtains a task handle.
570 *
571 * @param func Indicates a task executor function closure.
572 * @param attr Indicates a task attribute.
573 * @return Returns a non-null task handle if the task is submitted;
574           returns a null pointer otherwise.
575 * @since 10
576 * @version 1.0
577 */
578static inline task_handle submit_h(const std::function<void()>& func, const task_attr& attr = {})
579{
580    return ffrt_submit_h_base(create_function_wrapper(func), nullptr, nullptr, &attr);
581}
582
583/**
584 * @brief Submits a task with input dependencies only, and obtains a task handle.
585 *
586 * @param func Indicates a task executor function closure.
587 * @param in_deps Indicates a pointer to the input dependencies.
588 * @param attr Indicates a task attribute.
589 * @return Returns a non-null task handle if the task is submitted;
590           returns a null pointer otherwise.
591 * @since 10
592 * @version 1.0
593 */
594static inline task_handle submit_h(const std::function<void()>& func, std::initializer_list<dependence> in_deps,
595    const task_attr& attr = {})
596{
597    ffrt_deps_t in{static_cast<uint32_t>(in_deps.size()), in_deps.begin()};
598    return ffrt_submit_h_base(create_function_wrapper(func), &in, nullptr, &attr);
599}
600
601/**
602 * @brief Submits a task with input and output dependencies, and obtains a task handle.
603 *
604 * @param func Indicates a task executor function closure.
605 * @param in_deps Indicates a pointer to the input dependencies.
606 * @param out_deps Indicates a pointer to the output dependencies.
607 * @param attr Indicates a task attribute.
608 * @return Returns a non-null task handle if the task is submitted;
609           returns a null pointer otherwise.
610 * @since 10
611 * @version 1.0
612 */
613static inline task_handle submit_h(const std::function<void()>& func, std::initializer_list<dependence> in_deps,
614    std::initializer_list<dependence> out_deps, const task_attr& attr = {})
615{
616    ffrt_deps_t in{static_cast<uint32_t>(in_deps.size()), in_deps.begin()};
617    ffrt_deps_t out{static_cast<uint32_t>(out_deps.size()), out_deps.begin()};
618    return ffrt_submit_h_base(create_function_wrapper(func), &in, &out, &attr);
619}
620
621/**
622 * @brief Submits a task with input dependencies only, and obtains a task handle.
623 *
624 * @param func Indicates a task executor function closure.
625 * @param in_deps Indicates a pointer to the input dependencies.
626 * @param attr Indicates a task attribute.
627 * @return Returns a non-null task handle if the task is submitted;
628           returns a null pointer otherwise.
629 * @since 10
630 * @version 1.0
631 */
632static inline task_handle submit_h(const std::function<void()>& func, const std::vector<dependence>& in_deps,
633    const task_attr& attr = {})
634{
635    ffrt_deps_t in{static_cast<uint32_t>(in_deps.size()), in_deps.data()};
636    return ffrt_submit_h_base(create_function_wrapper(func), &in, nullptr, &attr);
637}
638
639/**
640 * @brief Submits a task with input and output dependencies, and obtains a task handle.
641 *
642 * @param func Indicates a task executor function closure.
643 * @param in_deps Indicates a pointer to the input dependencies.
644 * @param out_deps Indicates a pointer to the output dependencies.
645 * @param attr Indicates a task attribute.
646 * @return Returns a non-null task handle if the task is submitted;
647           returns a null pointer otherwise.
648 * @since 10
649 * @version 1.0
650 */
651static inline task_handle submit_h(const std::function<void()>& func, const std::vector<dependence>& in_deps,
652    const std::vector<dependence>& out_deps, const task_attr& attr = {})
653{
654    ffrt_deps_t in{static_cast<uint32_t>(in_deps.size()), in_deps.data()};
655    ffrt_deps_t out{static_cast<uint32_t>(out_deps.size()), out_deps.data()};
656    return ffrt_submit_h_base(create_function_wrapper(func), &in, &out, &attr);
657}
658
659/**
660 * @brief Waits until all submitted tasks are complete.
661 *
662 * @since 10
663 * @version 1.0
664 */
665static inline void wait()
666{
667    ffrt_wait();
668}
669
670/**
671 * @brief Waits until dependent tasks are complete.
672 *
673 * @param deps Indicates a pointer to the dependent tasks.
674 * @since 10
675 * @version 1.0
676 */
677static inline void wait(std::initializer_list<dependence> deps)
678{
679    ffrt_deps_t d{static_cast<uint32_t>(deps.size()), deps.begin()};
680    ffrt_wait_deps(&d);
681}
682
683/**
684 * @brief Waits until dependent tasks are complete.
685 *
686 * @param deps Indicates a pointer to the dependent tasks.
687 * @since 10
688 * @version 1.0
689 */
690static inline void wait(const std::vector<dependence>& deps)
691{
692    ffrt_deps_t d{static_cast<uint32_t>(deps.size()), deps.data()};
693    ffrt_wait_deps(&d);
694}
695
696/**
697 * @brief Sets the thread stack size of a specified QoS level.
698 *
699 * @param qos_ Indicates the QoS.
700 * @param stack_size Indicates the thread stack size.
701 * @return Returns ffrt_success if the stack size set success;
702           returns ffrt_error_inval if qos_ or stack_size invalid;
703           returns ffrt_error otherwise.
704 * @since 10
705 * @version 1.0
706 */
707static inline ffrt_error_t set_worker_stack_size(qos qos_, size_t stack_size)
708{
709    return ffrt_set_worker_stack_size(qos_, stack_size);
710}
711
712namespace this_task {
713static inline int update_qos(qos qos_)
714{
715    return ffrt_this_task_update_qos(qos_);
716}
717
718/**
719 * @brief Obtains the ID of this task.
720 *
721 * @return Returns the task ID.
722 * @since 10
723 * @version 1.0
724 */
725static inline uint64_t get_id()
726{
727    return ffrt_this_task_get_id();
728}
729} // namespace this_task
730} // namespace ffrt
731#endif
732