/* Swfdec
 * Copyright (C) 2007 Benjamin Otte <otte@gnome.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library 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
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
 * Boston, MA  02110-1301  USA
 */

/* build with:
 * gcc -Wall `pkg-config --libs --cflags swfdec-0.5` crash-tester.c -o crash-tester
 */

#include <libswfdec/swfdec.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#define N_FORKS 128
static pid_t pids[N_FORKS] = { 0, };
static guint use_mem_count = 0;
static gboolean aborted = FALSE;

static void
cleanup (guint from, guint to)
{
  guint i;
  int status;

  for (i = from; i < to; i++) {
    pid_t *pid = &pids[i % N_FORKS];
    waitpid (*pid, &status, 0);
    if (!WIFEXITED (status)) {
      g_print ("ERROR: %u\n", i);
#if 0
    } else {
      g_print ("OK: %u\n", i);
#endif
    }
  }
}

/* FIXME: use dlopen to get the real address */
gboolean
swfdec_as_context_use_mem (SwfdecAsContext *context, gsize bytes)
{
  g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context), FALSE);
  g_return_val_if_fail (bytes > 0, FALSE);

  if (context->state == SWFDEC_AS_CONTEXT_ABORTED)
    return FALSE;
  
  if (context->state != SWFDEC_AS_CONTEXT_NEW) {
    pid_t *pid = &pids[use_mem_count % N_FORKS];

    if ((use_mem_count % (N_FORKS / 2)) == 0 &&
	use_mem_count >= N_FORKS)
      cleanup (use_mem_count - N_FORKS, use_mem_count - N_FORKS / 2);
    use_mem_count++;
fork_again:
    *pid = fork ();
    if (*pid == 0) {
      aborted = TRUE;
      swfdec_as_context_abort (context, "No abort, no fun");
      return FALSE;
    }
    if (pid < 0) {
      g_print ("fork failed. Waiting 1 second and trying again...\n");
      g_usleep (G_USEC_PER_SEC);
      goto fork_again;
    }
  }

  context->memory += bytes;
  context->memory_since_gc += bytes;
  /* FIXME: Don't foget to abort on OOM */
  return TRUE;
}

int
main (int argc, char **argv)
{
  SwfdecPlayer *player;

  g_log_set_always_fatal (G_LOG_FATAL_MASK | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING);
  g_setenv ("SWFDEC_DEBUG", "0", FALSE);

  swfdec_init ();

  if (argc < 2) {
    g_print ("usage: %s SWF\n", argv[0]);
    return 1;
  }

  player = swfdec_player_new_from_file (argv[1]);
  g_rand_set_seed (SWFDEC_AS_CONTEXT (player)->rand, 0);
  swfdec_player_advance (player, 10 * 1000);
  g_object_unref (player);
  if (!aborted) {
    guint round_up = use_mem_count + N_FORKS / 2 - 1;
    round_up -= round_up % (N_FORKS / 2);
    cleanup (MAX (round_up, N_FORKS) - N_FORKS, use_mem_count);
    g_print ("DONE: %u memory allocations total\n", use_mem_count);
    if (use_mem_count == 0) {
      g_print ("Warning: No allocations seem to have happened. The reason for "
	       "this is probably, that your Swfdec was linked using -Bsymbolic, "
	       "which doesn't allow overriding functions. In that case you need "
	       "to rebuild the Swfdec library using a command such as:\n"
	       "  make clean && make SYMBOLIC_LDFLAGS= && sudo make install\n"
	       "in your Swfdec build repository.");
    }
  }
  return 0;
}

