util/HugeAllocator: throw std::bad_alloc on error

This commit is contained in:
Max Kellermann 2016-06-17 17:44:45 +02:00
parent 35faafb32c
commit ef053035d0
7 changed files with 39 additions and 54 deletions

View File

@ -20,14 +20,11 @@
#include "config.h" #include "config.h"
#include "MusicBuffer.hxx" #include "MusicBuffer.hxx"
#include "MusicChunk.hxx" #include "MusicChunk.hxx"
#include "system/FatalError.hxx"
#include <assert.h> #include <assert.h>
MusicBuffer::MusicBuffer(unsigned num_chunks) MusicBuffer::MusicBuffer(unsigned num_chunks)
:buffer(num_chunks) { :buffer(num_chunks) {
if (buffer.IsOOM())
FatalError("Failed to allocate buffer");
} }
MusicChunk * MusicChunk *

View File

@ -50,10 +50,7 @@ ThreadInputStream::Start(Error &error)
assert(buffer == nullptr); assert(buffer == nullptr);
void *p = HugeAllocate(buffer_size); void *p = HugeAllocate(buffer_size);
if (p == nullptr) { assert(p != nullptr);
error.SetErrno();
return nullptr;
}
buffer = new CircularBuffer<uint8_t>((uint8_t *)p, buffer_size); buffer = new CircularBuffer<uint8_t>((uint8_t *)p, buffer_size);

View File

