1 //  boost process_timer.cpp  -----------------------------------------------------------//
2 
3 //  Copyright Beman Dawes 1994, 2006, 2008
4 //  Copyright 2009-2010 Vicente J. Botet Escriba
5 //  Copyright (c) Microsoft Corporation 2014
6 
7 //  Distributed under the Boost Software License, Version 1.0.
8 //  See http://www.boost.org/LICENSE_1_0.txt
9 
10 //  See http://www.boost.org/libs/chrono for documentation.
11 
12 //--------------------------------------------------------------------------------------//
13 #ifndef BOOST_CHRONO_DETAIL_INLINED_WIN_PROCESS_CLOCK_HPP
14 #define BOOST_CHRONO_DETAIL_INLINED_WIN_PROCESS_CLOCK_HPP
15 
16 #include <boost/chrono/config.hpp>
17 #include <boost/chrono/process_cpu_clocks.hpp>
18 #include <cassert>
19 #include <time.h>
20 #include <boost/assert.hpp>
21 
22 #include <boost/winapi/get_last_error.hpp>
23 #include <boost/winapi/get_current_process.hpp>
24 #if BOOST_PLAT_WINDOWS_DESKTOP
25 #include <boost/winapi/get_process_times.hpp>
26 #endif
27 
28 namespace boost
29 {
30 namespace chrono
31 {
32 
now()33 process_real_cpu_clock::time_point process_real_cpu_clock::now() BOOST_NOEXCEPT
34 {
35     clock_t c = ::clock();
36     if ( c == clock_t(-1) ) // error
37     {
38       BOOST_ASSERT(0 && "Boost::Chrono - Internal Error");
39     }
40     typedef ratio_divide<giga, ratio<CLOCKS_PER_SEC> >::type R;
41     return time_point(
42       duration(static_cast<rep>(c)*R::num/R::den)
43     );
44 }
45 
46 #if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING
now(system::error_code & ec)47 process_real_cpu_clock::time_point process_real_cpu_clock::now(
48         system::error_code & ec)
49 {
50     clock_t c = ::clock();
51     if ( c == clock_t(-1) ) // error
52     {
53             boost::throw_exception(
54                     system::system_error(
55                             errno,
56                             ::boost::system::system_category(),
57                             "chrono::process_real_cpu_clock" ));
58     }
59     if (!::boost::chrono::is_throws(ec))
60     {
61       ec.clear();
62     }
63     typedef ratio_divide<giga, ratio<CLOCKS_PER_SEC> >::type R;
64     return time_point(
65       duration(static_cast<rep>(c)*R::num/R::den)
66     );
67 }
68 #endif
69 
70 #if BOOST_PLAT_WINDOWS_DESKTOP
now()71 process_user_cpu_clock::time_point process_user_cpu_clock::now() BOOST_NOEXCEPT
72 {
73 
74     //  note that Windows uses 100 nanosecond ticks for FILETIME
75     boost::winapi::FILETIME_ creation, exit, user_time, system_time;
76 
77     if ( boost::winapi::GetProcessTimes(
78             boost::winapi::GetCurrentProcess(), &creation, &exit,
79             &system_time, &user_time ) )
80     {
81         return time_point(duration(
82                 ((static_cast<process_user_cpu_clock::rep>(user_time.dwHighDateTime) << 32)
83                   | user_time.dwLowDateTime) * 100
84                 ));
85     }
86     else
87     {
88         BOOST_ASSERT(0 && "Boost::Chrono - Internal Error");
89         return time_point();
90     }
91 
92 }
93 
94 #if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING
now(system::error_code & ec)95 process_user_cpu_clock::time_point process_user_cpu_clock::now(
96         system::error_code & ec)
97 {
98 
99     //  note that Windows uses 100 nanosecond ticks for FILETIME
100     boost::winapi::FILETIME_ creation, exit, user_time, system_time;
101 
102     if ( boost::winapi::GetProcessTimes(
103             boost::winapi::GetCurrentProcess(), &creation, &exit,
104             &system_time, &user_time ) )
105     {
106         if (!::boost::chrono::is_throws(ec))
107         {
108             ec.clear();
109         }
110         return time_point(duration(
111                 ((static_cast<process_user_cpu_clock::rep>(user_time.dwHighDateTime) << 32)
112                   | user_time.dwLowDateTime) * 100
113                 ));
114     }
115     else
116     {
117         boost::winapi::DWORD_ cause = boost::winapi::GetLastError();
118         if (::boost::chrono::is_throws(ec))
119         {
120             boost::throw_exception(
121                     system::system_error(
122                             cause,
123                             ::boost::system::system_category(),
124                             "chrono::process_user_cpu_clock" ));
125         }
126         else
127         {
128             ec.assign( cause, ::boost::system::system_category() );
129             return time_point();
130         }
131     }
132 
133 }
134 #endif
135 
now()136 process_system_cpu_clock::time_point process_system_cpu_clock::now() BOOST_NOEXCEPT
137 {
138 
139     //  note that Windows uses 100 nanosecond ticks for FILETIME
140     boost::winapi::FILETIME_ creation, exit, user_time, system_time;
141 
142     if ( boost::winapi::GetProcessTimes(
143             boost::winapi::GetCurrentProcess(), &creation, &exit,
144             &system_time, &user_time ) )
145     {
146         return time_point(duration(
147                 ((static_cast<process_system_cpu_clock::rep>(system_time.dwHighDateTime) << 32)
148                                     | system_time.dwLowDateTime) * 100
149                 ));
150     }
151     else
152     {
153       BOOST_ASSERT(0 && "Boost::Chrono - Internal Error");
154       return time_point();
155     }
156 
157 }
158 
159 #if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING
now(system::error_code & ec)160 process_system_cpu_clock::time_point process_system_cpu_clock::now(
161         system::error_code & ec)
162 {
163 
164     //  note that Windows uses 100 nanosecond ticks for FILETIME
165     boost::winapi::FILETIME_ creation, exit, user_time, system_time;
166 
167     if ( boost::winapi::GetProcessTimes(
168             boost::winapi::GetCurrentProcess(), &creation, &exit,
169             &system_time, &user_time ) )
170     {
171         if (!::boost::chrono::is_throws(ec))
172         {
173             ec.clear();
174         }
175         return time_point(duration(
176                 ((static_cast<process_system_cpu_clock::rep>(system_time.dwHighDateTime) << 32)
177                                     | system_time.dwLowDateTime) * 100
178                 ));
179     }
180     else
181     {
182         boost::winapi::DWORD_ cause = boost::winapi::GetLastError();
183         if (::boost::chrono::is_throws(ec))
184         {
185             boost::throw_exception(
186                     system::system_error(
187                             cause,
188                             ::boost::system::system_category(),
189                             "chrono::process_system_cpu_clock" ));
190         }
191         else
192         {
193             ec.assign( cause, ::boost::system::system_category() );
194             return time_point();
195         }
196     }
197 
198 }
199 #endif
200 
now()201 process_cpu_clock::time_point process_cpu_clock::now()  BOOST_NOEXCEPT
202 {
203 
204     //  note that Windows uses 100 nanosecond ticks for FILETIME
205     boost::winapi::FILETIME_ creation, exit, user_time, system_time;
206 
207     if ( boost::winapi::GetProcessTimes(
208             boost::winapi::GetCurrentProcess(), &creation, &exit,
209             &system_time, &user_time ) )
210     {
211         time_point::rep r(process_real_cpu_clock::now().time_since_epoch().count()
212                             ,
213                 ((static_cast<process_user_cpu_clock::rep>(user_time.dwHighDateTime) << 32)
214                         | user_time.dwLowDateTime
215                 ) * 100,
216                 ((static_cast<process_system_cpu_clock::rep>(system_time.dwHighDateTime) << 32)
217                         | system_time.dwLowDateTime
218                 ) * 100
219         );
220         return time_point(duration(r));
221     }
222     else
223     {
224       BOOST_ASSERT(0 && "Boost::Chrono - Internal Error");
225       return time_point();
226     }
227 
228 }
229 
230 #if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING
now(system::error_code & ec)231 process_cpu_clock::time_point process_cpu_clock::now(
232         system::error_code & ec )
233 {
234 
235     //  note that Windows uses 100 nanosecond ticks for FILETIME
236     boost::winapi::FILETIME_ creation, exit, user_time, system_time;
237 
238     if ( boost::winapi::GetProcessTimes(
239             boost::winapi::GetCurrentProcess(), &creation, &exit,
240             &system_time, &user_time ) )
241     {
242         if (!::boost::chrono::is_throws(ec))
243         {
244             ec.clear();
245         }
246         time_point::rep r(process_real_cpu_clock::now().time_since_epoch().count()
247                             ,
248                 ((static_cast<process_user_cpu_clock::rep>(user_time.dwHighDateTime) << 32)
249                         | user_time.dwLowDateTime
250                 ) * 100,
251                 ((static_cast<process_system_cpu_clock::rep>(system_time.dwHighDateTime) << 32)
252                         | system_time.dwLowDateTime
253                 ) * 100
254         );
255         return time_point(duration(r));
256     }
257     else
258     {
259         boost::winapi::DWORD_ cause = boost::winapi::GetLastError();
260         if (::boost::chrono::is_throws(ec))
261         {
262             boost::throw_exception(
263                     system::system_error(
264                             cause,
265                             ::boost::system::system_category(),
266                             "chrono::process_cpu_clock" ));
267         }
268         else
269         {
270             ec.assign( cause, ::boost::system::system_category() );
271             return time_point();
272         }
273     }
274 
275 }
276 #endif
277 #endif
278 } // namespace chrono
279 } // namespace boost
280 
281 #endif
282