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