src/Platform-Windows.cpp
author Asher Baker <asherkin@gmail.com>
Mon Jun 10 01:04:43 2013 +0100 (2013-06-10)
changeset 263 ba85a47ee414
parent 251 ca99a81745fe
permissions -rw-r--r--
Normalise line endings.
dvander@28
     1
/* vim: set ts=4 sw=4 tw=99 et:
dvander@28
     2
 *
dvander@28
     3
 * Copyright (C) 2012 David Anderson
dvander@28
     4
 *
dvander@233
     5
 * This file is part of SourcePawn.
dvander@28
     6
 *
dvander@233
     7
 * SourcePawn is free software: you can redistribute it and/or modify it under
dvander@28
     8
 * the terms of the GNU General Public License as published by the Free
dvander@28
     9
 * Software Foundation, either version 3 of the License, or (at your option)
dvander@28
    10
 * any later version.
dvander@28
    11
 * 
dvander@233
    12
 * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
dvander@28
    13
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
dvander@28
    14
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
dvander@28
    15
 *
dvander@28
    16
 * You should have received a copy of the GNU General Public License along with
dvander@233
    17
 * SourcePawn. If not, see http://www.gnu.org/licenses/.
dvander@11
    18
 */
dvander@11
    19
dvander@11
    20
#define WIN32_LEAN_AND_MEAN
dvander@11
    21
#include <Windows.h>
dvander@251
    22
#include <direct.h>
dvander@251
    23
#include <sys/stat.h>
dvander@11
    24
#include "Platform.h"
dvander@11
    25
dvander@59
    26
using namespace ke;
dvander@11
    27
dvander@11
    28
static inline DWORD
dvander@11
    29
ToProtBits(OS::Protection prot)
dvander@11
    30
{
dvander@11
    31
    switch (prot) {
dvander@28
    32
      case OS::Prot_ReadWrite:
dvander@11
    33
        return PAGE_READWRITE;
dvander@11
    34
      case OS::Prot_ReadWriteExecute:
dvander@11
    35
        return PAGE_EXECUTE_READWRITE;
dvander@11
    36
      default:
dvander@11
    37
        assert(prot == OS::Prot_ReadExecute);
dvander@11
    38
        return PAGE_EXECUTE_READ;
dvander@11
    39
    }
dvander@11
    40
}
dvander@11
    41
dvander@11
    42
Address
dvander@11
    43
OS::MapMemory(size_t amount, MapMode mode, Protection prot_)
dvander@11
    44
{
dvander@11
    45
    DWORD prot = ToProtBits(prot_);
dvander@11
    46
    DWORD type = MEM_RESERVE;
dvander@11
    47
    if (mode == Map_Commit)
dvander@11
    48
        type |= MEM_COMMIT;
dvander@11
    49
dvander@11
    50
    return (Address)VirtualAlloc(NULL, amount, type, prot);
dvander@11
    51
}
dvander@11
    52
dvander@11
    53
bool
dvander@11
    54
OS::CommitMemory(Address address, size_t amount, Protection prot_)
dvander@11
    55
{
dvander@11
    56
    DWORD prot = ToProtBits(prot_);
dvander@11
    57
    return !!VirtualAlloc(address, amount, MEM_COMMIT, prot);
dvander@11
    58
}
dvander@11
    59
dvander@11
    60
void
dvander@11
    61
OS::UnmapMemory(Address address, size_t size)
dvander@11
    62
{
dvander@11
    63
    VirtualFree(address, 0, MEM_RELEASE);
dvander@11
    64
}
dvander@11
    65
dvander@28
    66
static Address
dvander@53
    67
MapMemoryAt(Address address, size_t amount, OS::MapMode mode, OS::Protection prot_)
dvander@28
    68
{
dvander@28
    69
    DWORD bits = ToProtBits(prot_);
dvander@28
    70
    DWORD flags = MEM_RESERVE;
dvander@53
    71
    if (mode == OS::Map_Commit)
dvander@28
    72
        flags |= MEM_COMMIT;
dvander@28
    73
dvander@69
    74
    return (Address)VirtualAlloc((LPVOID)address, amount, flags, bits);
dvander@28
    75
}
dvander@28
    76
dvander@11
    77
OS::AlignableMapping
dvander@11
    78
