1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 *
16 * The Original Code is Copyright (C) 2018 Blender Foundation.
17 * All rights reserved.
18 */
19
20 /** \file
21 * \ingroup bli
22 */
23
24 #include "BLI_timer.h"
25 #include "BLI_listbase.h"
26
27 #include "MEM_guardedalloc.h"
28 #include "PIL_time.h"
29
30 #define GET_TIME() PIL_check_seconds_timer()
31
32 typedef struct TimedFunction {
33 struct TimedFunction *next, *prev;
34 BLI_timer_func func;
35 BLI_timer_data_free user_data_free;
36 void *user_data;
37 double next_time;
38 uintptr_t uuid;
39 bool tag_removal;
40 bool persistent;
41 } TimedFunction;
42
43 typedef struct TimerContainer {
44 ListBase funcs;
45 } TimerContainer;
46
47 static TimerContainer GlobalTimer = {{0}};
48
BLI_timer_register(uintptr_t uuid,BLI_timer_func func,void * user_data,BLI_timer_data_free user_data_free,double first_interval,bool persistent)49 void BLI_timer_register(uintptr_t uuid,
50 BLI_timer_func func,
51 void *user_data,
52 BLI_timer_data_free user_data_free,
53 double first_interval,
54 bool persistent)
55 {
56 TimedFunction *timed_func = MEM_callocN(sizeof(TimedFunction), __func__);
57 timed_func->func = func;
58 timed_func->user_data_free = user_data_free;
59 timed_func->user_data = user_data;
60 timed_func->next_time = GET_TIME() + first_interval;
61 timed_func->tag_removal = false;
62 timed_func->persistent = persistent;
63 timed_func->uuid = uuid;
64
65 BLI_addtail(&GlobalTimer.funcs, timed_func);
66 }
67
clear_user_data(TimedFunction * timed_func)68 static void clear_user_data(TimedFunction *timed_func)
69 {
70 if (timed_func->user_data_free) {
71 timed_func->user_data_free(timed_func->uuid, timed_func->user_data);
72 timed_func->user_data_free = NULL;
73 }
74 }
75
BLI_timer_unregister(uintptr_t uuid)76 bool BLI_timer_unregister(uintptr_t uuid)
77 {
78 LISTBASE_FOREACH (TimedFunction *, timed_func, &GlobalTimer.funcs) {
79 if (timed_func->uuid == uuid && !timed_func->tag_removal) {
80 timed_func->tag_removal = true;
81 clear_user_data(timed_func);
82 return true;
83 }
84 }
85 return false;
86 }
87
BLI_timer_is_registered(uintptr_t uuid)88 bool BLI_timer_is_registered(uintptr_t uuid)
89 {
90 LISTBASE_FOREACH (TimedFunction *, timed_func, &GlobalTimer.funcs) {
91 if (timed_func->uuid == uuid && !timed_func->tag_removal) {
92 return true;
93 }
94 }
95 return false;
96 }
97
execute_functions_if_necessary(void)98 static void execute_functions_if_necessary(void)
99 {
100 double current_time = GET_TIME();
101
102 LISTBASE_FOREACH (TimedFunction *, timed_func, &GlobalTimer.funcs) {
103 if (timed_func->tag_removal) {
104 continue;
105 }
106 if (timed_func->next_time > current_time) {
107 continue;
108 }
109
110 double ret = timed_func->func(timed_func->uuid, timed_func->user_data);
111
112 if (ret < 0) {
113 timed_func->tag_removal = true;
114 }
115 else {
116 timed_func->next_time = current_time + ret;
117 }
118 }
119 }
120
remove_tagged_functions(void)121 static void remove_tagged_functions(void)
122 {
123 for (TimedFunction *timed_func = GlobalTimer.funcs.first; timed_func;) {
124 TimedFunction *next = timed_func->next;
125 if (timed_func->tag_removal) {
126 clear_user_data(timed_func);
127 BLI_freelinkN(&GlobalTimer.funcs, timed_func);
128 }
129 timed_func = next;
130 }
131 }
132
BLI_timer_execute()133 void BLI_timer_execute()
134 {
135 execute_functions_if_necessary();
136 remove_tagged_functions();
137 }
138
BLI_timer_free()139 void BLI_timer_free()
140 {
141 LISTBASE_FOREACH (TimedFunction *, timed_func, &GlobalTimer.funcs) {
142 timed_func->tag_removal = true;
143 }
144
145 remove_tagged_functions();
146 }
147
remove_non_persistent_functions(void)148 static void remove_non_persistent_functions(void)
149 {
150 LISTBASE_FOREACH (TimedFunction *, timed_func, &GlobalTimer.funcs) {
151 if (!timed_func->persistent) {
152 timed_func->tag_removal = true;
153 }
154 }
155 }
156
BLI_timer_on_file_load(void)157 void BLI_timer_on_file_load(void)
158 {
159 remove_non_persistent_functions();
160 }
161