PONY_API char* ponyint_formattime(date_t* date, const char* fmt) { pony_ctx_t* ctx = pony_ctx(); char* buffer; // Bail out on strftime formats that can produce a zero-length string. if((fmt[0] == '\0') || !strcmp(fmt, "%p") || !strcmp(fmt, "%P")) { buffer = (char*)pony_alloc(ctx, 1); buffer[0] = '\0'; return buffer; } struct tm tm; date_to_tm(date, &tm); size_t len = 64; size_t r = 0; while(r == 0) { buffer = (char*)pony_alloc(ctx, len); r = strftime(buffer, len, fmt, &tm); len <<= 1; } return buffer; }
PONY_API asio_event_t* pony_asio_event_create(pony_actor_t* owner, int fd, uint32_t flags, uint64_t nsec, bool noisy) { if((flags == ASIO_DISPOSABLE) || (flags == ASIO_DESTROYED)) return NULL; pony_type_t* type = *(pony_type_t**)owner; uint32_t msg_id = type->event_notify; if(msg_id == (uint32_t)-1) return NULL; asio_event_t* ev = POOL_ALLOC(asio_event_t); ev->magic = ev; ev->owner = owner; ev->msg_id = msg_id; ev->fd = fd; ev->flags = flags; ev->noisy = noisy; ev->nsec = nsec; ev->writeable = false; ev->readable = false; // The event is effectively being sent to another thread, so mark it here. pony_ctx_t* ctx = pony_ctx(); pony_gc_send(ctx); pony_traceknown(ctx, owner, type, PONY_TRACE_OPAQUE); pony_send_done(ctx); pony_asio_event_subscribe(ev); return ev; }
PONY_EXTERN_C_BEGIN char* pony_os_realpath(const char* path) { #ifdef PLATFORM_IS_WINDOWS char resolved[FILENAME_MAX]; if(GetFullPathName(path, FILENAME_MAX, resolved, NULL) == 0 || GetFileAttributes(resolved) == INVALID_FILE_ATTRIBUTES) return NULL; #elif defined(PLATFORM_IS_POSIX_BASED) char resolved[PATH_MAX]; if(realpath(path, resolved) == NULL) return NULL; #endif size_t len = strlen(resolved) + 1; #ifdef PLATFORM_IS_WINDOWS for(; resolved[len - 1] == '\\'; --len) resolved[len - 1] = '\0'; #endif char* cstring = (char*)pony_alloc(pony_ctx(), len); memcpy(cstring, resolved, len); return cstring; }
pony_ctx_t* ponyint_sched_init(uint32_t threads, bool noyield, bool nopin, bool pinasio) { pony_register_thread(); use_yield = !noyield; // If no thread count is specified, use the available physical core count. if(threads == 0) threads = ponyint_cpu_count(); scheduler_count = threads; scheduler = (scheduler_t*)ponyint_pool_alloc_size( scheduler_count * sizeof(scheduler_t)); memset(scheduler, 0, scheduler_count * sizeof(scheduler_t)); uint32_t asio_cpu = ponyint_cpu_assign(scheduler_count, scheduler, nopin, pinasio); for(uint32_t i = 0; i < scheduler_count; i++) { scheduler[i].ctx.scheduler = &scheduler[i]; scheduler[i].last_victim = &scheduler[i]; ponyint_messageq_init(&scheduler[i].mq); ponyint_mpmcq_init(&scheduler[i].q); } ponyint_mpmcq_init(&inject); ponyint_asio_init(asio_cpu); return pony_ctx(); }
void asio_event_send(asio_event_t* ev, uint32_t flags, uint32_t arg) { asio_msg_t* m = (asio_msg_t*)pony_alloc_msg(POOL_INDEX(sizeof(asio_msg_t)), ev->msg_id); m->event = ev; m->flags = flags; m->arg = arg; #ifdef PLATFORM_IS_WINDOWS // On Windows, this can be called from an IOCP callback thread, which may // not have a pony_ctx() associated with it yet. pony_register_thread(); #endif pony_sendv(pony_ctx(), ev->owner, &m->msg); }
PONY_API void pony_asio_event_destroy(asio_event_t* ev) { if((ev == NULL) || (ev->magic != ev) || (ev->flags != ASIO_DISPOSABLE)) { pony_assert(0); return; } ev->flags = ASIO_DESTROYED; // When we let go of an event, we treat it as if we had received it back from // the asio thread. pony_ctx_t* ctx = pony_ctx(); pony_gc_recv(ctx); pony_traceunknown(ctx, ev->owner, PONY_TRACE_OPAQUE); pony_recv_done(ctx); POOL_FREE(asio_event_t, ev); }