From: adam Date: Tue, 30 Oct 2012 06:14:43 +0000 (+0700) Subject: #1 X-Git-Tag: v1.2.12~643^2~44 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=66df94f4d6ecb3a64e7b520ce0e2ae7cf428a0d7;p=platform%2Fupstream%2Fejdb.git #1 --- diff --git a/node/Makefile b/node/Makefile index e69de29..16a6411 100644 --- a/node/Makefile +++ b/node/Makefile @@ -0,0 +1,9 @@ + + +all: + npm build . + +clean: + rm -rf ./build + +.PHONY: all clean \ No newline at end of file diff --git a/node/binding.gyp b/node/binding.gyp index 75cc305..af7afc2 100644 --- a/node/binding.gyp +++ b/node/binding.gyp @@ -2,7 +2,10 @@ 'targets': [ { 'target_name' : 'ejdb_native', - 'sources' : ['ejdb_native.cc'], + 'sources' : [ + 'ejdb_native.cc', + 'ejdb_logging.cc' + ], 'include_dirs': ['../tcejdb'], 'libraries' : [ '-L../../tcejdb', @@ -11,10 +14,15 @@ '-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 diff --git a/node/ejdb_args.h b/node/ejdb_args.h new file mode 100644 index 0000000..ff64add --- /dev/null +++ b/node/ejdb_args.h @@ -0,0 +1,110 @@ +/* + * 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 +#include + + +#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 VAR = Local::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 VAR = Local::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 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 VAR = Local::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 VAR = Local::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(args[I]->ToObject()); + + +#endif /* EJDB_ARGS_H */ + diff --git a/node/ejdb_cmd.h b/node/ejdb_cmd.h new file mode 100644 index 0000000..f03ee8a --- /dev/null +++ b/node/ejdb_cmd.h @@ -0,0 +1,89 @@ +/* + * File: ejdb_cmd.h + * Author: adam + * + * Created on October 30, 2012, 11:41 AM + */ + +#ifndef EJDB_CMD_H +#define EJDB_CMD_H + +#include +#include +#include + + +namespace ejdb { + + template < typename T, typename D = void > class EIOCmdTask { + public: + + //uv request + uv_work_t uv_work; + + v8::Persistent 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*); + + + public: + + static void free_val(EIOCmdTask* dtask) { + if (dtask->cmd_data) { + free(dtask->cmd_data); + dtask->cmd_data = NULL; + } + } + + static void delete_val(EIOCmdTask* dtask) { + if (dtask->cmd_data) { + delete dtask->cmd_data; + dtask->cmd_data = NULL; + } + } + + public: + + EIOCmdTask(const v8::Handle& _cb, T* _wrapped, int _cmd, + D* _cmd_data, void (*_free_cmd_data)(EIOCmdTask*)) : + 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::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 */ + diff --git a/node/ejdb_logging.cc b/node/ejdb_logging.cc new file mode 100644 index 0000000..c4ba7ed --- /dev/null +++ b/node/ejdb_logging.cc @@ -0,0 +1,145 @@ +#include "ejdb_logging.h" +#include "ejdb_thread.h" + +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#include +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 + + + + diff --git a/node/ejdb_logging.h b/node/ejdb_logging.h new file mode 100644 index 0000000..296948c --- /dev/null +++ b/node/ejdb_logging.h @@ -0,0 +1,98 @@ +/* + * 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 + +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 */ + diff --git a/node/ejdb_native.cc b/node/ejdb_native.cc index 75bd8b8..7da86af 100644 --- a/node/ejdb_native.cc +++ b/node/ejdb_native.cc @@ -3,19 +3,70 @@ #include #include #include +#include + +#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::ReadOnly|v8::DontDelete)) + namespace ejdb { - void Init(v8::Handle target) { - EJDB *jb = ejdbnew(); - ejdbdel(jb); + class NodeEJDB : public ObjectWrap { + typedef EIOCmdTask EJTask; + + static Persistent constructor_template; + + static Handle 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 target) { + HandleScope scope; + + Local t = FunctionTemplate::New(s_new_object); + constructor_template = Persistent::New(t); + constructor_template->InstanceTemplate()->SetInternalFieldCount(1); + constructor_template->SetClassName(String::NewSymbol("NodeEJDB")); + } + + void Ref() { + ObjectWrap::Ref(); + + } + + void Unref() { + ObjectWrap::Unref(); + } + }; + + Persistent NodeEJDB::constructor_template; + + void Init(v8::Handle target) { #ifdef __unix setlocale(LC_ALL, "en_US.UTF-8"); //todo review it #endif + ejdb::NodeEJDB::Init(target); } } diff --git a/node/ejdb_thread.h b/node/ejdb_thread.h new file mode 100644 index 0000000..f6557e6 --- /dev/null +++ b/node/ejdb_thread.h @@ -0,0 +1,64 @@ +#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 +#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 */ + diff --git a/node/nbproject/configurations.xml b/node/nbproject/configurations.xml index 2b05df8..3fe02ba 100644 --- a/node/nbproject/configurations.xml +++ b/node/nbproject/configurations.xml @@ -9,9 +9,13 @@ ejdb_native.node + ejdb_native.node linker.lock + Makefile + binding.Makefile config.gypi + ejdb_native.target.mk diff --git a/node/win32/pthread_mutex.h b/node/win32/pthread_mutex.h new file mode 100644 index 0000000..cb52d79 --- /dev/null +++ b/node/win32/pthread_mutex.h @@ -0,0 +1,241 @@ +#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 +#include +#include + +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 */