1 /*
2 *
3 * Copyright 2015 gRPC authors.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18
19 /**
20 * class Timeval
21 * @see https://github.com/grpc/grpc/tree/master/src/php/ext/grpc/timeval.c
22 */
23
24 #include "timeval.h"
25
26 #include <ext/spl/spl_exceptions.h>
27 #include <zend_exceptions.h>
28
29 zend_class_entry *grpc_ce_timeval;
30 PHP_GRPC_DECLARE_OBJECT_HANDLER(timeval_ce_handlers)
31
32 /* Frees and destroys an instance of wrapped_grpc_call */
PHP_GRPC_FREE_WRAPPED_FUNC_START(wrapped_grpc_timeval)33 PHP_GRPC_FREE_WRAPPED_FUNC_START(wrapped_grpc_timeval)
34 PHP_GRPC_FREE_WRAPPED_FUNC_END()
35
36 /* Initializes an instance of wrapped_grpc_timeval to be associated with an
37 * object of a class specified by class_type */
38 php_grpc_zend_object create_wrapped_grpc_timeval(zend_class_entry *class_type
39 TSRMLS_DC) {
40 PHP_GRPC_ALLOC_CLASS_OBJECT(wrapped_grpc_timeval);
41 zend_object_std_init(&intern->std, class_type TSRMLS_CC);
42 object_properties_init(&intern->std, class_type);
43 PHP_GRPC_FREE_CLASS_OBJECT(wrapped_grpc_timeval, timeval_ce_handlers);
44 }
45
grpc_php_wrap_timeval(gpr_timespec wrapped TSRMLS_DC)46 zval *grpc_php_wrap_timeval(gpr_timespec wrapped TSRMLS_DC) {
47 zval *timeval_object;
48 PHP_GRPC_MAKE_STD_ZVAL(timeval_object);
49 object_init_ex(timeval_object, grpc_ce_timeval);
50 wrapped_grpc_timeval *timeval =
51 PHP_GRPC_GET_WRAPPED_OBJECT(wrapped_grpc_timeval, timeval_object);
52 memcpy(&timeval->wrapped, &wrapped, sizeof(gpr_timespec));
53 return timeval_object;
54 }
55
56 /**
57 * Constructs a new instance of the Timeval class
58 * @param number $microseconds The number of microseconds in the interval
59 */
PHP_METHOD(Timeval,__construct)60 PHP_METHOD(Timeval, __construct) {
61 wrapped_grpc_timeval *timeval =
62 PHP_GRPC_GET_WRAPPED_OBJECT(wrapped_grpc_timeval, getThis());
63 int64_t microseconds = 0;
64
65 /* parse $microseconds as long */
66 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
67 ZEND_NUM_ARGS() TSRMLS_CC, "l",
68 µseconds) == FAILURE) {
69 double microsecondsDouble = 0.0;
70 /* parse $microseconds as double */
71 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
72 ZEND_NUM_ARGS() TSRMLS_CC, "d",
73 µsecondsDouble) == FAILURE) {
74 zend_throw_exception(spl_ce_InvalidArgumentException,
75 "Timeval expects a long or double", 1 TSRMLS_CC);
76 return;
77 }
78 microseconds = (int64_t)microsecondsDouble;
79 }
80 gpr_timespec time = gpr_time_from_micros(microseconds, GPR_TIMESPAN);
81 memcpy(&timeval->wrapped, &time, sizeof(gpr_timespec));
82 }
83
84 /**
85 * Adds another Timeval to this one and returns the sum. Calculations saturate
86 * at infinities.
87 * @param Timeval $other_obj The other Timeval object to add
88 * @return Timeval A new Timeval object containing the sum
89 */
PHP_METHOD(Timeval,add)90 PHP_METHOD(Timeval, add) {
91 zval *other_obj;
92
93 /* "O" == 1 Object */
94 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &other_obj,
95 grpc_ce_timeval) == FAILURE) {
96 zend_throw_exception(spl_ce_InvalidArgumentException,
97 "add expects a Timeval", 1 TSRMLS_CC);
98 return;
99 }
100 wrapped_grpc_timeval *self =
101 PHP_GRPC_GET_WRAPPED_OBJECT(wrapped_grpc_timeval, getThis());
102 wrapped_grpc_timeval *other =
103 PHP_GRPC_GET_WRAPPED_OBJECT(wrapped_grpc_timeval, other_obj);
104 zval *sum =
105 grpc_php_wrap_timeval(gpr_time_add(self->wrapped, other->wrapped)
106 TSRMLS_CC);
107 RETURN_DESTROY_ZVAL(sum);
108 }
109
110 /**
111 * Subtracts another Timeval from this one and returns the difference.
112 * Calculations saturate at infinities.
113 * @param Timeval $other_obj The other Timeval object to subtract
114 * @return Timeval A new Timeval object containing the diff
115 */
PHP_METHOD(Timeval,subtract)116 PHP_METHOD(Timeval, subtract) {
117 zval *other_obj;
118
119 /* "O" == 1 Object */
120 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &other_obj,
121 grpc_ce_timeval) == FAILURE) {
122 zend_throw_exception(spl_ce_InvalidArgumentException,
123 "subtract expects a Timeval", 1 TSRMLS_CC);
124 return;
125 }
126 wrapped_grpc_timeval *self =
127 PHP_GRPC_GET_WRAPPED_OBJECT(wrapped_grpc_timeval, getThis());
128 wrapped_grpc_timeval *other =
129 PHP_GRPC_GET_WRAPPED_OBJECT(wrapped_grpc_timeval, other_obj);
130 zval *diff =
131 grpc_php_wrap_timeval(gpr_time_sub(self->wrapped, other->wrapped)
132 TSRMLS_CC);
133 RETURN_DESTROY_ZVAL(diff);
134 }
135
136 /**
137 * Return negative, 0, or positive according to whether a < b, a == b,
138 * or a > b respectively.
139 * @param Timeval $a_obj The first time to compare
140 * @param Timeval $b_obj The second time to compare
141 * @return long
142 */
PHP_METHOD(Timeval,compare)143 PHP_METHOD(Timeval, compare) {
144 zval *a_obj;
145 zval *b_obj;
146
147 /* "OO" == 2 Objects */
148 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OO", &a_obj,
149 grpc_ce_timeval, &b_obj,
150 grpc_ce_timeval) == FAILURE) {
151 zend_throw_exception(spl_ce_InvalidArgumentException,
152 "compare expects two Timevals", 1 TSRMLS_CC);
153 return;
154 }
155 wrapped_grpc_timeval *a =
156 PHP_GRPC_GET_WRAPPED_OBJECT(wrapped_grpc_timeval, a_obj);
157 wrapped_grpc_timeval *b =
158 PHP_GRPC_GET_WRAPPED_OBJECT(wrapped_grpc_timeval, b_obj);
159 long result = gpr_time_cmp(a->wrapped, b->wrapped);
160 RETURN_LONG(result);
161 }
162
163 /**
164 * Checks whether the two times are within $threshold of each other
165 * @param Timeval $a_obj The first time to compare
166 * @param Timeval $b_obj The second time to compare
167 * @param Timeval $thresh_obj The threshold to check against
168 * @return bool True if $a and $b are within $threshold, False otherwise
169 */
PHP_METHOD(Timeval,similar)170 PHP_METHOD(Timeval, similar) {
171 zval *a_obj;
172 zval *b_obj;
173 zval *thresh_obj;
174
175 /* "OOO" == 3 Objects */
176 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OOO", &a_obj,
177 grpc_ce_timeval, &b_obj, grpc_ce_timeval,
178 &thresh_obj, grpc_ce_timeval) == FAILURE) {
179 zend_throw_exception(spl_ce_InvalidArgumentException,
180 "compare expects three Timevals", 1 TSRMLS_CC);
181 return;
182 }
183 wrapped_grpc_timeval *a =
184 PHP_GRPC_GET_WRAPPED_OBJECT(wrapped_grpc_timeval, a_obj);
185 wrapped_grpc_timeval *b =
186 PHP_GRPC_GET_WRAPPED_OBJECT(wrapped_grpc_timeval, b_obj);
187 wrapped_grpc_timeval *thresh =
188 PHP_GRPC_GET_WRAPPED_OBJECT(wrapped_grpc_timeval, thresh_obj);
189 int result = gpr_time_similar(a->wrapped, b->wrapped, thresh->wrapped);
190 RETURN_BOOL(result);
191 }
192
193 /**
194 * Returns the current time as a timeval object
195 * @return Timeval The current time
196 */
PHP_METHOD(Timeval,now)197 PHP_METHOD(Timeval, now) {
198 zval *now = grpc_php_wrap_timeval(gpr_now(GPR_CLOCK_REALTIME) TSRMLS_CC);
199 RETURN_DESTROY_ZVAL(now);
200 }
201
202 /**
203 * Returns the zero time interval as a timeval object
204 * @return Timeval Zero length time interval
205 */
PHP_METHOD(Timeval,zero)206 PHP_METHOD(Timeval, zero) {
207 zval *grpc_php_timeval_zero =
208 grpc_php_wrap_timeval(gpr_time_0(GPR_CLOCK_REALTIME) TSRMLS_CC);
209 RETURN_DESTROY_ZVAL(grpc_php_timeval_zero);
210 }
211
212 /**
213 * Returns the infinite future time value as a timeval object
214 * @return Timeval Infinite future time value
215 */
PHP_METHOD(Timeval,infFuture)216 PHP_METHOD(Timeval, infFuture) {
217 zval *grpc_php_timeval_inf_future =
218 grpc_php_wrap_timeval(gpr_inf_future(GPR_CLOCK_REALTIME) TSRMLS_CC);
219 RETURN_DESTROY_ZVAL(grpc_php_timeval_inf_future);
220 }
221
222 /**
223 * Returns the infinite past time value as a timeval object
224 * @return Timeval Infinite past time value
225 */
PHP_METHOD(Timeval,infPast)226 PHP_METHOD(Timeval, infPast) {
227 zval *grpc_php_timeval_inf_past =
228 grpc_php_wrap_timeval(gpr_inf_past(GPR_CLOCK_REALTIME) TSRMLS_CC);
229 RETURN_DESTROY_ZVAL(grpc_php_timeval_inf_past);
230 }
231
232 /**
233 * Sleep until this time, interpreted as an absolute timeout
234 * @return void
235 */
PHP_METHOD(Timeval,sleepUntil)236 PHP_METHOD(Timeval, sleepUntil) {
237 wrapped_grpc_timeval *this =
238 PHP_GRPC_GET_WRAPPED_OBJECT(wrapped_grpc_timeval, getThis());
239 gpr_sleep_until(this->wrapped);
240 }
241
242 ZEND_BEGIN_ARG_INFO_EX(arginfo_construct, 0, 0, 1)
243 ZEND_ARG_INFO(0, microseconds)
244 ZEND_END_ARG_INFO()
245
246 ZEND_BEGIN_ARG_INFO_EX(arginfo_add, 0, 0, 1)
247 ZEND_ARG_INFO(0, timeval)
248 ZEND_END_ARG_INFO()
249
250 ZEND_BEGIN_ARG_INFO_EX(arginfo_compare, 0, 0, 2)
251 ZEND_ARG_INFO(0, a_timeval)
252 ZEND_ARG_INFO(0, b_timeval)
253 ZEND_END_ARG_INFO()
254
255 ZEND_BEGIN_ARG_INFO_EX(arginfo_infFuture, 0, 0, 0)
256 ZEND_END_ARG_INFO()
257
258 ZEND_BEGIN_ARG_INFO_EX(arginfo_infPast, 0, 0, 0)
259 ZEND_END_ARG_INFO()
260
261 ZEND_BEGIN_ARG_INFO_EX(arginfo_now, 0, 0, 0)
262 ZEND_END_ARG_INFO()
263
264 ZEND_BEGIN_ARG_INFO_EX(arginfo_similar, 0, 0, 3)
265 ZEND_ARG_INFO(0, a_timeval)
266 ZEND_ARG_INFO(0, b_timeval)
267 ZEND_ARG_INFO(0, threshold_timeval)
268 ZEND_END_ARG_INFO()
269
270 ZEND_BEGIN_ARG_INFO_EX(arginfo_sleepUntil, 0, 0, 0)
271 ZEND_END_ARG_INFO()
272
273 ZEND_BEGIN_ARG_INFO_EX(arginfo_subtract, 0, 0, 1)
274 ZEND_ARG_INFO(0, timeval)
275 ZEND_END_ARG_INFO()
276
277 ZEND_BEGIN_ARG_INFO_EX(arginfo_zero, 0, 0, 0)
278 ZEND_END_ARG_INFO()
279
280 static zend_function_entry timeval_methods[] = {
281 PHP_ME(Timeval, __construct, arginfo_construct,
282 ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
283 PHP_ME(Timeval, add, arginfo_add,
284 ZEND_ACC_PUBLIC)
285 PHP_ME(Timeval, compare, arginfo_compare,
286 ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
287 PHP_ME(Timeval, infFuture, arginfo_infFuture,
288 ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
289 PHP_ME(Timeval, infPast, arginfo_infPast,
290 ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
291 PHP_ME(Timeval, now, arginfo_now,
292 ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
293 PHP_ME(Timeval, similar, arginfo_similar,
294 ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
295 PHP_ME(Timeval, sleepUntil, arginfo_sleepUntil,
296 ZEND_ACC_PUBLIC)
297 PHP_ME(Timeval, subtract, arginfo_subtract,
298 ZEND_ACC_PUBLIC)
299 PHP_ME(Timeval, zero, arginfo_zero,
300 ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
301 PHP_FE_END
302 };
303
grpc_init_timeval(TSRMLS_D)304 void grpc_init_timeval(TSRMLS_D) {
305 zend_class_entry ce;
306 INIT_CLASS_ENTRY(ce, "Grpc\\Timeval", timeval_methods);
307 ce.create_object = create_wrapped_grpc_timeval;
308 grpc_ce_timeval = zend_register_internal_class(&ce TSRMLS_CC);
309 PHP_GRPC_INIT_HANDLER(wrapped_grpc_timeval, timeval_ce_handlers);
310 }
311
grpc_shutdown_timeval(TSRMLS_D)312 void grpc_shutdown_timeval(TSRMLS_D) {}
313