summaryrefslogtreecommitdiff
path: root/src/job-manager.c
diff options
context:
space:
mode:
authorTomas Bzatek <tbzatek@users.sourceforge.net>2009-03-28 22:00:06 +0100
committerTomas Bzatek <tbzatek@users.sourceforge.net>2009-03-28 22:00:06 +0100
commit29aeb95a28d518944f1eb268f93a96cbb9dff7f2 (patch)
tree154c8870d72229a95f0ab0bd93f8c4d3048b9f91 /src/job-manager.c
parentd9ff1192a7b5eb7defca68e90e06c68e9b986c94 (diff)
downloadcataract-29aeb95a28d518944f1eb268f93a96cbb9dff7f2.tar.xz
Multithreading support
Also made progress output a little bit nicer default = 1 thread at once, for safety reasons I've encountered critical issues with ImageMagick compiled with OpenMP support. Hope that package maintainers are clever. ShittyMagickWandGenesis(), ShittyMagickWandTerminus() :-)
Diffstat (limited to 'src/job-manager.c')
-rw-r--r--src/job-manager.c362
1 files changed, 362 insertions, 0 deletions
diff --git a/src/job-manager.c b/src/job-manager.c
new file mode 100644
index 0000000..352229b
--- /dev/null
+++ b/src/job-manager.c
@@ -0,0 +1,362 @@
+/* Cataract - Static web photo gallery generator
+ * Copyright (C) 2009 Tomas Bzatek <tbzatek@users.sourceforge.net>
+ *
+ * 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 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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <glib.h>
+
+#include <config.h>
+
+#include "setup.h"
+#include "items.h"
+#include "gallery-utils.h"
+#include "generators.h"
+
+
+
+#define DEFAULT_DATA_DIR_MODE S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH
+
+
+typedef struct {
+ TGallerySetup *setup;
+ TAlbum *items;
+ const char *dst_dir;
+} TJob;
+
+
+
+
+static void
+mirror_files (TGallerySetup *setup, char **files, const char *src_tree, const char *dst_dir, const char *label)
+{
+ char **extra;
+ char *s1, *s2, *s3;
+
+ if (files && g_strv_length (files) > 0) {
+ extra = files;
+ if (setup->verbose) printf ("%s", label);
+ while (*extra) {
+ s1 = g_strstrip (*extra);
+ if (strlen (s1) > 0) {
+ /* First create target directory if it doesn't exist */
+ s2 = g_strconcat (dst_dir, "/", s1, NULL);
+ s3 = g_path_get_dirname (s2);
+ g_free (s2);
+ if (g_mkdir_with_parents (s3, DEFAULT_DATA_DIR_MODE)) {
+ fprintf (stderr, "error making target extra directory '%s': %s\n", s3, strerror (errno));
+ g_free (s3);
+ continue;
+ }
+ g_free (s3);
+
+ /* Copy the file */
+ if (setup->verbose) printf (" %s", s1);
+ s2 = g_strconcat (src_tree, "/", s1, NULL);
+ s3 = g_strconcat (dst_dir, "/", s1, NULL);
+ copy_file (s2, s3);
+ g_free (s2);
+ g_free (s3);
+ }
+ extra++;
+ }
+ if (setup->verbose) printf ("\n");
+ }
+}
+
+
+
+
+G_LOCK_DEFINE (items);
+G_LOCK_DEFINE (items_print);
+
+/* run in a cycle, returns when all completed */
+static gpointer
+thread_func (gpointer data)
+{
+ TIndexItem *item;
+ char *imgname;
+ int i;
+ char *s1, *s2, *s3;
+ int total, index, real_index;
+ TJob *job = data;
+
+ do {
+ item = NULL;
+ total = 0;
+ real_index = -1;
+ index = -1;
+ G_LOCK (items);
+ if (job->items->items->len > 0) {
+ for (i = 0; i < job->items->items->len; i++) {
+ TIndexItem *item_tmp = g_ptr_array_index (job->items->items, i);
+ if (item_tmp == NULL) {
+ fprintf (stderr, "run_job: error getting item %d\n", i);
+ continue;
+ }
+ if (item_tmp->type == INDEX_ITEM_TYPE_PICTURE) {
+ total++;
+ if (item_tmp->gen_done == FALSE && item == NULL) {
+ item_tmp->gen_done = TRUE;
+ item = item_tmp;
+ index = total;
+ real_index = i;
+ }
+ }
+ }
+ }
+ G_UNLOCK (items);
+
+ /* actually do some work */
+ if (item != NULL) {
+ imgname = g_path_get_basename ((item->path == NULL && item->preview) ? item->preview : item->path);
+ G_LOCK (items_print);
+ if (job->setup->verbose)
+ g_print (" [%d/%d] Processing item \"%s\"\n", index, total, imgname);
+ G_UNLOCK (items_print);
+
+ generate_image (job->setup, job->items, item, real_index, job->dst_dir);
+ if (job->items->type == GALLERY_TYPE_ALBUM) {
+ s1 = g_strconcat (job->setup->real_templates_dir, "/", job->setup->template_photo, NULL);
+ s2 = g_strconcat (job->items->base_dir, "/", (item->path == NULL && item->preview) ? item->preview : item->path, NULL);
+ s3 = g_strconcat (job->dst_dir, "/", imgname, GET_EXT (job->setup->index_file_name), NULL);
+ write_html_image (job->setup, s1, s2, s3, item, job->items);
+ g_free (s1);
+ g_free (s2);
+ g_free (s3);
+ }
+ g_free (imgname);
+ }
+
+ } while (item != NULL);
+ return NULL;
+}
+
+
+
+/*
+ * build_tree: generate complete gallery tree based on source xml files
+ *
+ * src_tree = source directory of the items
+ * dst_dir = destination of the generated items
+ * parent_index = parent album to determine our descent in the tree
+ *
+ */
+gboolean
+build_tree (TGallerySetup *setup,
+ const char *src_tree,
+ const char *dst_dir,
+ TAlbum *parent_index,
+ int parent_item_index,
+ int jobs)
+{
+ char *idx_file;
+ TAlbum *items;
+ TIndexItem *item;
+ char *s1, *s2, *s3;
+ char *thumb_dir;
+ char *img_big_dir;
+ char *img_orig_dir;
+ char *template;
+ gboolean res;
+ int i;
+ TJob *job;
+ GError *error;
+ GThread *thread;
+ GList *thread_list;
+
+ printf ("Processing directory \"%s\"\n", src_tree);
+ #ifdef __DEBUG_ALL__
+ printf ("setup->real_templates_dir = %s\n", setup->real_templates_dir);
+ #endif
+
+ /* Check access permissions */
+ if (access (src_tree, R_OK)) {
+ fprintf (stderr, "error accessing source directory: %s\n", strerror (errno));
+ return FALSE;
+ }
+ if (access (dst_dir, R_OK | W_OK | X_OK)) {
+ if (g_mkdir_with_parents (dst_dir, DEFAULT_DATA_DIR_MODE)) {
+ fprintf (stderr, "error creating destination directory: %s\n", strerror (errno));
+ return FALSE;
+ }
+ }
+
+ /* Check the index file */
+ idx_file = g_strconcat (src_tree, "/index.xml", NULL);
+ if (access (idx_file, R_OK)) {
+ fprintf (stderr, "error accessing index file '%s': %s\n", idx_file, strerror (errno));
+ g_free (idx_file);
+ return FALSE;
+ }
+
+ /* Read the index file and fill items array */
+ items = malloc (sizeof (TAlbum));
+ memset (items, 0, sizeof (TAlbum));
+ if (! parse_album_xml (idx_file, items)) {
+ fprintf (stderr, "error reading index file '%s'\n", idx_file);
+ g_free (idx_file);
+ free_album_data (items);
+ return FALSE;
+ }
+ g_free (idx_file);
+ items->parent_index = parent_index;
+ items->parent_item_index = parent_item_index;
+
+ /* Copy support files */
+ if (! setup->support_files_use_common_root || parent_index == NULL) {
+ /* copy only if we're in root level or old-style is active */
+ mirror_files (setup, setup->template_files, setup->real_templates_dir, dst_dir, " Copying template files: ");
+
+ /* favicon */
+ if (setup->favicon_file && strlen (setup->favicon_file) > 0) {
+ if (setup->verbose) printf (" Copying favicon: %s\n", setup->favicon_file);
+ s3 = g_path_get_dirname (setup->setup_xml_path);
+ s1 = g_strconcat (s3, "/", setup->favicon_file, NULL);
+ s2 = g_strconcat (dst_dir, "/", setup->favicon_file, NULL);
+ copy_file (s1, s2);
+ g_free (s1);
+ g_free (s2);
+ g_free (s3);
+ }
+ }
+
+ /* Prepare target thumbnail directory */
+ thumb_dir = g_strconcat (dst_dir, "/", THUMBNAIL_DIR, NULL);
+ if (access (thumb_dir, R_OK | W_OK | X_OK))
+ if (g_mkdir_with_parents (thumb_dir, DEFAULT_DATA_DIR_MODE)) {
+ fprintf (stderr, "error making target thumbnail directory: %s\n", strerror (errno));
+ g_free (thumb_dir);
+ free_album_data (items);
+ return FALSE;
+ }
+ g_free (thumb_dir);
+
+ /* Prepare target preview and orig directories */
+ if (items->type == GALLERY_TYPE_ALBUM)
+ {
+ res = TRUE;
+ img_big_dir = g_strconcat (dst_dir, "/", IMG_BIG_DIR, NULL);
+ img_orig_dir = g_strconcat (dst_dir, "/", IMG_ORIG_DIR, NULL);
+ if (access (img_big_dir, R_OK | W_OK | X_OK))
+ if (g_mkdir_with_parents (img_big_dir, DEFAULT_DATA_DIR_MODE)) {
+ fprintf (stderr, "error making target preview directory: %s\n", strerror (errno));
+ res = FALSE;
+ }
+ if (access (img_orig_dir, R_OK | W_OK | X_OK))
+ if (g_mkdir_with_parents (img_orig_dir, DEFAULT_DATA_DIR_MODE)) {
+ fprintf (stderr, "error making target full size directory: %s\n", strerror (errno));
+ res = FALSE;
+ }
+ g_free (img_big_dir);
+ g_free (img_orig_dir);
+ if (! res) {
+ free_album_data (items);
+ return FALSE;
+ }
+ }
+
+ /* Generate images + particular html pages */
+ job = g_new0 (TJob, 1);
+ job->items = items;
+ job->setup = setup;
+ job->dst_dir = dst_dir;
+
+#ifdef G_THREADS_ENABLED
+ thread_list = NULL;
+
+ for (i = 0; i < jobs; i++)
+ {
+ error = NULL;
+ thread = g_thread_create (thread_func, job, TRUE, &error);
+ if (thread)
+ thread_list = g_list_append (thread_list, thread);
+ if (error) {
+ fprintf (stderr, "build_tree: error starting new thread: %s\n", error->message);
+ g_clear_error (&error);
+ }
+ }
+
+ /* wait for threads are finished */
+ GList *l;
+ for (l = thread_list; l != NULL; l = l->next) {
+ g_thread_join (l->data);
+ }
+ /* TODO: free threads? */
+ g_list_free (thread_list);
+
+#else /* threads are disabled */
+ thread_func (job);
+#endif
+ g_free (job);
+
+
+ /* Start generating items */
+ if (items->type == GALLERY_TYPE_INDEX)
+ template = g_strconcat ("/", setup->template_index, NULL);
+ else
+ if (items->type == GALLERY_TYPE_ALBUM)
+ template = g_strconcat ("/", setup->template_album, NULL);
+ else
+ /* default to album */
+ template = g_strconcat ("/", setup->template_album, NULL);
+
+ if (setup->verbose) printf (" Writing %s\n", setup->index_file_name);
+ s1 = g_strconcat (setup->real_templates_dir, template, NULL);
+ s2 = g_strconcat (dst_dir, "/", setup->index_file_name, NULL);
+ res = write_html_album (setup, s1, s2, items);
+ g_free (s1);
+ g_free (s2);
+ g_free (template);
+ if (! res) {
+ fprintf (stderr, "error generating target index file\n");
+ free_album_data (items);
+ return FALSE;
+ }
+
+
+ /* Recurse to sub-albums (in case of album index) */
+ if (items->type == GALLERY_TYPE_INDEX)
+ {
+ if (items->items->len > 0) {
+ for (i = 0; i < items->items->len; i++) {
+ item = g_ptr_array_index (items->items, i);
+ if (item == NULL) {
+ fprintf (stderr, "build_tree: error getting item %d\n", i);
+ continue;
+ }
+ if (item->type == INDEX_ITEM_TYPE_PICTURE) {
+ s1 = g_strconcat (src_tree, "/", item->path, "/", NULL);
+ s2 = g_strconcat (dst_dir, "/", item->path, "/", NULL);
+ build_tree (setup, s1, s2, items, i, jobs);
+ g_free (s1);
+ g_free (s2);
+ }
+ }
+ }
+ }
+
+ /* Copy extra files */
+ mirror_files (setup, items->extra_files, src_tree, dst_dir, " Copying extra files: ");
+
+ free_album_data (items);
+ return TRUE;
+}