icd: add generic icd_instance

It provides memory allocation and logging support.
diff --git a/icd/common/icd-instance.c b/icd/common/icd-instance.c
new file mode 100644
index 0000000..ce6e1d8
--- /dev/null
+++ b/icd/common/icd-instance.c
@@ -0,0 +1,218 @@
+/*
+ * XGL
+ *
+ * Copyright (C) 2014-2015 LunarG, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *   Chia-I Wu <olv@lunarg.com>
+ */
+
+#define _ISOC11_SOURCE /* for aligned_alloc() */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "icd-instance.h"
+
+static void * XGLAPI default_alloc(void *user_data, size_t size,
+                                   size_t alignment,
+                                   XGL_SYSTEM_ALLOC_TYPE allocType)
+{
+    if (alignment <= 1) {
+        return malloc(size);
+    } else if (u_is_pow2(alignment)) {
+        if (alignment < sizeof(void *)) {
+            assert(u_is_pow2(sizeof(void*)));
+            alignment = sizeof(void *);
+        }
+
+        size = (size + alignment - 1) & ~(alignment - 1);
+
+        return aligned_alloc(alignment, size);
+    }
+    else {
+        return NULL;
+    }
+}
+
+static void XGLAPI default_free(void *user_data, void *ptr)
+{
+    free(ptr);
+}
+
+struct icd_instance *icd_instance_create(const XGL_APPLICATION_INFO *app_info,
+                                         const XGL_ALLOC_CALLBACKS *alloc_cb)
+{
+    static const XGL_ALLOC_CALLBACKS default_alloc_cb = {
+        .pfnAlloc = default_alloc,
+        .pfnFree = default_free,
+    };
+    struct icd_instance *instance;
+    const char *name;
+    size_t len;
+
+    if (!alloc_cb)
+        alloc_cb = &default_alloc_cb;
+
+    instance = alloc_cb->pfnAlloc(alloc_cb->pUserData, sizeof(*instance), 0,
+            XGL_SYSTEM_ALLOC_API_OBJECT);
+    if (!instance)
+        return NULL;
+
+    memset(instance, 0, sizeof(*instance));
+
+    name = (app_info->pAppName) ? app_info->pAppName : "unnamed";
+    len = strlen(name);
+    instance->name = alloc_cb->pfnAlloc(alloc_cb->pUserData, len + 1, 0,
+            XGL_SYSTEM_ALLOC_INTERNAL);
+    if (!instance->name) {
+        alloc_cb->pfnFree(alloc_cb->pUserData, instance);
+        return NULL;
+    }
+
+    memcpy(instance->name, name, len);
+    instance->name[len] = '\0';
+
+    instance->alloc_cb = *alloc_cb;
+
+    return instance;
+}
+
+void icd_instance_destroy(struct icd_instance *instance)
+{
+    struct icd_instance_logger *logger;
+
+    for (logger = instance->loggers; logger; logger = logger->next) {
+        struct icd_instance_logger *next = logger->next;
+
+        icd_instance_free(instance, logger);
+        logger = next;
+    }
+
+    icd_instance_free(instance, instance->name);
+    icd_instance_free(instance, instance);
+}
+
+XGL_RESULT icd_instance_set_bool(struct icd_instance *instance,
+                                 XGL_DBG_GLOBAL_OPTION option, bool yes)
+{
+    XGL_RESULT res = XGL_SUCCESS;
+
+    switch (option) {
+    case XGL_DBG_OPTION_DEBUG_ECHO_ENABLE:
+        instance->debug_echo_enable = yes;
+        break;
+    case XGL_DBG_OPTION_BREAK_ON_ERROR:
+        instance->break_on_error = yes;
+        break;
+    case XGL_DBG_OPTION_BREAK_ON_WARNING:
+        instance->break_on_warning = yes;
+        break;
+    default:
+        res = XGL_ERROR_INVALID_VALUE;
+        break;
+    }
+
+    return res;
+}
+
+XGL_RESULT icd_instance_add_logger(struct icd_instance *instance,
+                                   XGL_DBG_MSG_CALLBACK_FUNCTION func,
+                                   void *user_data)
+{
+    struct icd_instance_logger *logger;
+
+    for (logger = instance->loggers; logger; logger = logger->next) {
+        if (logger->func == func)
+            break;
+    }
+
+    if (!logger) {
+        logger = icd_instance_alloc(instance, sizeof(*logger), 0,
+                XGL_SYSTEM_ALLOC_DEBUG);
+        if (!logger)
+            return XGL_ERROR_OUT_OF_MEMORY;
+
+        logger->func = func;
+        logger->next = instance->loggers;
+        instance->loggers = logger;
+    }
+
+    logger->user_data = user_data;
+
+    return XGL_SUCCESS;
+}
+
+XGL_RESULT icd_instance_remove_logger(struct icd_instance *instance,
+                                      XGL_DBG_MSG_CALLBACK_FUNCTION func)
+{
+    struct icd_instance_logger *logger, *prev;
+
+    for (prev = NULL, logger = instance->loggers; logger;
+         prev = logger, logger = logger->next) {
+        if (logger->func == func)
+            break;
+    }
+
+    if (!logger)
+        return XGL_ERROR_INVALID_POINTER;
+
+    if (prev)
+        prev->next = logger->next;
+    else
+        instance->loggers = logger->next;
+
+    icd_instance_free(instance, logger);
+
+    return XGL_SUCCESS;
+}
+
+void icd_instance_log(const struct icd_instance *instance,
+                      XGL_DBG_MSG_TYPE msg_type,
+                      XGL_VALIDATION_LEVEL validation_level,
+                      XGL_BASE_OBJECT src_object,
+                      size_t location, int32_t msg_code,
+                      const char *msg)
+{
+    const struct icd_instance_logger *logger;
+
+    if (instance->debug_echo_enable || !instance->loggers) {
+        fputs(msg, stderr);
+        fputc('\n', stderr);
+    }
+
+    for (logger = instance->loggers; logger; logger = logger->next) {
+        logger->func(msg_type, validation_level, src_object, location,
+                msg_code, msg, logger->user_data);
+    }
+
+    switch (msg_type) {
+    case XGL_DBG_MSG_ERROR:
+        if (instance->break_on_error)
+            abort();
+        /* fall through */
+    case XGL_DBG_MSG_WARNING:
+        if (instance->break_on_warning)
+            abort();
+        break;
+    default:
+        break;
+    }
+}