From fe3f0332f71258354b70e5db685b56934f0df703 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 30 Jan 2013 09:18:52 +0100 Subject: page: convert to C++ --- Makefile.am | 5 +- src/IcyMetaDataServer.cxx | 7 ++- src/IcyMetaDataServer.hxx | 4 +- src/Page.cxx | 70 ++++++++++++++++++++++++++ src/Page.hxx | 104 +++++++++++++++++++++++++++++++++++++++ src/output/HttpdClient.cxx | 49 +++++++++--------- src/output/HttpdClient.hxx | 16 +++--- src/output/HttpdInternal.hxx | 8 +-- src/output/HttpdOutputPlugin.cxx | 22 ++++----- src/page.c | 89 --------------------------------- src/page.h | 102 -------------------------------------- 11 files changed, 229 insertions(+), 247 deletions(-) create mode 100644 src/Page.cxx create mode 100644 src/Page.hxx delete mode 100644 src/page.c delete mode 100644 src/page.h diff --git a/Makefile.am b/Makefile.am index c14ff2ed8..e2977a438 100644 --- a/Makefile.am +++ b/Makefile.am @@ -92,7 +92,6 @@ mpd_headers = \ src/AudioCompress/config.h \ src/AudioCompress/compress.h \ src/open.h \ - src/page.h \ src/Playlist.hxx \ src/playlist_error.h \ src/poison.h \ @@ -218,7 +217,7 @@ src_mpd_SOURCES = \ src/MusicPipe.cxx src/MusicPipe.hxx \ src/MusicChunk.cxx src/MusicChunk.hxx \ src/Mapper.cxx src/Mapper.hxx \ - src/page.c \ + src/Page.cxx src/Page.hxx \ src/Partition.hxx \ src/Permission.cxx src/Permission.hxx \ src/PlayerThread.cxx src/PlayerThread.hxx \ @@ -1325,7 +1324,7 @@ test_run_output_SOURCES = test/run_output.cxx \ src/audio_parser.c \ src/timer.c src/clock.c \ src/Tag.cxx src/TagNames.c src/TagPool.cxx \ - src/page.c \ + src/Page.cxx \ src/SocketUtil.cxx \ src/resolver.c \ src/OutputInit.cxx src/OutputFinish.cxx src/OutputList.cxx \ diff --git a/src/IcyMetaDataServer.cxx b/src/IcyMetaDataServer.cxx index e7bd0acf4..b1d075582 100644 --- a/src/IcyMetaDataServer.cxx +++ b/src/IcyMetaDataServer.cxx @@ -19,7 +19,7 @@ #include "config.h" #include "IcyMetaDataServer.hxx" -#include "page.h" +#include "Page.hxx" #include "tag.h" #include @@ -86,14 +86,13 @@ icy_server_metadata_string(const char *stream_title, const char* stream_url) return icy_metadata; } -struct page* +Page * icy_server_metadata_page(const struct tag *tag, const enum tag_type *types) { const gchar *tag_items[TAG_NUM_OF_ITEM_TYPES]; gint last_item, item; guint position; gchar *icy_string; - struct page *icy_metadata; gchar stream_title[(1 + 255 - 28) * 16]; // Length + Metadata - // "StreamTitle='';StreamUrl='';" // = 4081 - 28 @@ -131,7 +130,7 @@ icy_server_metadata_page(const struct tag *tag, const enum tag_type *types) if (icy_string == NULL) return NULL; - icy_metadata = page_new_copy(icy_string, (icy_string[0] * 16) + 1); + Page *icy_metadata = Page::Copy(icy_string, (icy_string[0] * 16) + 1); g_free(icy_string); diff --git a/src/IcyMetaDataServer.hxx b/src/IcyMetaDataServer.hxx index 78f1be7db..b344c61f2 100644 --- a/src/IcyMetaDataServer.hxx +++ b/src/IcyMetaDataServer.hxx @@ -22,12 +22,14 @@ #include "tag.h" +class Page; + char* icy_server_metadata_header(const char *name, const char *genre, const char *url, const char *content_type, int metaint); -struct page* +Page * icy_server_metadata_page(const struct tag *tag, const enum tag_type *types); #endif diff --git a/src/Page.cxx b/src/Page.cxx new file mode 100644 index 000000000..bf30376e4 --- /dev/null +++ b/src/Page.cxx @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2003-2011 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "Page.hxx" + +#include + +#include + +#include +#include + +Page * +Page::Create(size_t size) +{ + void *p = g_malloc(sizeof(Page) + size - + sizeof(Page::data)); + return ::new(p) Page(size); +} + +Page * +Page::Copy(const void *data, size_t size) +{ + assert(data != nullptr); + + Page *page = Create(size); + memcpy(page->data, data, size); + return page; +} + +Page * +Page::Concat(const Page &a, const Page &b) +{ + Page *page = Create(a.size + b.size); + + memcpy(page->data, a.data, a.size); + memcpy(page->data + a.size, b.data, b.size); + + return page; +} + +bool +Page::Unref() +{ + bool unused = ref.Decrement(); + + if (unused) { + this->Page::~Page(); + g_free(this); + } + + return unused; +} diff --git a/src/Page.hxx b/src/Page.hxx new file mode 100644 index 000000000..2bc9a6ac5 --- /dev/null +++ b/src/Page.hxx @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2003-2011 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/** \file + * + * This is a library which manages reference counted buffers. + */ + +#ifndef MPD_PAGE_HXX +#define MPD_PAGE_HXX + +#include "util/RefCount.hxx" + +#include + +#include + +/** + * A dynamically allocated buffer which keeps track of its reference + * count. This is useful for passing buffers around, when several + * instances hold references to one buffer. + */ +class Page { + /** + * The number of references to this buffer. This library uses + * atomic functions to access it, i.e. no locks are required. + * As soon as this attribute reaches zero, the buffer is + * freed. + */ + RefCount ref; + +public: + /** + * The size of this buffer in bytes. + */ + const size_t size; + + /** + * Dynamic array containing the buffer data. + */ + unsigned char data[sizeof(long)]; + +protected: + Page(size_t _size):size(_size) {} + ~Page() = default; + + /** + * Allocates a new #Page object, without filling the data + * element. + */ + static Page *Create(size_t size); + +public: + /** + * Creates a new #page object, and copies data from the + * specified buffer. It is initialized with a reference count + * of 1. + * + * @param data the source buffer + * @param size the size of the source buffer + */ + static Page *Copy(const void *data, size_t size); + + /** + * Concatenates two pages to a new page. + * + * @param a the first page + * @param b the second page, which is appended + */ + static Page *Concat(const Page &a, const Page &b); + + /** + * Increases the reference counter. + */ + void Ref() { + ref.Increment(); + } + + /** + * Decreases the reference counter. If it reaches zero, the #page is + * freed. + * + * @return true if the #page has been freed + */ + bool Unref(); +}; + +#endif diff --git a/src/output/HttpdClient.cxx b/src/output/HttpdClient.cxx index 5ac3bf7cc..dd2f44fa0 100644 --- a/src/output/HttpdClient.cxx +++ b/src/output/HttpdClient.cxx @@ -21,7 +21,7 @@ #include "HttpdClient.hxx" #include "HttpdInternal.hxx" #include "util/fifo_buffer.h" -#include "page.h" +#include "Page.hxx" #include "IcyMetaDataServer.hxx" #include "glib_socket.h" @@ -38,15 +38,15 @@ HttpdClient::~HttpdClient() g_source_remove(write_source_id); if (current_page != nullptr) - page_unref(current_page); + current_page->Unref(); for (auto page : pages) - page_unref(page); + page->Unref(); } else fifo_buffer_free(input); if (metadata) - page_unref(metadata); + metadata->Unref(); g_source_remove(read_source_id); g_io_channel_unref(channel); @@ -379,7 +379,7 @@ HttpdClient::CancelQueue() return; for (auto page : pages) - page_unref(page); + page->Unref(); pages.clear(); if (write_source_id != 0 && current_page == nullptr) { @@ -390,36 +390,34 @@ HttpdClient::CancelQueue() static GIOStatus write_page_to_channel(GIOChannel *channel, - const struct page *page, size_t position, + const Page &page, size_t position, gsize *bytes_written_r, GError **error) { assert(channel != nullptr); - assert(page != nullptr); - assert(position < page->size); + assert(position < page.size); return g_io_channel_write_chars(channel, - (const gchar*)page->data + position, - page->size - position, + (const gchar*)page.data + position, + page.size - position, bytes_written_r, error); } static GIOStatus -write_n_bytes_to_channel(GIOChannel *channel, const struct page *page, +write_n_bytes_to_channel(GIOChannel *channel, const Page &page, size_t position, gint n, gsize *bytes_written_r, GError **error) { GIOStatus status; assert(channel != nullptr); - assert(page != nullptr); - assert(position < page->size); + assert(position < page.size); if (n == -1) { status = write_page_to_channel (channel, page, position, bytes_written_r, error); } else { status = g_io_channel_write_chars(channel, - (const gchar*)page->data + position, + (const gchar*)page.data + position, n, bytes_written_r, error); } @@ -466,7 +464,7 @@ HttpdClient::Write() if (!metadata_sent) { status = write_page_to_channel(channel, - metadata, + *metadata, metadata_to_write, &bytes_written, &error); @@ -478,13 +476,12 @@ HttpdClient::Write() metadata_sent = true; } } else { - struct page *empty_meta; guchar empty_data = 0; - empty_meta = page_new_copy(&empty_data, 1); + Page *empty_meta = Page::Copy(&empty_data, 1); status = write_page_to_channel(channel, - empty_meta, + *empty_meta, metadata_to_write, &bytes_written, &error); @@ -494,11 +491,13 @@ HttpdClient::Write() metadata_fill = 0; metadata_current_position = 0; } + + empty_meta->Unref(); } bytes_written = 0; } else { - status = write_n_bytes_to_channel(channel, current_page, + status = write_n_bytes_to_channel(channel, *current_page, current_position, bytes_to_write, &bytes_written, &error); } @@ -512,7 +511,7 @@ HttpdClient::Write() metadata_fill += bytes_written; if (current_position >= current_page->size) { - page_unref(current_page); + current_page->Unref(); current_page = nullptr; if (pages.empty()) { @@ -561,13 +560,13 @@ httpd_client_out_event(gcc_unused GIOChannel *source, } void -HttpdClient::PushPage(struct page *page) +HttpdClient::PushPage(Page *page) { if (state != RESPONSE) /* the client is still writing the HTTP request */ return; - page_ref(page); + page->Ref(); pages.push_back(page); if (write_source_id == 0) @@ -577,16 +576,16 @@ HttpdClient::PushPage(struct page *page) } void -HttpdClient::PushMetaData(struct page *page) +HttpdClient::PushMetaData(Page *page) { if (metadata) { - page_unref(metadata); + metadata->Unref(); metadata = nullptr; } g_return_if_fail (page); - page_ref(page); + page->Ref(); metadata = page; metadata_sent = false; } diff --git a/src/output/HttpdClient.hxx b/src/output/HttpdClient.hxx index 8fb7c8b28..1dd4eead1 100644 --- a/src/output/HttpdClient.hxx +++ b/src/output/HttpdClient.hxx @@ -29,7 +29,7 @@ #include struct HttpdOutput; -struct page; +class Page; class HttpdClient final { /** @@ -76,14 +76,14 @@ class HttpdClient final { } state; /** - * A queue of #page objects to be sent to the client. + * A queue of #Page objects to be sent to the client. */ - std::list pages; + std::list pages; /** * The #page which is currently being sent to the client. */ - page *current_page; + Page *current_page; /** * The amount of bytes which were already sent from @@ -120,9 +120,9 @@ class HttpdClient final { guint metaint; /** - * The metadata as #page which is currently being sent to the client. + * The metadata as #Page which is currently being sent to the client. */ - page *metadata; + Page *metadata; /* * The amount of bytes which were already sent from the metadata. @@ -204,12 +204,12 @@ public: /** * Appends a page to the client's queue. */ - void PushPage(page *page); + void PushPage(Page *page); /** * Sends the passed metadata. */ - void PushMetaData(page *page); +void PushMetaData(Page *page); }; #endif diff --git a/src/output/HttpdInternal.hxx b/src/output/HttpdInternal.hxx index 1c2fdfb16..702f4ad3d 100644 --- a/src/output/HttpdInternal.hxx +++ b/src/output/HttpdInternal.hxx @@ -85,12 +85,12 @@ struct HttpdOutput { /** * The header page, which is sent to every client on connect. */ - struct page *header; + Page *header; /** * The metadata, which is sent to every client. */ - struct page *metadata; + Page *metadata; /** * The configured name. @@ -178,14 +178,14 @@ struct HttpdOutput { * Reads data from the encoder (as much as available) and * returns it as a new #page object. */ - page *ReadPage(); + Page *ReadPage(); /** * Broadcasts a page struct to all clients. * * Mutext must not be locked. */ - void BroadcastPage(struct page *page); + void BroadcastPage(Page *page); /** * Broadcasts data from the encoder to all clients. diff --git a/src/output/HttpdOutputPlugin.cxx b/src/output/HttpdOutputPlugin.cxx index 52b2e0e8d..a9b27c483 100644 --- a/src/output/HttpdOutputPlugin.cxx +++ b/src/output/HttpdOutputPlugin.cxx @@ -25,7 +25,7 @@ #include "encoder_plugin.h" #include "encoder_list.h" #include "resolver.h" -#include "page.h" +#include "Page.hxx" #include "IcyMetaDataServer.hxx" #include "fd_util.h" #include "ServerSocket.hxx" @@ -156,7 +156,7 @@ httpd_output_finish(struct audio_output *ao) HttpdOutput *httpd = (HttpdOutput *)ao; if (httpd->metadata) - page_unref(httpd->metadata); + httpd->metadata->Unref(); encoder_finish(httpd->encoder); server_socket_free(httpd->server_socket); @@ -230,7 +230,7 @@ httpd_listen_in_event(int fd, const struct sockaddr *address, } } -struct page * +Page * HttpdOutput::ReadPage() { if (unflushed_input >= 65536) { @@ -257,7 +257,7 @@ HttpdOutput::ReadPage() if (size == 0) return NULL; - return page_new_copy(buffer, size); + return Page::Copy(buffer, size); } static bool @@ -337,7 +337,7 @@ HttpdOutput::Close() clients.clear(); if (header != NULL) - page_unref(header); + header->Unref(); encoder_close(encoder); } @@ -398,7 +398,7 @@ httpd_output_delay(struct audio_output *ao) } void -HttpdOutput::BroadcastPage(struct page *page) +HttpdOutput::BroadcastPage(Page *page) { assert(page != NULL); @@ -419,10 +419,10 @@ HttpdOutput::BroadcastFromEncoder() } mutex.unlock(); - struct page *page; + Page *page; while ((page = ReadPage()) != nullptr) { BroadcastPage(page); - page_unref(page); + page->Unref(); } } @@ -492,10 +492,10 @@ HttpdOutput::SendTag(const struct tag *tag) used as the new "header" page, which is sent to all new clients */ - struct page *page = ReadPage(); + Page *page = ReadPage(); if (page != NULL) { if (header != NULL) - page_unref(header); + header->Unref(); header = page; BroadcastPage(page); } @@ -503,7 +503,7 @@ HttpdOutput::SendTag(const struct tag *tag) /* use Icy-Metadata */ if (metadata != NULL) - page_unref(metadata); + metadata->Unref(); static constexpr tag_type types[] = { TAG_ALBUM, TAG_ARTIST, TAG_TITLE, diff --git a/src/page.c b/src/page.c deleted file mode 100644 index e2e22791f..000000000 --- a/src/page.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2003-2011 The Music Player Daemon Project - * http://www.musicpd.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "config.h" -#include "page.h" - -#include - -#include -#include - -/** - * Allocates a new #page object, without filling the data element. - */ -static struct page * -page_new(size_t size) -{ - struct page *page = g_malloc(sizeof(*page) + size - - sizeof(page->data)); - - assert(size > 0); - - page->ref = 1; - page->size = size; - return page; -} - -struct page * -page_new_copy(const void *data, size_t size) -{ - struct page *page = page_new(size); - - assert(data != NULL); - - memcpy(page->data, data, size); - return page; -} - -struct page * -page_new_concat(const struct page *a, const struct page *b) -{ - struct page *page = page_new(a->size + b->size); - - memcpy(page->data, a->data, a->size); - memcpy(page->data + a->size, b->data, b->size); - - return page; -} - -void -page_ref(struct page *page) -{ - g_atomic_int_inc(&page->ref); -} - -static void -page_free(struct page *page) -{ - assert(page->ref == 0); - - g_free(page); -} - -bool -page_unref(struct page *page) -{ - bool unused = g_atomic_int_dec_and_test(&page->ref); - - if (unused) - page_free(page); - - return unused; -} diff --git a/src/page.h b/src/page.h deleted file mode 100644 index 8629298cd..000000000 --- a/src/page.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2003-2011 The Music Player Daemon Project - * http://www.musicpd.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -/** \file - * - * This is a library which manages reference counted buffers. - */ - -#ifndef MPD_PAGE_H -#define MPD_PAGE_H - -#include -#include - -/** - * A dynamically allocated buffer which keeps track of its reference - * count. This is useful for passing buffers around, when several - * instances hold references to one buffer. - */ -struct page { - /** - * The number of references to this buffer. This library uses - * atomic functions to access it, i.e. no locks are required. - * As soon as this attribute reaches zero, the buffer is - * freed. - */ - int ref; - - /** - * The size of this buffer in bytes. - */ - size_t size; - - /** - * Dynamic array containing the buffer data. - */ - unsigned char data[sizeof(long)]; -}; - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Creates a new #page object, and copies data from the specified - * buffer. It is initialized with a reference count of 1. - * - * @param data the source buffer - * @param size the size of the source buffer - * @return the new #page object - */ -struct page * -page_new_copy(const void *data, size_t size); - -/** - * Concatenates two pages to a new page. - * - * @param a the first page - * @param b the second page, which is appended - */ -struct page * -page_new_concat(const struct page *a, const struct page *b); - -/** - * Increases the reference counter. - * - * @param page the #page object - */ -void -page_ref(struct page *page); - -/** - * Decreases the reference counter. If it reaches zero, the #page is - * freed. - * - * @param page the #page object - * @return true if the #page has been freed - */ -bool -page_unref(struct page *page); - -#ifdef __cplusplus -} -#endif - -#endif -- cgit v1.2.3