@ -73,10 +73,10 @@ struct CurlInputStream final : public AsyncInputStream {
/** parser for icy-metadata */ /** parser for icy-metadata */
IcyInputStream *icy; IcyInputStream *icy;
CurlInputStream(const char *_url, Mutex &_mutex, Cond &_cond, CurlInputStream(const char *_url, Mutex &_mutex, Cond &_cond)
void *_buffer)
:AsyncInputStream(_url, _mutex, _cond, :AsyncInputStream(_url, _mutex, _cond,
_buffer, CURL_MAX_BUFFERED, HugeAllocate(CURL_MAX_BUFFERED),
CURL_MAX_BUFFERED,
CURL_RESUME_AT), CURL_RESUME_AT),
request_headers(nullptr), request_headers(nullptr),
icy(new IcyInputStream(this)) {} icy(new IcyInputStream(this)) {}
@ -844,14 +844,7 @@ inline InputStream *
CurlInputStream::Open(const char *url, Mutex &mutex, Cond &cond, CurlInputStream::Open(const char *url, Mutex &mutex, Cond &cond,
Error &error) Error &error)
{ {
void *buffer = HugeAllocate(CURL_MAX_BUFFERED); CurlInputStream *c = new CurlInputStream(url, mutex, cond);
if (buffer == nullptr) {
error.Set(curl_domain, "Out of memory");
return nullptr;
}
CurlInputStream *c = new CurlInputStream(url, mutex, cond, buffer);
if (!c->InitEasy(error) || !input_curl_easy_add_indirect(c, error)) { if (!c->InitEasy(error) || !input_curl_easy_add_indirect(c, error)) {
delete c; delete c;
return nullptr; return nullptr;

View File

@ -48,11 +48,10 @@ class NfsInputStream final : public AsyncInputStream, NfsFileReader {
bool reconnect_on_resume, reconnecting; bool reconnect_on_resume, reconnecting;
public: public:
NfsInputStream(const char *_uri, NfsInputStream(const char *_uri, Mutex &_mutex, Cond &_cond)
Mutex &_mutex, Cond &_cond,
void *_buffer)
:AsyncInputStream(_uri, _mutex, _cond, :AsyncInputStream(_uri, _mutex, _cond,
_buffer, NFS_MAX_BUFFERED, HugeAllocate(NFS_MAX_BUFFERED),
NFS_MAX_BUFFERED,
NFS_RESUME_AT), NFS_RESUME_AT),
reconnect_on_resume(false), reconnecting(false) {} reconnect_on_resume(false), reconnecting(false) {}
@ -239,13 +238,7 @@ input_nfs_open(const char *uri,
if (!StringStartsWith(uri, "nfs://")) if (!StringStartsWith(uri, "nfs://"))
return nullptr; return nullptr;
void *buffer = HugeAllocate(NFS_MAX_BUFFERED); NfsInputStream *is = new NfsInputStream(uri, mutex, cond);
if (buffer == nullptr) {
error.Set(nfs_domain, "Out of memory");
return nullptr;
}
NfsInputStream *is = new NfsInputStream(uri, mutex, cond, buffer);
if (!is->Open(error)) { if (!is->Open(error)) {
delete is; delete is;
return nullptr; return nullptr;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2013 Max Kellermann <max@duempel.org> * Copyright (C) 2013-2016 Max Kellermann <max@duempel.org>
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
@ -54,7 +54,7 @@ AlignToPageSize(size_t size)
} }
void * void *
HugeAllocate(size_t size) HugeAllocate(size_t size) throw(std::bad_alloc)
{ {
size = AlignToPageSize(size); size = AlignToPageSize(size);
@ -63,7 +63,7 @@ HugeAllocate(size_t size)
PROT_READ|PROT_WRITE, flags, PROT_READ|PROT_WRITE, flags,
-1, 0); -1, 0);
if (p == (void *)-1) if (p == (void *)-1)
return nullptr; throw std::bad_alloc();
#ifdef MADV_HUGEPAGE #ifdef MADV_HUGEPAGE
/* allow the Linux kernel to use "Huge Pages", which reduces page /* allow the Linux kernel to use "Huge Pages", which reduces page
@ -94,4 +94,19 @@ HugeDiscard(void *p, size_t size)
#endif #endif
} }
#elif defined(WIN32)
void *
HugeAllocate(size_t size) throw(std::bad_alloc)
{
// TODO: use MEM_LARGE_PAGES
void *p = VirtualAlloc(nullptr, size,
MEM_COMMIT|MEM_RESERVE,
PAGE_READWRITE);
if (p == nullptr)
throw std::bad_alloc();
return p;
}
#endif #endif

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2013 Max Kellermann <max@duempel.org> * Copyright (C) 2013-2016 Max Kellermann <max@duempel.org>
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
@ -32,6 +32,8 @@
#include "Compiler.h" #include "Compiler.h"
#include <new>
#include <stddef.h> #include <stddef.h>
#ifdef __linux__ #ifdef __linux__
@ -43,7 +45,7 @@
*/ */
gcc_malloc gcc_malloc
void * void *
HugeAllocate(size_t size); HugeAllocate(size_t size) throw(std::bad_alloc);
/** /**
* @param p an allocation returned by HugeAllocate() * @param p an allocation returned by HugeAllocate()
@ -67,14 +69,8 @@ HugeDiscard(void *p, size_t size);
#include <windows.h> #include <windows.h>
gcc_malloc gcc_malloc
static inline void * void *
HugeAllocate(size_t size) HugeAllocate(size_t size) throw(std::bad_alloc);
{
// TODO: use MEM_LARGE_PAGES
return VirtualAlloc(nullptr, size,
MEM_COMMIT|MEM_RESERVE,
PAGE_READWRITE);
}
static inline void static inline void
HugeFree(void *p, gcc_unused size_t size) HugeFree(void *p, gcc_unused size_t size)
@ -92,19 +88,20 @@ HugeDiscard(void *p, size_t size)
/* not Linux: fall back to standard C calls */ /* not Linux: fall back to standard C calls */
#include <stdlib.h> #include <stdint.h>
gcc_malloc gcc_malloc
static inline void * static inline void *
HugeAllocate(size_t size) HugeAllocate(size_t size) throw(std::bad_alloc)
{ {
return malloc(size); return new uint8_t[size];
} }
static inline void static inline void
HugeFree(void *p, size_t) HugeFree(void *_p, size_t)
{ {
free(p); auto *p = (uint8_t *)_p;
delete[] p;
} }
static inline void static inline void

View File

@ -88,13 +88,6 @@ public:
SliceBuffer(const SliceBuffer &other) = delete; SliceBuffer(const SliceBuffer &other) = delete;
SliceBuffer &operator=(const SliceBuffer &other) = delete; SliceBuffer &operator=(const SliceBuffer &other) = delete;
/**
* @return true if buffer allocation (by the constructor) has failed
*/
bool IsOOM() {
return data == nullptr;
}
unsigned GetCapacity() const { unsigned GetCapacity() const {
return n_max; return n_max;
} }