mt_throws Result
TcpServer::open ()
{
    fd = WSASocket (AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0);
    if (fd == INVALID_SOCKET) {
        exc_throw (WSAException, WSAGetLastError ());
        exc_throw (InternalException, InternalException::BackendError);
        return Result::Failure;
    }

    {
        u_long value = 1;
        int const res = ioctlsocket (fd, FIONBIO, &value);
        if (res != 0) {
            if (res != SOCKET_ERROR) {
                exc_throw (InternalException, InternalException::BackendMalfunction);
                logE_ (_func, "ioctlsocket(): unexpected return value: ", res);
                return Result::Failure;
            }

            int const error = WSAGetLastError ();
            exc_throw (WSAException, error);
            exc_push (InternalException, InternalException::BackendError);
            logE_ (_func, "ioctlsocket() failed: ", wsaErrorToString (error));
            return Result::Failure;
        }
    }

    if (!_libMary_win32_setsockopt_reuseaddr (fd))
        return Result::Failure;

    return Result::Success;
}
Exemple #2
0
static void xxfwrite(FILE * stream, const eu8 * ptr, size_t size) 
{
    size_t n = fwrite(ptr, size, 1, stream);
    if (n == 0) 
    {
        if (ferror(stream))
            exc_throw(MiscError, "fwrite failure:");
        exc_throw(MiscError, "fwrite failure:"); 
    }
}
Exemple #3
0
static eu8 * xxfread(FILE * stream, eu8 * ptr, size_t size) 
{
    size_t n = fread(ptr, size, 1, stream);
    if (n == 0) 
    {
        if (ferror(stream))
            exc_throw(MiscError, "fread failure:");
        exc_throw(EOFIndicator, NULL); }
    return ptr; 
}
mt_throws AsyncIoResult
NativeAsyncFile::write (ConstMemory   const mem,
                        Size        * const ret_nwritten)
{
    if (ret_nwritten)
	*ret_nwritten = 0;

    // According to POSIX, if we pass a value larger than SSIZE_MAX to read,
    // then the result is implementation-defined.
    Size len;
    if (mem.len() > SSIZE_MAX)
	len = SSIZE_MAX;
    else
	len = mem.len();

    ssize_t const res = ::write (fd, mem.mem(), len);

    if (res == -1) {
	if (errno == EAGAIN || errno == EWOULDBLOCK) {
	    requestOutput ();
	    return AsyncIoResult::Again;
	}

	if (errno == EINTR)
	    return AsyncIoResult::Normal;

	if (errno == EPIPE) {
	  // If there'll be a need to distinguish Eof from Error, then this
	  // is the place to intervene.
	    return AsyncIoResult::Error;
	}

	exc_throw (PosixException, errno);
	exc_push_ (IoException);
	return AsyncIoResult::Error;
    } else
    if (res < 0) {
	exc_throw (InternalException, InternalException::BackendMalfunction);
	return AsyncIoResult::Error;
    }

    if ((Size) res > len) {
	exc_throw (InternalException, InternalException::BackendMalfunction);
	return AsyncIoResult::Error;
    }

    if (ret_nwritten)
	*ret_nwritten = res;

    return AsyncIoResult::Normal;
}
Exemple #5
0
mt_throws Result
Thread::spawn (bool const joinable)
{
    this->ref ();

    mutex.lock ();
    GError *error = NULL;
    GThread * const tmp_thread = g_thread_create (wrapperThreadFunc,
						  this,
						  joinable ? TRUE : FALSE,
						  &error);
    this->thread = tmp_thread;
    mutex.unlock ();

    if (tmp_thread == NULL) {
	exc_throw (InternalException, InternalException::BackendError);
	logE_ (_func, "g_thread_create() failed: ",
	       error->message, error->message ? strlen (error->message) : 0);
	g_clear_error (&error);

	this->unref ();

	return Result::Failure;
    }

    return Result::Success;
}
Exemple #6
0
static FILE * xfopen(const char * filename, const char * mode) 
{
    FILE * fh = fopen(filename, mode);
    if (fh == NULL)
        exc_throw(MiscError, "fopen(\"%s\", \"%s\") failure:", filename, mode);
    return fh; 
}
mt_throws AsyncIoResult
NativeAsyncFile::read (Memory   const mem,
                       Size   * const ret_nread)
{
    if (ret_nread)
        *ret_nread = 0;

    // According to POSIX, if we pass a value larger than SSIZE_MAX to read,
    // then the result is implementation-defined.
    Size len;
    if (mem.len() > SSIZE_MAX)
	len = SSIZE_MAX;
    else
	len = mem.len();

    ssize_t const res = ::read (fd, mem.mem(), len);
    if (res == -1) {
	if (errno == EAGAIN || errno == EWOULDBLOCK) {
	    requestInput ();
	    return AsyncIoResult::Again;
	}

	if (errno == EINTR)
	    return AsyncIoResult::Normal;

	exc_throw (PosixException, errno);
	exc_push_ (IoException);
	return AsyncIoResult::Error;
    } else
    if (res < 0) {
	exc_throw (InternalException, InternalException::BackendMalfunction);
	return AsyncIoResult::Error;
    } else
    if (res == 0) {
	return AsyncIoResult::Eof;
    }

    if ((Size) res > len) {
	exc_throw (InternalException, InternalException::BackendMalfunction);
	return AsyncIoResult::Error;
    }

    if (ret_nread)
	*ret_nread = res;

    return AsyncIoResult::Normal;
}
mt_throws Result
PollPollGroup::poll (Uint64 const timeout_microsec)
{
    Time const start_microsec = getTimeMicroseconds ();

    Result ret_res = Result::Success;

    SelectedList selected_list;
    for (;;) {
	selected_list.clear ();

	Count cur_num_pollables = 1;
	struct pollfd pollfds [num_pollables];

	pollfds [0].fd = trigger_pipe [0];
	pollfds [0].events = POLLIN;

	{
	    mutex.lock ();
	    PollableList::iter iter (pollable_list);
	    while (!pollable_list.iter_done (iter)) {
		PollableEntry * const pollable_entry = pollable_list.iter_next (iter);
		selected_list.append (pollable_entry);
		pollfds [cur_num_pollables].fd = pollable_entry->fd;

		pollfds [cur_num_pollables].events =
#ifdef __linux__
			POLLRDHUP;
#else
			0;
#endif

		if (pollable_entry->need_input)
		    pollfds [cur_num_pollables].events |= POLLIN;

		if (pollable_entry->need_output)
		    pollfds [cur_num_pollables].events |= POLLOUT;

		pollable_entry->ref ();
		++cur_num_pollables;
	    }
	    assert (cur_num_pollables == num_pollables + 1);
	    mutex.unlock ();
	}

	Time elapsed_microsec;
	int nfds;
	{
	    Time cur_microsec = getTimeMicroseconds ();
	    if (cur_microsec < start_microsec)
		cur_microsec = start_microsec;

	    elapsed_microsec = cur_microsec - start_microsec;

            int timeout;
            if (!got_deferred_tasks) {
                if (timeout_microsec != (Uint64) -1) {
                    if (timeout_microsec > elapsed_microsec) {
                        Uint64 const tmp_timeout = (timeout_microsec - elapsed_microsec) / 1000;
                        timeout = (int) tmp_timeout;
                        if ((Uint64) timeout != tmp_timeout || timeout < 0)
                            timeout = Int_Max - 1;

                        if (timeout == 0)
                            timeout = 1;
                    } else {
                        timeout = 0;
                    }
                } else {
                    timeout = -1;
                }
            } else {
                timeout = 0;
            }

            mutex.lock ();
            if (triggered || timeout == 0) {
                block_trigger_pipe = true;
                timeout = 0;
            } else {
                block_trigger_pipe = false;
            }
            mutex.unlock ();

	    nfds = ::poll (pollfds, cur_num_pollables, timeout);
	    if (nfds == -1) {
		if (errno == EINTR) {
		    SelectedList::iter iter (selected_list);
		    mutex.lock ();
		    while (!selected_list.iter_done (iter)) {
			PollableEntry * const pollable_entry = selected_list.iter_next (iter);
			pollable_entry->unref ();
		    }
		    mutex.unlock ();

		    // Re-initializing pollfds.
		    continue;
		}

                exc_throw (PosixException, errno);
                exc_push (InternalException, InternalException::BackendError);
                logE_ (_func, "poll() failed: ", errnoString (errno));
                ret_res = Result::Failure;
                goto _poll_interrupted;
	    } else
	    if (nfds < 0) {
		logE_ (_func, "unexpected return value from poll(): ", nfds);
		exc_throw (InternalException, InternalException::BackendMalfunction);
		ret_res = Result::Failure;
		goto _poll_interrupted;
	    }
	}

        mutex.lock ();
        block_trigger_pipe = true;
        bool const was_triggered = triggered;
        triggered = false;
        mutex.unlock ();

        got_deferred_tasks = false;

	if (frontend)
	    frontend.call (frontend->pollIterationBegin);

	bool trigger_pipe_ready = false;
	{
	    if (pollfds [0].revents & (POLLIN | POLLERR | POLLHUP
#ifdef __linux__
			| POLLRDHUP
#endif
			))
		trigger_pipe_ready = true;

	    mutex.lock ();

	    SelectedList::iter iter (selected_list);
	    Count i = 1;
	    while (!selected_list.iter_done (iter)) {
		PollableEntry * const pollable_entry = selected_list.iter_next (iter);

		if (nfds > 0 &&
		    pollable_entry->valid)
		{
		    Uint32 event_flags = 0;

		    if (pollfds [i].revents & POLLNVAL) {
			logW_ (_func, "POLLNVAL for pollable_entry "
			       "0x", fmt_hex, (UintPtr) pollable_entry, ", "
			       "fd ", pollable_entry->fd, " (", pollfds [i].fd, ")");
			++i;
			continue;
		    }

		    if (pollfds [i].revents & POLLIN) {
			pollable_entry->need_input = false;
			event_flags |= PollGroup::Input;
		    }

		    if (pollfds [i].revents & POLLOUT) {
			pollable_entry->need_output = false;
			event_flags |= PollGroup::Output;
		    }

		    if (pollfds [i].revents & POLLHUP
#ifdef __linux__
			|| pollfds [i].revents & POLLRDHUP
#endif
			)
		    {
			event_flags |= PollGroup::Hup;
		    }

		    if (pollfds [i].revents & POLLERR) {
			event_flags |= PollGroup::Error;
		    }

		    if (event_flags) {
			mutex.unlock ();
			pollable_entry->pollable.call (pollable_entry->pollable->processEvents, /*(*/ event_flags /*)*/);
			mutex.lock ();
		    }
		}

		pollable_entry->unref ();
		++i;
	    }
	    assert (i == cur_num_pollables);

	    mutex.unlock ();
	}

	if (frontend) {
	    bool extra_iteration_needed = false;
	    frontend.call_ret (&extra_iteration_needed, frontend->pollIterationEnd);
	    if (extra_iteration_needed)
		got_deferred_tasks = true;
	}

        if (trigger_pipe_ready) {
            if (!commonTriggerPipeRead (trigger_pipe [0])) {
                logF_ (_func, "commonTriggerPipeRead() failed: ", exc->toString());
                return Result::Failure;
            }
            break;
        }

        if (was_triggered)
            break;

	if (elapsed_microsec >= timeout_microsec) {
	  // Timeout expired.
	    break;
	}
    }

    return ret_res;

_poll_interrupted:
    SelectedList::iter iter (selected_list);
    mutex.lock ();
    while (!selected_list.iter_done (iter)) {
	PollableEntry * const pollable_entry = selected_list.iter_next (iter);
	pollable_entry->unref ();
    }
    mutex.unlock ();

    return ret_res;
}
Exemple #9
0
mt_throws Result
loadModule (ConstMemory   const filename,
            void        * const app_specific)
{
  #ifdef LIBMARY_GLIB
    GModule * const module = g_module_open ((gchar const*) makeString (filename)->cstr(),
                                            (GModuleFlags) (G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL));
    if (!module) {
        exc_throw (InternalException, InternalException::BackendError);
        logE_ (_func, "failed to open module ", filename, ": ",  g_module_error());
        return Result::Failure;
    }

    ModuleInitFunc init_ptr;
    if (!g_module_symbol (module, "libMary_moduleInit_wrapper", (gpointer*) &init_ptr)) {
        exc_throw (InternalException, InternalException::BackendError);
        logE_ (_func, "failed to open module ", filename, ": "
               "g_module_symbol (\"libMary_moduleInit_wrapper\") failed: ", g_module_error());
        return Result::Failure;
    }

    if (!init_ptr (app_specific)) {
        logE_ (_func, "could notd initialize module ", filename);
        return Result::Failure;
    }

    return Result::Success;
  #else
    libraryLock ();
    void * const handle = dlopen (
          #ifdef LIBMARY_PLATFORM_MACOSX
            makeString (filename, ".0.dylib")->cstr(),
          #else
            makeString (filename, ".so")->cstr(),
          #endif
            RTLD_LAZY);
    if (!handle) {
        char const * const err_str = dlerror ();
        libraryUnlock ();
        exc_throw (InternalException, InternalException::BackendError);
        logE_ (_func, "dlopen (", filename, ") failed: ", err_str);
        return Result::Failure;
    }

    dlerror (); // Clearing any old error conditions. See man dlsym(3).
    void * const init_ptr = dlsym (handle, "libMary_moduleInit");
    if (!init_ptr) {
        char const * const err_str = dlerror ();
        libraryUnlock ();
        exc_throw (InternalException, InternalException::BackendError);
        logE_ (_func, "dlsym (", filename, ", libMary_moduleInit) failed: ", err_str);
        return Result::Failure;
    }
    libraryUnlock ();

    bool const res = ((ModuleInitFunc) init_ptr) (app_specific);
    if (!res) {
        exc_throw (InternalException, InternalException::BackendError);
        logE_ (_func, "module init failed: ", filename);
    }

    return res ? Result::Success : Result::Failure;
  #endif
}
Exemple #10
0
mt_throws Result updateTime ()
{
    LibMary_ThreadLocal * const tlocal = libMary_getThreadLocal();

#ifdef LIBMARY_PLATFORM_WIN32
    DWORD const win_time_dw = timeGetTime();
    if (tlocal->prv_win_time_dw >= win_time_dw) {
        tlocal->win_time_offs += 0x100000000;
    }
    tlocal->prv_win_time_dw = win_time_dw;
    DWORD const win_time = win_time_dw + tlocal->win_time_offs;

    Time const new_seconds = (Time) win_time / 1000;
    Time const new_microseconds = (Time) win_time * 1000;
#else
  #ifdef __MACH__
    mach_timespec_t mts;
    {
        #warning TODO call host_get_clock_service only once
        clock_serv_t clk;
        host_get_clock_service (mach_host_self(), SYSTEM_CLOCK, &clk);

        clock_get_time (clk, &mts);

        mach_port_deallocate (mach_task_self(), clk);
    }

    Time const new_seconds = mts.tv_sec;
    Time const new_microseconds = (Uint64) mts.tv_sec * 1000000 + (Uint64) mts.tv_nsec / 1000;

#if 0
// Deprecated
    gint64 const mono_time = g_get_monotonic_time ();
    Int64 const mono_time = 0;
    Time const new_seconds = mono_time / 1000000;
    Time const new_microseconds = mono_time;
#endif
  #else
    struct timespec ts;
    // Note that clock_gettime is well-optimized on Linux x86_64 and does not carry
    // full syscall overhead (depends on system configuration).
    int const res = clock_gettime (CLOCK_MONOTONIC, &ts);
    if (res == -1) {
	exc_throw (PosixException, errno);
	exc_push (InternalException, InternalException::BackendError);
	logE_ (_func, "clock_gettime() failed: ", errnoString (errno));
	return Result::Failure;
    } else
    if (res != 0) {
	exc_throw (InternalException, InternalException::BackendError);
	logE_ (_func, "clock_gettime(): unexpected return value: ", res);
	return Result::Failure;
    }

    logD (time, _func, "tv_sec: ", ts.tv_sec, ", tv_nsec: ", ts.tv_nsec);

    Time const new_seconds = ts.tv_sec;
    Time const new_microseconds = (Uint64) ts.tv_sec * 1000000 + (Uint64) ts.tv_nsec / 1000;
  #endif
#endif

    tlocal->time_log_frac = new_microseconds % 1000000 / 100;

    if (new_seconds >= tlocal->time_seconds)
	tlocal->time_seconds = new_seconds;
    else
	logW_ (_func, "seconds backwards: ", new_seconds, " (was ", tlocal->time_seconds, ")");

    if (new_microseconds >= tlocal->time_microseconds)
	tlocal->time_microseconds = new_microseconds;
    else
	logW_ (_func, "microseconds backwards: ", new_microseconds, " (was ", tlocal->time_microseconds, ")");

    logD (time, _func, fmt_hex, tlocal->time_seconds, ", ", tlocal->time_microseconds);

    if (tlocal->saved_monotime < tlocal->time_seconds
        || tlocal->saved_unixtime == 0)
    {
	// Updading saved unixtime once in a minute.
	if (tlocal->time_seconds - tlocal->saved_monotime >= 60
            || tlocal->saved_unixtime == 0)
        {
	    // Obtaining current unixtime. This is an extra syscall.
	    tlocal->saved_unixtime = time (NULL);
	    tlocal->saved_monotime = tlocal->time_seconds;
	}

      // Updating localtime (broken-down time).

	time_t const cur_unixtime = tlocal->saved_unixtime + (tlocal->time_seconds - tlocal->saved_monotime);
	tlocal->unixtime = cur_unixtime;
	// Note that we call tzset() in libMary_posixInit() for localtime_r() to work correctly.
#ifdef LIBMARY_PLATFORM_WIN32
  #ifdef LIBMARY_WIN32_SECURE_CRT
        if (localtime_s (&tlocal->localtime, &cur_unixtime) != 0)
            logF_ (_func, "localtime_s() failed");
  #else
        libraryLock ();
        struct tm * const tmp_localtime = localtime (&cur_unixtime);
        if (tmp_localtime) {
            tlocal->localtime = *tmp_localtime;
        }
        libraryUnlock ();
        if (!tmp_localtime)
            logF_ (_func, "localtime() failed");
  #endif
#else
        // TODO FIXME This lib function is dog-slow and has huge synchronization overhead.
	localtime_r (&cur_unixtime, &tlocal->localtime);
#endif
    }

//    long const timezone_abs = timezone >= 0 ? timezone : -timezone;
    long const timezone_abs = 0;
//    tlocal->timezone_str [0] = timezone >= 0 ? '+' : '-';
    tlocal->timezone_str [0] = '+';
    tlocal->timezone_str [1] = '0' + timezone_abs / 36000;
    tlocal->timezone_str [2] = '0' + timezone_abs /  3600 % 10;
    tlocal->timezone_str [3] = '0' + timezone_abs /   600 %  6;
    tlocal->timezone_str [4] = '0' + timezone_abs /    60 % 10;

    return Result::Success;
}
Exemple #11
0
static void xmkdir(const char * path, int mode) 
{
    if (mkdir(path, mode) < 0)
        exc_throw(MiscError, "mkdir(%s, 0%o) failure:", path, mode);
}
Exemple #12
0
static void xfseek0(FILE * stream, long offset) 
{
    if (fseek(stream, offset, SEEK_SET) < 0)
        exc_throw(MiscError, "fseek(stream, %ld, SEEK_SET) failure:",offset); 
}
mt_throws Result
NativeAsyncFile::open (ConstMemory    const filename,
                       Uint32         const open_flags,
                       FileAccessMode const access_mode)
{
    int flags = 0;
    switch ((FileAccessMode::Value) access_mode) {
	case FileAccessMode::ReadOnly:
	    flags = O_RDONLY;
	    break;
	case FileAccessMode::WriteOnly:
	    flags = O_WRONLY;
	    break;
	case FileAccessMode::ReadWrite:
	    flags = O_RDWR;
	    break;
	default:
	    unreachable ();
    }

    if (open_flags && FileOpenFlags::Create)
	flags |= O_CREAT;

    // TODO Specify behavior for Truncate & O_RDONLY combination.
    if (open_flags & FileOpenFlags::Truncate)
	flags |= O_TRUNC;

    // TODO Seek to the end of file instead. O_APPEND semantics is too complicated.
    if (open_flags & FileOpenFlags::Append)
	flags |= O_APPEND;

    StRef<String> const filename_str = st_grab (new (std::nothrow) String (filename));

    for (;;) {
	/* NOTE: man 2 open does not mention EINTR as a possible return
	 * value, while man 3 open _does_. This means that EINTR should
	 * be handled for all invocations of open() in MyCpp (and all
	 * over MyNC). */
	fd = ::open (filename_str->cstr(),
		     // Note that O_DIRECT affects kernel-level caching/buffering
		     // and should not be set here.
		     flags | O_NONBLOCK,
		     S_IRUSR | S_IWUSR);
	if (fd == -1) {
	    if (errno == EINTR)
		continue;

            if (errno == EAGAIN) {
                logD_ (_func, "EAGAIN");
                break;
            }

            if (errno == EWOULDBLOCK) {
                logD_ (_func, "EWOULDBLOCK");
                break;
            }

	    exc_throw (PosixException, errno);
	    exc_push_ (IoException);
	    return Result::Failure;
	}

	break;
    }

    return Result::Success;
}