+
+
+all:
+ npm build .
+
+clean:
+ rm -rf ./build
+
+.PHONY: all clean
\ No newline at end of file
'targets': [
{
'target_name' : 'ejdb_native',
- 'sources' : ['ejdb_native.cc'],
+ 'sources' : [
+ 'ejdb_native.cc',
+ 'ejdb_logging.cc'
+ ],
'include_dirs': ['../tcejdb'],
'libraries' : [
'-L../../tcejdb',
'-lbz2 -lz -lrt -lpthread -lm -lc'
],
'cflags': [
+ '-g',
+ '-O0',
'-fPIC',
+ '-D_GNU_SOURCE',
'-D_FILE_OFFSET_BITS=64',
'-D_LARGEFILE_SOURCE'
- ]
+ ],
+ 'cflags!': [ '-fno-exceptions' ],
+ 'cflags_cc!': [ '-fno-exceptions' ]
}
]
}
\ No newline at end of file
--- /dev/null
+/*
+ * File: node_args.h
+ * Author: adam
+ *
+ * Created on October 30, 2012, 10:37 AM
+ */
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#ifndef EJDB_ARGS_H
+#define EJDB_ARGS_H
+
+#include <v8.h>
+#include <node.h>
+
+
+#define REQ_ARGS(N) \
+ if (args.Length() < (N)) \
+ return ThrowException(Exception::TypeError( \
+ String::New("Expected " #N " arguments")));
+
+#define REQ_STR_ARG(I, VAR) \
+ if (args.Length() <= (I) || !args[I]->IsString()) \
+ return ThrowException(Exception::TypeError( \
+ String::New("Argument " #I " must be a string"))); \
+ String::Utf8Value VAR(args[I]->ToString());
+
+#define REQ_STRW_ARG(I, VAR) \
+ if (args.Length() <= (I) || !args[I]->IsString()) \
+ return ThrowException(Exception::TypeError( \
+ String::New("Argument " #I " must be a string"))); \
+ String::Value VAR(args[I]->ToString());
+
+
+#define REQ_FUN_ARG(I, VAR) \
+ if (args.Length() <= (I) || !args[I]->IsFunction()) \
+ return ThrowException(Exception::TypeError( \
+ String::New("Argument " #I " must be a function"))); \
+ Local<Function> VAR = Local<Function>::Cast(args[I]);
+
+#define REQ_OBJ_ARG(I, VAR) \
+ if (args.Length() <= (I) || !args[I]->IsObject()) \
+ return ThrowException(Exception::TypeError( \
+ String::New("Argument " #I " must be a object"))); \
+ Local<Object> VAR = Local<Object>::Cast(args[I]);
+
+#define REQ_VAL_ARG(I, VAR) \
+ if (args.Length() <= (I)) \
+ return ThrowException(Exception::TypeError( \
+ String::New("Argument " #I " must be a provided"))); \
+ Local<Value> VAR = args[I];
+
+
+#define REQ_ARR_ARG(I, VAR) \
+ if (args.Length() <= (I) || !args[I]->IsArray()) \
+ return ThrowException(Exception::TypeError( \
+ String::New("Argument " #I " must be an array"))); \
+ Local<Array> VAR = Local<Array>::Cast(args[I]);
+
+
+#define REQ_EXT_ARG(I, VAR) \
+ if (args.Length() <= (I) || !args[I]->IsExternal()) \
+ return ThrowException(Exception::TypeError( \
+ String::New("Argument " #I " invalid"))); \
+ Local<External> VAR = Local<External>::Cast(args[I]);
+
+#define OPT_INT_ARG(I, VAR, DEFAULT) \
+ int VAR; \
+ if (args.Length() <= (I)) { \
+ VAR = (DEFAULT); \
+ } else if (args[I]->IsInt32()) { \
+ VAR = args[I]->Int32Value(); \
+ } else { \
+ return ThrowException(Exception::TypeError( \
+ String::New("Argument " #I " must be an integer"))); \
+ }
+
+#define REQ_INT32_ARG(I, VAR) \
+ if (args.Length() <= (I) || !args[I]->IsInt32()) \
+ return ThrowException(Exception::TypeError( \
+ String::New("Argument " #I " must be an integer"))); \
+ int32_t VAR = args[I]->Int32Value();
+
+
+#define REQ_INT64_ARG(I, VAR) \
+ if (args.Length() <= (I) || !args[I]->IsNumber()) \
+ return ThrowException(Exception::TypeError( \
+ String::New("Argument " #I " must be an number"))); \
+ int64_t VAR = args[I]->IntegerValue();
+
+
+
+#define REQ_NUM_ARG(I, VAR) \
+ if (args.Length() <= (I) || !args[I]->IsNumber()) \
+ return ThrowException(Exception::TypeError( \
+ String::New("Argument " #I " must be an number"))); \
+ double VAR = args[I]->ToNumber()->Value();
+
+
+#define REQ_BUFF_ARG(I, VAR) \
+ if (!Buffer::HasInstance(args[I])) { \
+ return ThrowException(Exception::Error( \
+ String::New("Argument " #I " must to be a buffer"))); \
+ } \
+ Buffer* VAR = ObjectWrap::Unwrap<Buffer>(args[I]->ToObject());
+
+
+#endif /* EJDB_ARGS_H */
+
--- /dev/null
+/*
+ * File: ejdb_cmd.h
+ * Author: adam
+ *
+ * Created on October 30, 2012, 11:41 AM
+ */
+
+#ifndef EJDB_CMD_H
+#define EJDB_CMD_H
+
+#include <uv.h>
+#include <v8.h>
+#include <string>
+
+
+namespace ejdb {
+
+ template < typename T, typename D = void > class EIOCmdTask {
+ public:
+
+ //uv request
+ uv_work_t uv_work;
+
+ v8::Persistent<v8::Function> cb;
+ T* wrapped;
+
+ //cmd spec
+ int cmd;
+ D* cmd_data;
+
+ //cmd return data
+ int cmd_ret;
+ int cmd_ret_data_length;
+ std::string cmd_ret_msg;
+
+ //entity type
+ int entity;
+
+ //Pointer to free_cmd_data function
+ void (*free_cmd_data)(EIOCmdTask<T, D>*);
+
+
+ public:
+
+ static void free_val(EIOCmdTask<T, D>* dtask) {
+ if (dtask->cmd_data) {
+ free(dtask->cmd_data);
+ dtask->cmd_data = NULL;
+ }
+ }
+
+ static void delete_val(EIOCmdTask<T, D>* dtask) {
+ if (dtask->cmd_data) {
+ delete dtask->cmd_data;
+ dtask->cmd_data = NULL;
+ }
+ }
+
+ public:
+
+ EIOCmdTask(const v8::Handle<v8::Function>& _cb, T* _wrapped, int _cmd,
+ D* _cmd_data, void (*_free_cmd_data)(EIOCmdTask<T, D>*)) :
+ wrapped(_wrapped), cmd(_cmd), cmd_data(_cmd_data), cmd_ret(0), cmd_ret_data_length(0), entity(0) {
+
+ this->free_cmd_data = _free_cmd_data;
+ this->cb = v8::Persistent<v8::Function>::New(_cb);
+ this->wrapped->Ref();
+ this->uv_work.data = this;
+ }
+
+ virtual ~EIOCmdTask() {
+ this->cb.Dispose();
+ this->wrapped->Unref();
+ if (this->free_cmd_data) {
+ this->free_cmd_data(this);
+ }
+ }
+ };
+}
+
+
+
+
+
+
+
+
+#endif /* EJDB_CMD_H */
+
--- /dev/null
+#include "ejdb_logging.h"
+#include "ejdb_thread.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+
+#ifdef _WIN32
+#include <io.h>
+static void __flockfile(FILE *stream) {
+ HANDLE hf;
+ int fd;
+ LARGE_INTEGER li;
+ fd = _fileno(stream);
+ hf = (HANDLE) _get_osfhandle(fd);
+ li.QuadPart = _filelengthi64(fd);
+ LockFile(hf, 0, 0, li.LowPart, li.HighPart);
+}
+
+static void __funlockfile(FILE *stream) {
+ HANDLE hf;
+ int fd;
+ LARGE_INTEGER li;
+ fd = _fileno(stream);
+ hf = (HANDLE) _get_osfhandle(fd);
+ li.QuadPart = _filelengthi64(fd);
+ UnlockFile(hf, 0, 0, li.LowPart, li.HighPart);
+}
+#endif
+#ifdef __unix
+
+static void __flockfile(FILE *stream) {
+ flockfile(stream);
+}
+
+static void __funlockfile(FILE *stream) {
+ funlockfile(stream);
+}
+#endif
+
+namespace ejdb {
+
+ EJMutex g_outputMtx;
+
+ const char* ej_errno_msg(int errno_rv) {
+ return strerror(errno_rv);
+ }
+
+ void ej_log_intern(int priority, const char* file, int line, const char* fmt, ...) {
+#ifndef _DEBUG
+ if (priority == LOG_DEBUG) {
+ return;
+ }
+#endif
+ //Timestamp
+ char tbuff[64];
+ time_t rawtime;
+ struct tm* timeinfo;
+ time(&rawtime);
+ timeinfo = localtime(&rawtime);
+ strftime(tbuff, 64, "%d %b %H:%M:%S -", timeinfo);
+
+ __flockfile(stderr);
+ __flockfile(stdout);
+ try {
+ switch (priority) {
+ case LOG_ERROR:
+ if (file && line > 0) {
+ fprintf(stderr, "%s ERROR %s:%d ", tbuff, file, line);
+ } else {
+ fprintf(stderr, "%s ERROR ", tbuff);
+ }
+ break;
+ case LOG_DEBUG:
+ if (file && line > 0) {
+ fprintf(stderr, "%s DEBUG %s:%d ", tbuff, file, line);
+ } else {
+ fprintf(stderr, "%s DEBUG ", tbuff);
+ }
+ break;
+ case LOG_INFO:
+ if (file && line > 0) {
+ fprintf(stderr, "%s INFO %s:%d ", tbuff, file, line);
+ } else {
+ fprintf(stderr, "%s INFO ", tbuff);
+ }
+ break;
+ case LOG_WARNING:
+ if (file && line > 0) {
+ fprintf(stderr, "%s WARN %s:%d ", tbuff, file, line);
+ } else {
+ fprintf(stderr, "%s WARN ", tbuff);
+ }
+ break;
+ default:
+ if (file && line > 0) {
+ fprintf(stderr, "%s %s:%d ", tbuff, file, line);
+ } else {
+ fprintf(stderr, "%s ", tbuff);
+ }
+ }
+ va_list vl;
+ va_start(vl, fmt);
+ vfprintf(stderr, fmt, vl);
+ va_end(vl);
+ fprintf(stderr, "\n");
+ } catch (...) {
+ __funlockfile(stderr);
+ __funlockfile(stdout);
+ throw;
+ }
+ __funlockfile(stderr);
+ __funlockfile(stdout);
+ }
+
+ void ej_log_errno_status(const char* file, int line, int errno_rv, const std::string& msg) {
+ ej_log_errno_status(file, line, errno_rv, msg.c_str());
+ }
+
+ void ej_log_errno_status(const char* file, int line, int errno_rv, const char* msg) {
+ if (msg) {
+ ej_log_intern(LOG_WARNING, file, line, "%s, %s", msg, strerror(errno_rv));
+ } else {
+ ej_log_intern(LOG_WARNING, file, line, "%s", strerror(errno_rv));
+ }
+ }
+
+ void ej_log_ejerror(const char* file, int line, const EJError& err) {
+ ej_log_errno_status(file, line, err.errno_code, err.msg);
+ }
+
+ void EJError::errPrint() {
+ ej_log_intern(LOG_ERROR, this->location.c_str(), this->line, "%s, %s",
+ this->msg.c_str(),
+ strerror(this->errno_code));
+ }
+
+} //eof ejdb namespace
+
+
+
+
--- /dev/null
+/*
+ * File: ejdb_logging.h
+ * Author: adam
+ *
+ * Created on October 30, 2012, 12:15 PM
+ */
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+
+#ifndef EJDB_LOGGING_H
+#define EJDB_LOGGING_H
+
+#include <string>
+
+namespace ejdb {
+
+ class EJError;
+
+ //No throw exception
+#define EJ_NO_THROW throw()
+#define EJ_THROW(E) throw(E)
+#define EJ_THROW_ERR throw(ejdb::EJError)
+
+ //Logging
+#define LOG_ERROR 1
+#define LOG_WARNING 2
+#define LOG_INFO 3
+#define LOG_DEBUG 4
+
+
+#define EJ_LOG_EJERROR(err) ejdb::ej_log_mherror(__FILE__, __LINE__, err)
+#define EJ_ERRNO_THROW(errno_rv, msg) throw ejdb::EJError(msg, errno_rv, __FILE__, __LINE__)
+#define EJ_LOG_ERRNO_THROW(errno_rv, msg) ejdb::ej_log_errno_status(__FILE__, __LINE__, errno_rv, msg); throw ejdb::MHError(msg, errno_rv, __FILE__, __LINE__)
+#define EJ_LOG_ERRNO_STATUS(errno_rv, msg) ejdb::ej_log_errno_status(__FILE__, __LINE__, errno_rv, msg)
+
+#define EJ_LOG_ERROR(fmt,...) ej_log_intern(LOG_ERROR, __FILE__, __LINE__, fmt,##__VA_ARGS__)
+#define EJ_LOG_WARN(fmt,...) ej_log_intern(LOG_WARNING, __FILE__, __LINE__, fmt,##__VA_ARGS__)
+#define EJ_LOG_INFO(fmt,...) ej_log_intern(LOG_INFO, __FILE__, __LINE__, fmt,##__VA_ARGS__)
+
+#ifdef _DEBUG
+#define EJ_LOG_DBG(fmt, ...) ej_log_intern(LOG_DEBUG, __FILE__, __LINE__, fmt,##__VA_ARGS__)
+#else
+#define EJ_LOG_DBG(fmt, ...)
+#endif
+
+ void ej_log_intern(int priority, const char* file, int line, const char* fmt, ...);
+ void ej_log_ejerror(const char* file, int line, const EJError& err);
+ void ej_log_errno_status(const char* file, int line, int errno_rv, const std::string& msg);
+ void ej_log_errno_status(const char* file, int line, int errno_rv, const char* msg);
+
+
+#define EJ_ERRNO_MSG(err) ej_errno_msg(err)
+ const char* ej_errno_msg(int errno_rv);
+
+ /**
+ * Exception class
+ */
+ class EJError {
+ public:
+
+ //exception message
+ const std::string msg;
+ //error code
+ const int errno_code;
+
+ const std::string location;
+ const size_t line;
+
+ public:
+
+ virtual void errPrint();
+
+ public:
+
+ EJError(const EJError& src) : msg(src.msg), errno_code(src.errno_code), location(src.location), line(src.line) {
+ }
+
+ EJError(const char* _msg, int _errno_code = 0, const char* _location = "", size_t _line = 0) :
+ msg(_msg), errno_code(_errno_code), location(_location), line(_line) {
+ };
+
+ EJError(const std::string& _msg, int _errno_code = 0, const char* _location = "", size_t _line = 0) :
+ msg(_msg), errno_code(_errno_code), location(_location), line(_line) {
+ }
+
+ virtual ~EJError() {
+ }
+ };
+
+}
+
+
+
+#endif /* EJDB_LOGGING_H */
+
#include <node.h>
#include <ejdb.h>
#include <locale.h>
+#include <stdio.h>
+
+#include "ejdb_args.h"
+#include "ejdb_cmd.h"
+#include "ejdb_logging.h"
+#include "ejdb_thread.h"
using namespace node;
using namespace v8;
+
+#define DEFINE_INT64_CONSTANT(target, constant) \
+ (target)->Set(v8::String::NewSymbol(#constant), \
+ v8::Number::New((int64_t) constant), \
+ static_cast<v8::PropertyAttribute>( \
+ v8::ReadOnly|v8::DontDelete))
+
namespace ejdb {
- void Init(v8::Handle<v8::Object> target) {
- EJDB *jb = ejdbnew();
- ejdbdel(jb);
+ class NodeEJDB : public ObjectWrap {
+ typedef EIOCmdTask<NodeEJDB> EJTask;
+
+ static Persistent<FunctionTemplate> constructor_template;
+
+ static Handle<Value> s_new_object(const Arguments& args) {
+ HandleScope scope;
+ REQ_STR_ARG(0, dbPath);
+
+ return scope.Close(args.This());
+ }
+
+ NodeEJDB() {
+ }
+ virtual ~NodeEJDB() {
+ }
+ public:
+
+ static void Init(Handle<Object> target) {
+ HandleScope scope;
+
+ Local<FunctionTemplate> t = FunctionTemplate::New(s_new_object);
+ constructor_template = Persistent<FunctionTemplate>::New(t);
+ constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
+ constructor_template->SetClassName(String::NewSymbol("NodeEJDB"));
+ }
+
+ void Ref() {
+ ObjectWrap::Ref();
+
+ }
+
+ void Unref() {
+ ObjectWrap::Unref();
+ }
+ };
+
+ Persistent<FunctionTemplate> NodeEJDB::constructor_template;
+
+ void Init(v8::Handle<v8::Object> target) {
#ifdef __unix
setlocale(LC_ALL, "en_US.UTF-8"); //todo review it
#endif
+ ejdb::NodeEJDB::Init(target);
}
}
--- /dev/null
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#ifndef EJDB_THREAD_H
+#define EJDB_THREAD_H
+
+#ifdef _WIN32
+#include "win32/pthread_mutex.h"
+#else
+#include <pthread.h>
+#endif
+
+namespace ejdb {
+ /**
+ * Mutex
+ */
+ class EJMutex {
+ pthread_mutex_t cs;
+ volatile bool initialized;
+ public:
+ EJMutex() {
+ pthread_mutex_init(&cs, NULL);
+ initialized = true;
+ }
+ ~EJMutex() {
+ pthread_mutex_destroy(&cs);
+ initialized = false;
+ }
+ bool IsInitialized() {
+ return initialized;
+ }
+ void Lock() {
+ if (initialized) {
+ pthread_mutex_lock(&cs);
+ }
+ }
+ void Unlock() {
+ if (initialized) {
+ pthread_mutex_unlock(&cs);
+ }
+ }
+ };
+
+ /**
+ * Stack based mutex locking
+ */
+ class EJCriticalSection {
+ private:
+ EJMutex& mutex;
+ public:
+ EJCriticalSection(EJMutex& guard) : mutex(guard) {
+ mutex.Lock();
+ }
+ ~EJCriticalSection() {
+ mutex.Unlock();
+ }
+ };
+}
+
+
+
+#endif /* EJDB_THREAD_H */
+
</df>
<in>ejdb_native.node</in>
</df>
+ <in>ejdb_native.node</in>
<in>linker.lock</in>
</df>
+ <in>Makefile</in>
+ <in>binding.Makefile</in>
<in>config.gypi</in>
+ <in>ejdb_native.target.mk</in>
</df>
<df name="nodejs">
<df name="benchmark">
--- /dev/null
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#ifdef _WIN32
+
+#ifndef PTHREAD_MUTEX_H
+#define PTHREAD_MUTEX_H
+
+/*
+ * Posix Threads library for Microsoft Windows
+ *
+ * Use at own risk, there is no implied warranty to this code.
+ * It uses undocumented features of Microsoft Windows that can change
+ * at any time in the future.
+ *
+ * (C) 2010 Lockless Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of Lockless Inc. nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AN
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include <winsock2.h>
+#include <errno.h>
+#include <sys/timeb.h>
+
+struct timespec {
+ long tv_sec; /* seconds */
+ long tv_nsec; /* nanoseconds */
+};
+
+static unsigned long long _pthread_time_in_ms(void)
+{
+ struct __timeb64 tb;
+
+ _ftime64(&tb);
+
+ return tb.time * 1000 + tb.millitm;
+}
+
+static unsigned long long _pthread_time_in_ms_from_timespec(const struct timespec *ts)
+{
+ unsigned long long t = ts->tv_sec * 1000;
+ t += ts->tv_nsec / 1000000;
+
+ return t;
+}
+
+static unsigned long long _pthread_rel_time_in_ms(const struct timespec *ts)
+{
+ unsigned long long t1 = _pthread_time_in_ms_from_timespec(ts);
+ unsigned long long t2 = _pthread_time_in_ms();
+
+ /* Prevent underflow */
+ if (t1 < t2) return 1;
+ return t1 - t2;
+}
+
+typedef CRITICAL_SECTION pthread_mutex_t;
+typedef unsigned int pthread_mutexattr_t;
+
+static int pthread_mutex_lock(pthread_mutex_t *m)
+{
+ EnterCriticalSection(m);
+ return 0;
+}
+
+static int pthread_mutex_unlock(pthread_mutex_t *m)
+{
+ LeaveCriticalSection(m);
+ return 0;
+}
+
+static int pthread_mutex_trylock(pthread_mutex_t *m)
+{
+ return TryEnterCriticalSection(m) ? 0 : EBUSY;
+}
+
+static int pthread_mutex_init(pthread_mutex_t *m, pthread_mutexattr_t *a)
+{
+ (void) a;
+ InitializeCriticalSection(m);
+
+ return 0;
+}
+
+static int pthread_mutex_destroy(pthread_mutex_t *m)
+{
+ DeleteCriticalSection(m);
+ return 0;
+}
+
+#define PTHREAD_MUTEX_INITIALIZER {(PRTL_CRITICAL_SECTION_DEBUG)-1,-1,0,0,0,0}
+#define PTHREAD_MUTEX_NORMAL 0
+#define PTHREAD_MUTEX_ERRORCHECK 1
+#define PTHREAD_MUTEX_RECURSIVE 2
+#define PTHREAD_MUTEX_DEFAULT 3
+#define PTHREAD_MUTEX_SHARED 4
+#define PTHREAD_MUTEX_PRIVATE 0
+
+#ifndef PTHREAD_PRIO_MULT
+# define PTHREAD_PRIO_MULT 32
+#endif
+
+static int pthread_mutexattr_init(pthread_mutexattr_t *a)
+{
+ *a = 0;
+ return 0;
+}
+
+static int pthread_mutexattr_destroy(pthread_mutexattr_t *a)
+{
+ (void) a;
+ return 0;
+}
+
+static int pthread_mutexattr_gettype(pthread_mutexattr_t *a, int *type)
+{
+ *type = *a & 3;
+
+ return 0;
+}
+
+static int pthread_mutexattr_settype(pthread_mutexattr_t *a, int type)
+{
+ if ((unsigned) type > 3) return EINVAL;
+ *a &= ~3;
+ *a |= type;
+
+ return 0;
+}
+
+static int pthread_mutexattr_getpshared(pthread_mutexattr_t *a, int *type)
+{
+ *type = *a & 4;
+
+ return 0;
+}
+
+static int pthread_mutexattr_setpshared(pthread_mutexattr_t * a, int type)
+{
+ if ((type & 4) != type) return EINVAL;
+
+ *a &= ~4;
+ *a |= type;
+
+ return 0;
+}
+
+static int pthread_mutexattr_getprotocol(pthread_mutexattr_t *a, int *type)
+{
+ *type = *a & (8 + 16);
+
+ return 0;
+}
+
+static int pthread_mutexattr_setprotocol(pthread_mutexattr_t *a, int type)
+{
+ if ((type & (8 + 16)) != 8 + 16) return EINVAL;
+
+ *a &= ~(8 + 16);
+ *a |= type;
+
+ return 0;
+}
+
+static int pthread_mutexattr_getprioceiling(pthread_mutexattr_t *a, int * prio)
+{
+ *prio = *a / PTHREAD_PRIO_MULT;
+ return 0;
+}
+
+static int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *a, int prio)
+{
+ *a &= (PTHREAD_PRIO_MULT - 1);
+ *a += prio * PTHREAD_PRIO_MULT;
+
+ return 0;
+}
+
+static int pthread_mutex_timedlock(pthread_mutex_t *m, const struct timespec *ts)
+{
+ unsigned long long t, ct;
+
+ struct _pthread_crit_t
+ {
+ void *debug;
+ LONG count;
+ LONG r_count;
+ HANDLE owner;
+ HANDLE sem;
+ ULONG_PTR spin;
+ };
+
+ /* Try to lock it without waiting */
+ if (!pthread_mutex_trylock(m)) return 0;
+
+ ct = _pthread_time_in_ms();
+ t = _pthread_time_in_ms_from_timespec(ts);
+
+ while (1)
+ {
+ /* Have we waited long enough? */
+ if (ct > t) return ETIMEDOUT;
+
+ /* Wait on semaphore within critical section */
+ WaitForSingleObject(((struct _pthread_crit_t *)m)->sem, (DWORD)(t - ct));
+
+ /* Try to grab lock */
+ if (!pthread_mutex_trylock(m)) return 0;
+
+ /* Get current time */
+ ct = _pthread_time_in_ms();
+ }
+}
+
+#endif /* PTHREAD_MUTEX_H */
+#endif /* _WIN32 */