>> Sorry, but I'm confused, mysql_free_result(res); does free the result, doesn't it? <<

Yep, but you have:
Code:
    if(!res)
        mysql_free_result(res);
which is equivalent to:
Code:
    if(res == NULL)
        mysql_free_result(res);
and if res is NULL, there is nothing to free. I think this is just a typo on your behalf.

>> And row is already stored, so freeing the actual result won't matter. I'm assuming so because MYSQL_ROW is an array, so freeing where it came from won't matter, unless I'm wrong, which is quite possible :P <<

MYSQL_ROW is a pointer to an array of pointers. As far as I can tell, these pointers reference memory controlled by the MYSQL_RES. When you free the result set you free all the rows and data in the result set.
The MySql manual rather ambiguously says:
Do not attempt to access a result set after freeing it.
Otherwise, you would have to free each row seperately.
--
Can you run something like below and see what is going on:
Code:
struct timeval tod;

gettimeofday(&tod, NULL);
printf("before: %d.%d\n", tod.tv_sec, tod.tv_usec);

	for(t = alltimers; t; t = t->next) {
		if((int)(t->lastrun + t->interval) <= curTime) {
			printf("Running %s\n", t->name);

			i = t->func(t->row, t->ch);
//			x = t->times - 1;
			x = t->times;
			if(!i || (t->times && x && t->run && (t->run >= x)))
				timer_del(t);
			else {
				t->lastrun = curTime;
				t->run++;
			}
		}
		else
		{
			printf("Not running %s. lastrun=%d, curTime=%d\n", t->name, t->lastrun, curTime);
		}
	}

gettimeofday(&tod, NULL);
printf("after: %d.%d\n", tod.tv_sec, tod.tv_usec);