Skip to content

Commit 502c89c

Browse files
authored
[k2] implement strtotime (#1318)
This commit also adds __wrap_strdup
1 parent 1f85f0b commit 502c89c

19 files changed

Lines changed: 411 additions & 104 deletions

builtin-functions/kphp-light/stdlib/time-functions.txt

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,23 @@ function mktime ($h ::: int = PHP_INT_MIN, $m ::: int = PHP_INT_MIN, $s ::: int
77

88
function date ($format ::: string, $timestamp ::: int = PHP_INT_MIN) ::: string;
99

10+
function date_default_timezone_get() ::: string;
11+
1012
function date_default_timezone_set ($s ::: string) ::: bool;
1113

1214
function gmdate ($format ::: string, $timestamp ::: int = PHP_INT_MIN) ::: string;
1315

1416
function time() ::: int;
1517

18+
function strtotime ($time ::: string, $timestamp ::: int = PHP_INT_MIN) ::: int | false;
19+
1620
function microtime ($get_as_float ::: bool = false) ::: mixed;
1721

1822
function hrtime (bool $as_number = false): mixed; // int[]|int
1923

2024
/** @kphp-extern-func-info interruptible */
2125
function set_timer(int $timeout, callable():void $callback) ::: void;
2226

23-
2427
// ===== UNSUPPORTED =====
2528

2629
/** @kphp-generate-stub-class */
@@ -167,8 +170,6 @@ define('DATE_RFC3339', "Y-m-d\TH:i:sP");
167170
define('DATE_RSS', "D, d M Y H:i:s O");
168171
define('DATE_W3C', "Y-m-d\TH:i:sP");
169172

170-
/** @kphp-extern-func-info stub generation-required */
171-
function date_default_timezone_get() ::: string;
172173
/** @kphp-extern-func-info stub generation-required */
173174
function getdate ($timestamp ::: int = PHP_INT_MIN) ::: mixed[];
174175
/** @kphp-extern-func-info stub generation-required */
@@ -178,9 +179,6 @@ function gmmktime ($h ::: int = PHP_INT_MIN, $m ::: int = PHP_INT_MIN, $s ::: in
178179
function localtime ($timestamp ::: int = PHP_INT_MIN, $is_associative ::: bool = false) ::: mixed[];
179180
/** @kphp-extern-func-info stub generation-required */
180181
function strftime ($format ::: string, $timestamp ::: int = PHP_INT_MIN) ::: string;
181-
/** @kphp-extern-func-info stub generation-required */
182-
function strtotime ($time ::: string, $timestamp ::: int = PHP_INT_MIN) ::: int | false;
183-
184182

185183
/** @kphp-extern-func-info stub generation-required */
186184
function checkdate ($month ::: int, $day ::: int, $year ::: int) ::: bool;

compiler/make/objs-to-k2-component-target.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class Objs2K2ComponentTarget : public Target {
3636
#if defined(__APPLE__)
3737
return " -Wl,-undefined,dynamic_lookup ";
3838
#else
39-
return " -Wl,--wrap,malloc -Wl,--wrap,free, -Wl,--wrap,calloc -Wl,--wrap,realloc -static-libgcc ";
39+
return " -Wl,--wrap,malloc -Wl,--wrap,free, -Wl,--wrap,calloc -Wl,--wrap,realloc -Wl,--wrap,strdup -static-libgcc ";
4040
#endif
4141
}
4242

runtime-light/allocator-wrapper/libc-alloc-wrapper.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// Distributed under the GPL v3 License, see LICENSE.notice.txt
44

55
#include <cstddef>
6+
#include <cstring>
67

78
#include "runtime-common/core/allocator/script-malloc-interface.h"
89
#include "runtime-light/allocator/allocator-state.h"
@@ -29,9 +30,17 @@ extern "C" void* __wrap_calloc(size_t nmemb, size_t size) noexcept {
2930
return kphp::memory::script::calloc(nmemb, size);
3031
}
3132

32-
extern "C" void* __wrap_realloc([[maybe_unused]] void* ptr, [[maybe_unused]] size_t size) noexcept {
33+
extern "C" void* __wrap_realloc(void* ptr, size_t size) noexcept {
3334
if (!AllocatorState::get().libc_alloc_allowed()) [[unlikely]] {
3435
kphp::log::error("unexpected use of realloc");
3536
}
3637
return kphp::memory::script::realloc(ptr, size);
3738
}
39+
40+
extern "C" char* __wrap_strdup(const char* str1) noexcept {
41+
if (!AllocatorState::get().libc_alloc_allowed()) [[unlikely]] {
42+
kphp::log::error("unexpected use of strdup");
43+
}
44+
auto* str2{static_cast<char*>(kphp::memory::script::alloc(std::strlen(str1) + 1))};
45+
return std::strcpy(str2, str1);
46+
}

runtime-light/k2-platform/k2-api.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
#include <cerrno>
88
#include <cstddef>
99
#include <cstdint>
10+
#include <ctime>
1011
#include <memory>
12+
#include <string_view>
1113
#include <sys/utsname.h>
1214
#include <utility>
1315

@@ -204,6 +206,14 @@ inline auto env_fetch(uint32_t arg_num) noexcept {
204206
std::unique_ptr<char, decltype(std::addressof(k2::free))>{value_buffer, k2::free});
205207
}
206208

209+
inline int32_t set_timezone(std::string_view timezone) noexcept {
210+
return k2_set_timezone(timezone.data());
211+
}
212+
213+
inline struct tm* localtime_r(const time_t* timer, struct tm* result) noexcept {
214+
return k2_localtime_r(timer, result);
215+
}
216+
207217
inline int32_t udp_connect(uint64_t* socket_d, const char* host, size_t host_len) noexcept {
208218
return k2_udp_connect(socket_d, host, host_len);
209219
}

runtime-light/runtime-light.cmake

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
include(${THIRD_PARTY_DIR}/timelib-cmake/timelib.cmake)
12
include(${THIRD_PARTY_DIR}/pcre2-cmake/pcre2.cmake)
23

34
# =================================================================================================
@@ -54,9 +55,9 @@ vk_add_library_pic(runtime-light-pic OBJECT ${RUNTIME_LIGHT_SRC})
5455
target_compile_options(runtime-light-pic PUBLIC ${RUNTIME_LIGHT_COMPILE_FLAGS})
5556
target_link_libraries(runtime-light-pic PUBLIC vk::pic::libc-alloc-wrapper) # it's mandatory to have alloc-wrapper first in the list of link libraries since we
5657
# want to use its symbols in all other libraries
57-
target_link_libraries(runtime-light-pic PUBLIC PCRE2::pic::pcre2 ZLIB::pic::zlib) # third parties
58+
target_link_libraries(runtime-light-pic PUBLIC KPHP_TIMELIB::pic::timelib PCRE2::pic::pcre2 ZLIB::pic::zlib) # third parties
5859

59-
set(RUNTIME_LIGHT_LINK_LIBS "${PCRE2_PIC_LIBRARIES} ${ZLIB_PIC_LIBRARIES}")
60+
set(RUNTIME_LIGHT_LINK_LIBS "${KPHP_TIMELIB_PIC_LIBRARIES} ${PCRE2_PIC_LIBRARIES} ${ZLIB_PIC_LIBRARIES}")
6061

6162
# =================================================================================================
6263

runtime-light/runtime-light.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ ImageState* k2_create_image() {
1616
auto* image_state_ptr{static_cast<ImageState*>(k2::alloc(sizeof(ImageState)))};
1717
if (image_state_ptr == nullptr) [[unlikely]] {
1818
kphp::log::error("can't allocate enough memory for image state");
19-
return nullptr;
2019
}
2120
kphp::log::debug("finish image state creation");
2221
return image_state_ptr;
@@ -34,7 +33,6 @@ ComponentState* k2_create_component() {
3433
auto* component_state_ptr{static_cast<ComponentState*>(k2::alloc(sizeof(ComponentState)))};
3534
if (component_state_ptr == nullptr) [[unlikely]] {
3635
kphp::log::error("can't allocate enough memory for component state");
37-
return nullptr;
3836
}
3937
kphp::log::debug("finish component state creation");
4038
return component_state_ptr;
@@ -51,7 +49,6 @@ InstanceState* k2_create_instance() {
5149
auto* instance_state_ptr{static_cast<InstanceState*>(k2::alloc(sizeof(InstanceState)))};
5250
if (instance_state_ptr == nullptr) [[unlikely]] {
5351
kphp::log::error("can't allocate enough memory for instance state");
54-
return nullptr;
5552
}
5653
kphp::log::debug("finish instance state creation");
5754
return instance_state_ptr;

runtime-light/state/image-state.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@
1717
#include "runtime-light/stdlib/math/math-state.h"
1818
#include "runtime-light/stdlib/rpc/rpc-client-state.h"
1919
#include "runtime-light/stdlib/string/string-state.h"
20+
#include "runtime-light/stdlib/time/time-state.h"
2021
#include "runtime-light/stdlib/visitors/shape-visitors.h"
2122
#include "runtime-light/utils/logs.h"
2223

2324
struct ImageState final : private vk::not_copyable {
2425
AllocatorState image_allocator_state{INIT_IMAGE_ALLOCATOR_SIZE, 0};
2526

26-
char* c_linear_mem{nullptr};
2727
uint32_t pid{k2::getpid()};
2828
string uname_info_s;
2929
string uname_info_n;
@@ -34,9 +34,10 @@ struct ImageState final : private vk::not_copyable {
3434

3535
ShapeKeyDemangle shape_key_demangler;
3636

37-
RpcImageState rpc_image_state;
3837
StringImageState string_image_state;
38+
TimeImageState time_image_state;
3939
MathImageState math_image_state;
40+
RpcImageState rpc_image_state;
4041

4142
ImageState() noexcept {
4243
utsname uname_info{};

runtime-light/state/instance-state.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "runtime-light/stdlib/string/regex-state.h"
3636
#include "runtime-light/stdlib/string/string-state.h"
3737
#include "runtime-light/stdlib/system/system-state.h"
38+
#include "runtime-light/stdlib/time/time-state.h"
3839

3940
// Coroutine scheduler type. Change it here if you want to use another scheduler
4041
using CoroutineScheduler = SimpleCoroutineScheduler;
@@ -61,10 +62,7 @@ struct InstanceState final : vk::not_copyable {
6162
template<typename T>
6263
using list = kphp::stl::list<T, kphp::memory::script_allocator>;
6364

64-
InstanceState() noexcept
65-
: instance_allocator_state(INIT_INSTANCE_ALLOCATOR_SIZE, 0) {}
66-
67-
~InstanceState() = default;
65+
InstanceState() noexcept = default;
6866

6967
static InstanceState& get() noexcept {
7068
return *k2::instance_state();
@@ -106,7 +104,7 @@ struct InstanceState final : vk::not_copyable {
106104
void release_stream(uint64_t) noexcept;
107105
void release_all_streams() noexcept;
108106

109-
AllocatorState instance_allocator_state;
107+
AllocatorState instance_allocator_state{INIT_INSTANCE_ALLOCATOR_SIZE, 0};
110108

111109
CoroutineScheduler scheduler;
112110
ForkInstanceState fork_instance_state;
@@ -124,6 +122,7 @@ struct InstanceState final : vk::not_copyable {
124122
JobWorkerServerInstanceState job_worker_server_instance_state;
125123
InstanceCacheInstanceState instance_cache_instance_state;
126124

125+
TimeInstanceState time_instance_state;
127126
MathInstanceState math_instance_state;
128127
RandomInstanceState random_instance_state;
129128
RegexInstanceState regex_instance_state;

runtime-light/stdlib/stdlib.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,6 @@ prepend(
3434
file/file-system-state.cpp
3535
file/resource.cpp
3636
time/time-functions.cpp
37+
time/time-state.cpp
38+
time/timelib-functions.cpp
3739
zlib/zlib-functions.cpp)

runtime-light/stdlib/time/time-functions.cpp

Lines changed: 20 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@
77
#include <array>
88
#include <chrono>
99
#include <climits>
10+
#include <cstdint>
1011
#include <ctime>
1112
#include <string_view>
1213

13-
#include "runtime-light/utils/logs.h"
14+
#include "runtime-common/core/runtime-core.h"
15+
#include "runtime-light/stdlib/time/timelib-constants.h"
1416

1517
namespace {
16-
constexpr std::string_view PHP_TIMELIB_TZ_MOSCOW = "Europe/Moscow";
17-
constexpr std::string_view PHP_TIMELIB_TZ_GMT3 = "Etc/GMT-3";
1818

1919
constexpr std::array<std::string_view, 12> PHP_TIMELIB_MON_FULL_NAMES = {"January", "February", "March", "April", "May", "June",
2020
"July", "August", "September", "October", "November", "December"};
@@ -65,6 +65,21 @@ void iso_week_number(int y, int doy, int weekday, int& iw, int& iy) noexcept {
6565
}
6666
}
6767

68+
} // namespace
69+
70+
namespace kphp::time::impl {
71+
72+
int64_t fix_year(int64_t year) noexcept {
73+
if (year <= 100U) {
74+
if (year <= 69) {
75+
year += 2000;
76+
} else {
77+
year += 1900;
78+
}
79+
}
80+
return year;
81+
}
82+
6883
string date(const string& format, const tm& t, int64_t timestamp, bool local) noexcept {
6984
string_buffer& SB{RuntimeContext::get().static_SB};
7085

@@ -196,7 +211,7 @@ string date(const string& format, const tm& t, int64_t timestamp, bool local) no
196211
break;
197212
case 'e':
198213
if (local) {
199-
SB << PHP_TIMELIB_TZ_MOSCOW.data();
214+
SB << kphp::timelib::timezones::MOSCOW.data();
200215
} else {
201216
SB << "UTC";
202217
}
@@ -294,59 +309,4 @@ string date(const string& format, const tm& t, int64_t timestamp, bool local) no
294309
return SB.str();
295310
}
296311

297-
int64_t fix_year(int64_t year) noexcept {
298-
if (year <= 100U) {
299-
if (year <= 69) {
300-
year += 2000;
301-
} else {
302-
year += 1900;
303-
}
304-
}
305-
return year;
306-
}
307-
308-
} // namespace
309-
310-
int64_t f$mktime(Optional<int64_t> hour, Optional<int64_t> minute, Optional<int64_t> second, Optional<int64_t> month, Optional<int64_t> day,
311-
Optional<int64_t> year) noexcept {
312-
namespace chrono = std::chrono;
313-
const auto time_since_epoch{chrono::system_clock::now().time_since_epoch()};
314-
chrono::year_month_day current_date{chrono::sys_days{duration_cast<chrono::days>(time_since_epoch)}};
315-
316-
const auto hours{chrono::hours(hour.has_value() ? hour.val() : duration_cast<chrono::hours>(time_since_epoch).count() % 24)};
317-
const auto minutes{chrono::minutes(minute.has_value() ? minute.val() : duration_cast<chrono::minutes>(time_since_epoch).count() % 60)};
318-
const auto seconds{chrono::seconds(second.has_value() ? second.val() : duration_cast<chrono::seconds>(time_since_epoch).count() % 60)};
319-
const auto months{chrono::months(month.has_value() ? month.val() : static_cast<unsigned>(current_date.month()))};
320-
const auto days{chrono::days(day.has_value() ? day.val() : static_cast<unsigned>(current_date.day()))};
321-
const auto years{chrono::years(year.has_value() ? fix_year(year.val()) : static_cast<int>(current_date.year()) - 1970)};
322-
323-
const auto result{hours + minutes + seconds + months + days + years};
324-
return duration_cast<chrono::seconds>(result).count();
325-
}
326-
327-
string f$gmdate(const string& format, Optional<int64_t> timestamp) noexcept {
328-
namespace chrono = std::chrono;
329-
330-
const time_t now{timestamp.has_value() ? timestamp.val() : duration_cast<chrono::seconds>(chrono::system_clock::now().time_since_epoch()).count()};
331-
struct tm tm {};
332-
gmtime_r(&now, &tm);
333-
return date(format, tm, now, false);
334-
}
335-
336-
string f$date(const string& format, Optional<int64_t> timestamp) noexcept {
337-
namespace chrono = std::chrono;
338-
339-
const time_t now{timestamp.has_value() ? timestamp.val() : duration_cast<chrono::seconds>(chrono::system_clock::now().time_since_epoch()).count()};
340-
struct tm tm {};
341-
localtime_r(&now, &tm);
342-
return date(format, tm, now, true);
343-
}
344-
345-
bool f$date_default_timezone_set(const string& s) noexcept {
346-
const std::string_view timezone_view{s.c_str(), s.size()};
347-
if (timezone_view != PHP_TIMELIB_TZ_GMT3 && timezone_view != PHP_TIMELIB_TZ_MOSCOW) {
348-
kphp::log::warning("unsupported default timezone '{}'", s.c_str());
349-
return false;
350-
}
351-
return true;
352-
}
312+
} // namespace kphp::time::impl

0 commit comments

Comments
 (0)