OS::MapAlignedMemory(size_t amount, size_t alignment, MapMode mode)
dvander@11
    79
{
dvander@11
    80
    Address addr = MapMemory(amount, mode, OS::Prot_ReadWrite);
dvander@11
    81
    if (!addr)
dvander@11
    82
        return AlignableMapping(NULL, alignment, 0);
dvander@11
    83
dvander@11
    84
    if (!IsAligned(addr, alignment)) {
dvander@11
    85
        UnmapMemory(addr, amount);
dvander@11
    86
dvander@11
    87
        // Try to grab the next available aligned address.
dvander@11
    88
        addr = AlignedBase(addr, alignment);
dvander@11
    89
        addr = MapMemoryAt(addr + alignment, amount, mode, OS::Prot_ReadWrite);
dvander@11
    90
        while (!addr) {
dvander@11
    91
            // Try to over-allocate to get the right region. This can race
dvander@11
    92
            // with other threads; we expect this to be rare. If this turns
dvander@11
    93
            // out to be a problem, the API is set up such that we can just
dvander@11
    94
            // return two pointers: the base, and the aligned address into
dvander@11
    95
            // the over-allocated region.
dvander@11
    96
            addr = MapMemory(amount + alignment, mode, OS::Prot_ReadWrite);
dvander@11
    97
            if (!addr)
dvander@11
    98
                return AlignableMapping(NULL, alignment, 0);
dvander@11
    99
            UnmapMemory(addr, amount + alignment);
dvander@11
   100
            addr = AlignedBase(addr, alignment);
dvander@11
   101
            addr = MapMemoryAt(addr + alignment, amount, mode, OS::Prot_ReadWrite);
dvander@11
   102
        }
dvander@11
   103
    }
dvander@11
   104
dvander@11
   105
    return AlignableMapping(addr, alignment, amount);
dvander@11
   106
}
dvander@11
   107
dvander@11
   108
void
dvander@11
   109
OS::UnmapAlignedMemory(Address address, size_t size)
dvander@11
   110
{
dvander@11
   111
    OS::UnmapMemory(address, size);
dvander@11
   112
}
dvander@251
   113
dvander@251
   114
bool
dvander@251
   115
OS::GetAbsolutePath(const char *path, AutoFree<char> &chars)
dvander@251
   116
{
dvander@251
   117
    char try1[MAX_PATH];
dvander@251
   118
    DWORD result = GetFullPathName(path, sizeof(try1), try1, NULL);
dvander@251
   119
    if (result <= 0)
dvander@251
   120
        return false;
dvander@251
   121
dvander@251
   122
    // +1 because if result < MAX_PATH, it doesn't include the null terminator.
dvander@251
   123
    chars = (char *)calloc(result + 1, sizeof(char));
dvander@251
   124
    if (!*chars)
dvander@251
   125
        return false;
dvander@251
   126
dvander@251
   127
    if (result <= MAX_PATH) {
dvander@251
   128
        strcpy(*chars, try1);
dvander@251
   129
        return true;
dvander@251
   130
    }
dvander@251
   131
dvander@251
   132
    // We should get the same output on the next try.
dvander@251
   133
    return GetFullPathName(path, result, *chars, NULL) == result - 1;
dvander@251
   134
}
dvander@251
   135
dvander@251
   136
bool
dvander@251
   137
OS::SplitPath(const char *path, AutoFree<char> &base, AutoFree<char> &name)
dvander@251
   138
{
dvander@251
   139
    size_t len = strlen(path);
dvander@251
   140
dvander@251
   141
    // Skip trailing slashes.
dvander@251
   142
    while (len > 1 && (path[len - 1] == '/' || path[len - 1] == '\\'))
dvander@251
   143
        len--;
dvander@251
   144
dvander@251
   145
    for (size_t i = len - 1; i < len; i--) {
dvander@251
   146
        if (path[i] == '\\' || path[i] == '/') {
dvander@251
   147
            name = (char *)calloc(len - i, sizeof(char));
dvander@251
   148
            if (!*name)
dvander@251
   149
                return false;
dvander@251
   150
dvander@251
   151
            strcpy(*name, &path[i + 1]);
dvander@251
   152
dvander@251
   153
            base = (char *)calloc(i + 1, sizeof(char));
dvander@251
   154
            if (!*base)
dvander@251
   155
                return false;
dvander@251
   156
dvander@251
   157
            memcpy(*base, path, i);
dvander@251
   158
            (*base)[i] = '\0';
dvander@251
   159
            return true;
dvander@251
   160
        }
dvander@251
   161
    }
dvander@251
   162
    
dvander@251
   163
    // The path should have been absolute, which contains at least one separator.
dvander@251
   164
    return false;
dvander@251
   165
}
dvander@251
   166
dvander@251
   167
const char *
dvander@251
   168
OS::PathSeparator()
dvander@251
   169
{
dvander@251
   170
    return "\\";
dvander@251
   171
}
dvander@251
   172
dvander@251
   173
OS::PathType
dvander@251
   174
OS::InspectPath(const char *path)
dvander@251
   175
{
dvander@251
   176
    struct _stat s;
dvander@251
   177
    int result = _stat(path, &s);
dvander@251
   178
    if (result != 0)
dvander@251
   179
        return OS::Path_Invalid;
dvander@251
   180
dvander@251
   181
    if (s.st_mode & _S_IFDIR)
dvander@251
   182
        return OS::Path_Folder;
dvander@251
   183
    if (s.st_mode & _S_IFREG)
dvander@251
   184
        return OS::Path_File;
dvander@251
   185
dvander@251
   186
    return OS::Path_Invalid;
dvander@251
   187
}