From dad631290cc197343ef4dcb3065fdfae08b4c6bc Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 15 Jul 2007 00:32:37 +0000 Subject: [PATCH] * Made header includable by C code. In this case a KMessage structure with the same size as the class is defined. * The SetTo() methods do now accept an unspecified (negative) bufferSize in case of being told to initialize from the given buffer. * Added handy Get*() methods returning a field element value or a supplied default value, if the field element doesn't exist. * Added also handy Set*() methods setting the value of first element of a field, i.e. adding it, if it didn't exist before, otherwise replacing the old value. Only for fixed size types. * Moved _FindType() inline template method into the header. * Made the source file fit for use in the boot loader. If the macro KMESSAGE_CONTAINER_ONLY is defined, the message sending/receiving part is omitted. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21605 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/kernel/util/KMessage.h | 244 ++++++++++++++++++++++- src/system/kernel/messaging/KMessage.cpp | 108 +++++++--- 2 files changed, 319 insertions(+), 33 deletions(-) diff --git a/headers/private/kernel/util/KMessage.h b/headers/private/kernel/util/KMessage.h index da7f0fb3d4..061aa63c1b 100644 --- a/headers/private/kernel/util/KMessage.h +++ b/headers/private/kernel/util/KMessage.h @@ -11,6 +11,10 @@ #include #include + +#ifdef __cplusplus + + class BMessage; namespace BPrivate { @@ -36,7 +40,7 @@ public: status_t SetTo(uint32 what, uint32 flags = 0); status_t SetTo(void *buffer, int32 bufferSize, uint32 what, uint32 flags = 0); - status_t SetTo(const void *buffer, int32 bufferSize); + status_t SetTo(const void *buffer, int32 bufferSize = -1); void Unset(); void SetWhat(uint32 what); @@ -82,6 +86,33 @@ public: inline status_t FindString(const char *name, int32 index, const char **value) const; + inline bool GetBool(const char* name, bool defaultValue) const; + inline bool GetBool(const char* name, int32 index, bool defaultValue) const; + inline int8 GetInt8(const char* name, int8 defaultValue) const; + inline int8 GetInt8(const char* name, int32 index, int8 defaultValue) const; + inline int16 GetInt16(const char* name, int16 defaultValue) const; + inline int16 GetInt16(const char* name, int32 index, + int16 defaultValue) const; + inline int32 GetInt32(const char* name, int32 defaultValue) const; + inline int32 GetInt32(const char* name, int32 index, + int32 defaultValue) const; + inline int64 GetInt64(const char* name, int64 defaultValue) const; + inline int64 GetInt64(const char* name, int32 index, + int64 defaultValue) const; + inline const char* GetString(const char* name, + const char* defaultValue) const; + inline const char* GetString(const char* name, int32 index, + const char* defaultValue) const; + + // fixed size fields only + status_t SetData(const char* name, type_code type, const void* data, + int32 numBytes); + inline status_t SetBool(const char* name, bool value); + inline status_t SetInt8(const char* name, int8 value); + inline status_t SetInt16(const char* name, int16 value); + inline status_t SetInt32(const char* name, int32 value); + inline status_t SetInt64(const char* name, int64 value); + // message delivery team_id Sender() const; int32 TargetToken() const; @@ -129,7 +160,7 @@ private: status_t _AddFieldData(KMessageField *field, const void *data, int32 elementSize, int32 elementCount); - status_t _InitFromBuffer(); + status_t _InitFromBuffer(bool sizeFromBuffer); void _InitBuffer(uint32 what); void _CheckBuffer(); // debugging only @@ -139,6 +170,8 @@ private: int32 _CapacityFor(int32 size); template inline status_t _FindType(const char* name, type_code type, int32 index, T *value) const; + template inline T _GetType(const char* name, type_code type, + int32 index, const T& defaultValue) const; Header fHeader; // pointed to by fBuffer, if nothing is // allocated @@ -185,8 +218,9 @@ private: using BPrivate::KMessage; using BPrivate::KMessageField; -// #pragma mark - -// inline functions + +// #pragma mark - inline functions + // AddBool inline @@ -238,8 +272,30 @@ KMessage::AddString(const char *name, const char *value) return AddData(name, B_STRING_TYPE, value, strlen(value) + 1, false); } + // #pragma mark - + +// _FindType +template +inline status_t +KMessage::_FindType(const char* name, type_code type, int32 index, + T *value) const +{ + const void *data; + int32 size; + status_t error = FindData(name, type, index, &data, &size); + if (error != B_OK) + return error; + + if (size != sizeof(T)) + return B_BAD_DATA; + + *value = *(T*)data; + + return B_OK; +} + // FindBool inline status_t @@ -337,4 +393,184 @@ KMessage::FindString(const char *name, int32 index, const char **value) const return FindData(name, B_STRING_TYPE, index, (const void**)value, &size); } + +// _GetType +template +inline T +KMessage::_GetType(const char* name, type_code type, int32 index, + const T& defaultValue) const +{ + T value; + if (_FindType(name, type, index, &value) == B_OK) + return value; + return defaultValue; +} + + +// GetBool +inline bool +KMessage::GetBool(const char* name, bool defaultValue) const +{ + return _GetType(name, B_BOOL_TYPE, 0, defaultValue); +} + + +// GetBool +inline bool +KMessage::GetBool(const char* name, int32 index, bool defaultValue) const +{ + return _GetType(name, B_BOOL_TYPE, index, defaultValue); +} + +// GetInt8 +inline int8 +KMessage::GetInt8(const char* name, int8 defaultValue) const +{ + return _GetType(name, B_INT8_TYPE, 0, defaultValue); +} + + +// GetInt8 +inline int8 +KMessage::GetInt8(const char* name, int32 index, int8 defaultValue) const +{ + return _GetType(name, B_INT8_TYPE, index, defaultValue); +} + + +// GetInt16 +inline int16 +KMessage::GetInt16(const char* name, int16 defaultValue) const +{ + return _GetType(name, B_INT16_TYPE, 0, defaultValue); +} + + +// GetInt16 +inline int16 +KMessage::GetInt16(const char* name, int32 index, int16 defaultValue) const +{ + return _GetType(name, B_INT16_TYPE, index, defaultValue); +} + + +// GetInt32 +inline int32 +KMessage::GetInt32(const char* name, int32 defaultValue) const +{ + return _GetType(name, B_INT32_TYPE, 0, defaultValue); +} + + +// GetInt32 +inline int32 +KMessage::GetInt32(const char* name, int32 index, int32 defaultValue) const +{ + return _GetType(name, B_INT32_TYPE, index, defaultValue); +} + + +// GetInt64 +inline int64 +KMessage::GetInt64(const char* name, int64 defaultValue) const +{ + return _GetType(name, B_INT64_TYPE, 0, defaultValue); +} + + +// GetInt64 +inline int64 +KMessage::GetInt64(const char* name, int32 index, int64 defaultValue) const +{ + return _GetType(name, B_INT64_TYPE, index, defaultValue); +} + + +// GetString +inline const char* +KMessage::GetString(const char* name, int32 index, + const char* defaultValue) const +{ + // don't use _GetType() here, since it checks field size == sizeof(T) + int32 size; + const char* value; + if (FindData(name, B_STRING_TYPE, index, (const void**)&value, &size) + == B_OK) { + return value; + } + return defaultValue; +} + + +// GetString +inline const char* +KMessage::GetString(const char* name, const char* defaultValue) const +{ + return GetString(name, 0, defaultValue); +} + + +// SetBool +inline status_t +KMessage::SetBool(const char* name, bool value) +{ + return SetData(name, B_BOOL_TYPE, &value, sizeof(bool)); +} + + +// SetInt8 +inline status_t +KMessage::SetInt8(const char* name, int8 value) +{ + return SetData(name, B_INT8_TYPE, &value, sizeof(int8)); +} + + +// SetInt16 +inline status_t +KMessage::SetInt16(const char* name, int16 value) +{ + return SetData(name, B_INT16_TYPE, &value, sizeof(int16)); +} + + +// SetInt32 +inline status_t +KMessage::SetInt32(const char* name, int32 value) +{ + return SetData(name, B_INT32_TYPE, &value, sizeof(int32)); +} + + +// SetInt64 +inline status_t +KMessage::SetInt64(const char* name, int64 value) +{ + return SetData(name, B_INT64_TYPE, &value, sizeof(int64)); +} + + +#else // !__cplusplus + + +typedef struct KMessage { + struct Header { + uint32 magic; + int32 size; + uint32 what; + team_id sender; + int32 targetToken; + port_id replyPort; + int32 replyToken; + } fHeader; + void* fBuffer; + int32 fBufferCapacity; + uint32 fFlags; + int32 fLastFieldOffset; +} KMessage; + + +#endif // !__cplusplus + + #endif // KMESSAGE_H diff --git a/src/system/kernel/messaging/KMessage.cpp b/src/system/kernel/messaging/KMessage.cpp index 8d622c2c74..676b2cd53c 100644 --- a/src/system/kernel/messaging/KMessage.cpp +++ b/src/system/kernel/messaging/KMessage.cpp @@ -1,8 +1,10 @@ /* - * Copyright 2005, Ingo Weinhold, bonefish@users.sf.net. All rights reserved. - * Distributed under the terms of the MIT License. + * Copyright 2005-2007, Ingo Weinhold, bonefish@users.sf.net. + * All rights reserved. Distributed under the terms of the MIT License. */ +#include "KMessage.h" + #include #include @@ -10,7 +12,13 @@ #include #include -#include "KMessage.h" +#if defined(_BOOT_MODE) +# include +#else +# include +#endif + +using std::nothrow; // TODO: Add a field index using a hash map, so that lookup improves to O(1) // (is now O(n)). @@ -141,21 +149,33 @@ status_t KMessage::SetTo(void *buffer, int32 bufferSize, uint32 what, uint32 flags) { Unset(); - if (!buffer || bufferSize < (int)sizeof(Header)) + + if (!buffer) return B_BAD_VALUE; + + if (bufferSize < 0) { + if (!(flags & KMESSAGE_INIT_FROM_BUFFER)) + return B_BAD_VALUE; + } else if (bufferSize < (int)sizeof(Header)) + return B_BAD_VALUE; + // if read-only, we need to init from the buffer, too if (flags & KMESSAGE_READ_ONLY && !(flags & KMESSAGE_INIT_FROM_BUFFER)) return B_BAD_VALUE; + fBuffer = buffer; fBufferCapacity = bufferSize; fFlags = flags; + status_t error = B_OK; if (flags & KMESSAGE_INIT_FROM_BUFFER) - error = _InitFromBuffer(); + error = _InitFromBuffer(bufferSize < 0); else _InitBuffer(what); + if (error != B_OK) Unset(); + return error; } @@ -325,6 +345,42 @@ KMessage::AddArray(const char *name, type_code type, const void *data, return _AddFieldData(&field, data, elementSize, elementCount); } + +// SetData +status_t +KMessage::SetData(const char* name, type_code type, const void* data, + int32 numBytes) +{ + if (fBuffer != &fHeader && (fFlags & KMESSAGE_READ_ONLY)) + return B_NOT_ALLOWED; + + KMessageField field; + + if (FindField(name, &field) == B_OK) { + // field already known + if (field.TypeCode() != type || !field.HasFixedElementSize() + || field.ElementSize() != numBytes) { + return B_BAD_VALUE; + } + + // if it has an element, just replace its value + if (field.CountElements() > 0) { + const void* element = field.ElementAt(0); + memcpy(const_cast(element), data, numBytes); + return B_OK; + } + } else { + // no such field yet -- add it + status_t error = _AddField(name, type, numBytes, &field); + if (error != B_OK) + return error; + } + + // we've got an empty field -- add the element + return _AddFieldData(&field, data, numBytes, 1); +} + + // FindData status_t KMessage::FindData(const char *name, type_code type, const void **data, @@ -380,6 +436,9 @@ KMessage::ReplyToken() const return _Header()->replyToken; } + +#ifndef KMESSAGE_CONTAINER_ONLY + // SendTo status_t KMessage::SendTo(port_id targetPort, int32 targetToken, port_id replyPort, @@ -512,6 +571,9 @@ KMessage::ReceiveFrom(port_id fromPort, bigtime_t timeout) KMESSAGE_OWNS_BUFFER | KMESSAGE_INIT_FROM_BUFFER); } +#endif // !KMESSAGE_CONTAINER_ONLY + + // _Header KMessage::Header * KMessage::_Header() const @@ -631,18 +693,24 @@ KMessage::_AddFieldData(KMessageField *field, const void *data, // _InitFromBuffer status_t -KMessage::_InitFromBuffer() +KMessage::_InitFromBuffer(bool sizeFromBuffer) { - if (!fBuffer || fBufferCapacity < (int)sizeof(Header) - || _Align(fBuffer) != fBuffer) { + if (!fBuffer || _Align(fBuffer) != fBuffer) return B_BAD_DATA; - } - // check header Header *header = _Header(); + + if (sizeFromBuffer) + fBufferCapacity = header->size; + + if (fBufferCapacity < (int)sizeof(Header)) + return B_BAD_DATA; + + // check header if (header->magic != kMessageHeaderMagic) return B_BAD_DATA; if (header->size < (int)sizeof(Header) || header->size > fBufferCapacity) return B_BAD_DATA; + // check the fields FieldHeader *fieldHeader = NULL; uint8 *data = (uint8*)_FirstFieldHeader(); @@ -721,7 +789,7 @@ void KMessage::_CheckBuffer() { int32 lastFieldOffset = fLastFieldOffset; - if (_InitFromBuffer() != B_OK) { + if (_InitFromBuffer(false) != B_OK) { PANIC("internal data mangled"); } if (fLastFieldOffset != lastFieldOffset) { @@ -779,24 +847,6 @@ KMessage::_CapacityFor(int32 size) * kMessageReallocChunkSize; } -// _FindType -template -inline -status_t -KMessage::_FindType(const char* name, type_code type, int32 index, - T *value) const -{ - const void *data; - int32 size; - status_t error = FindData(name, type, index, &data, &size); - if (error != B_OK) - return error; - if (size != sizeof(T)) - return B_BAD_DATA; - *value = *(T*)data; - return B_OK; -} - // #pragma mark -