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 */ 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 299 void grpc_shutdown_timeval(TSRMLS_D) {} 300