diff --git a/ecrire/action/editer_site.php b/ecrire/action/editer_site.php
index 3555441a11d4c68815b4cae9924158ccc8654c97..6767215ff920dfdcd7c3f20d66e672aace20ddf9 100644
--- a/ecrire/action/editer_site.php
+++ b/ecrire/action/editer_site.php
@@ -107,8 +107,12 @@ function action_editer_site_dist() {
 	}
 
 	if ($resyndiquer) {
-		include_spip('inc/syndic');
-		syndic_a_jour($id_syndic);
+	  // ah si PHP connaisait les fermetures...
+	  // Cette globale est utilisee exclusivement dans la fct suivante.
+		$GLOBALS['genie_syndic_now'] = $id_syndic;
+		// forcer l'execution immediate de cette tache
+		// (i.e. appeler la fct suivante avec gestion du verrou)
+		cron(0, array('syndic' => -91));
 	}
 	// Rediriger le navigateur
 	$redirect = parametre_url(urldecode(_request('redirect')),
diff --git a/ecrire/genie/syndic.php b/ecrire/genie/syndic.php
index bc4ef2e0fc9163555c03ff0af10f9f10f38b239a..55cdbc2a6c748b421f0cf79177393dfed88ee330 100644
--- a/ecrire/genie/syndic.php
+++ b/ecrire/genie/syndic.php
@@ -11,11 +11,218 @@
 \***************************************************************************/
 
 if (!defined("_ECRIRE_INC_VERSION")) return;
-
 include_spip('inc/syndic');
 
 function genie_syndic_dist($t) {
+	define('_GENIE_SYNDIC', 1); // pour message de compatibilite ci-dessous
 	return executer_une_syndication();
 }
 
+//
+// Effectuer la syndication d'un unique site,
+// retourne 0 si aucun a faire ou echec lors de la tentative
+//
+
+// http://doc.spip.org/@executer_une_syndication
+function executer_une_syndication() {
+
+	spip_connect();
+
+	## valeurs modifiables dans mes_options
+	## attention il est tres mal vu de prendre une periode < 20 minutes
+	define('_PERIODE_SYNDICATION', 2*60);
+	define('_PERIODE_SYNDICATION_SUSPENDUE', 24*60);
+
+	// On va tenter un site 'sus' ou 'off' de plus de 24h, et le passer en 'off'
+	// s'il echoue
+	$where = "syndication IN ('sus','off')
+	AND statut='publie'
+	AND date_syndic < DATE_SUB(NOW(), INTERVAL
+	"._PERIODE_SYNDICATION_SUSPENDUE." MINUTE)";
+	$row = sql_fetch(sql_select("id_syndic", "spip_syndic", $where, '', "date_syndic", "1"));
+	if ($row) {
+		$id_syndic = $row["id_syndic"];
+		$res1 = syndic_a_jour($id_syndic, 'off');
+	} else $res1 = true;
+
+	// Et un site 'oui' de plus de 2 heures, qui passe en 'sus' s'il echoue
+	$where = "syndication='oui'
+	AND statut='publie'
+	AND date_syndic < DATE_SUB(NOW(), INTERVAL "._PERIODE_SYNDICATION." MINUTE)";
+	$row = sql_fetch(sql_select("id_syndic", "spip_syndic", $where, '', "date_syndic", "1"));
+
+	if ($row) {
+		$id_syndic = $row["id_syndic"];
+		$res2 = syndic_a_jour($id_syndic, 'sus');
+	} else $res2 = true;
+
+	return ($res1 OR $res2) ? 0 : $id_syndic;
+}
+
+
+//
+// Mettre a jour le site
+//
+// Attention, cette fonction ne doit pas etre appellee simultanement
+// sur un meme site: un verrouillage a du etre pose en amont.
+//
+
+// http://doc.spip.org/@syndic_a_jour
+function syndic_a_jour($now_id_syndic, $statut = 'off') {
+	include_spip('inc/texte');
+	if (!defined('_GENIE_SYNDIC'))
+		spip_log("syndic_a_jour doit etre appelee par Cron. Cf. " .
+			 "http://trac.rezo.net/trac/spip/changeset/10294",
+			 'vieilles_defs');
+	$result = spip_query("SELECT * FROM spip_syndic WHERE id_syndic=$now_id_syndic");
+
+	if (!$row = sql_fetch($result))
+		return;
+
+	$url_syndic = $row['url_syndic'];
+	$url_site = $row['url_site'];
+
+	if ($row['moderation'] == 'oui')
+		$moderation = 'dispo';	// a valider
+	else
+		$moderation = 'publie';	// en ligne sans validation
+
+	spip_query("UPDATE spip_syndic SET syndication='$statut', date_syndic=NOW() WHERE id_syndic=$now_id_syndic");
+
+	// Aller chercher les donnees du RSS et les analyser
+	include_spip('inc/distant');
+	$rss = recuperer_page($url_syndic, true);
+	if (!$rss)
+		$articles = _T('avis_echec_syndication_02');
+	else
+		$articles = analyser_backend($rss, $url_syndic);
+
+	// Renvoyer l'erreur le cas echeant
+	if (!is_array($articles)) return $articles;
+
+	// Les enregistrer dans la base
+
+	$faits = array();
+	foreach ($articles as $data) {
+		inserer_article_syndique ($data, $now_id_syndic, $moderation, $url_site, $url_syndic, $row['resume'], $row['documents'], $faits);
+	}
+
+	// moderation automatique des liens qui sont sortis du feed
+	if (count($faits) > 0) {
+		$faits = join(",", $faits);
+		if ($row['miroir'] == 'oui') {
+			spip_query("UPDATE spip_syndic_articles	SET statut='off', maj=maj WHERE id_syndic=$now_id_syndic AND NOT (id_syndic_article IN ($faits))");
+		}
+	// suppression apres 2 mois des liens qui sont sortis du feed
+		if ($row['oubli'] == 'oui') {
+
+			sql_delete('spip_syndic_articles', "id_syndic=$now_id_syndic AND maj < DATE_SUB(NOW(), INTERVAL 2 MONTH) AND date < DATE_SUB(NOW(), INTERVAL 2 MONTH) AND NOT (id_syndic_article IN ($faits))");
+		}
+	}
+
+	// Noter que la syndication est OK
+	spip_query("UPDATE spip_syndic SET syndication='oui' WHERE id_syndic=$now_id_syndic");
+
+	return false; # c'est bon
+}
+
+
+//
+// Insere un article syndique (renvoie true si l'article est nouveau)
+//
+// http://doc.spip.org/@inserer_article_syndique
+function inserer_article_syndique ($data, $now_id_syndic, $statut, $url_site, $url_syndic, $resume, $documents, &$faits) {
+	// Creer le lien s'il est nouveau - cle=(id_syndic,url)
+	// On coupe a 255 caracteres pour eviter tout doublon
+	// sur une URL de plus de 255 qui exloserait la base de donnees
+	$le_lien = substr($data['url'], 0,255);
+
+	// Chercher les liens de meme cle
+	$s = spip_query("SELECT id_syndic_article,titre FROM spip_syndic_articles WHERE url=" . _q($le_lien) . " AND id_syndic=$now_id_syndic ORDER BY maj DESC");
+
+	// S'il y a plusieurs liens qui repondent, il faut choisir le plus proche
+	// (ie meme titre et pas deja fait), le mettre a jour et ignorer les autres
+	if (spip_num_rows($s) > 1) {
+		while ($a = sql_fetch($s))
+			if ($a['titre'] == $data['titre']
+			AND !in_array($a['id_syndic_article'], $faits)) {
+				$id_syndic_article = $a['id_syndic_article'];
+				break;
+			}
+	}
+
+	// Sinon, s'il y en a un, on verifie qu'on ne vient pas de l'ecrire avec
+	// un autre item du meme feed qui aurait le meme link
+	else if ($a = sql_fetch($s)
+	AND !in_array($a['id_syndic_article'], $faits)) {
+		$id_syndic_article = $a['id_syndic_article'];
+	} 
+
+	// Si l'article n'existe pas, on le cree
+	if (!isset($id_syndic_article)) {
+		$ajout = $id_syndic_article = sql_insertq('spip_syndic_articles',
+				array('id_syndic' => $now_id_syndic,
+				'url' => $le_lien,
+				'date' => date("Y-m-d H:i:s", $data['date']),
+				'statut'  => $statut));
+		if (!$ajout) return;
+	}
+	$faits[] = $id_syndic_article;
+
+	// Descriptif, en mode resume ou mode 'full text'
+	// on prend en priorite data['descriptif'] si on est en mode resume,
+	// et data['content'] si on est en mode "full syndication"
+	if ($resume != 'non') {
+		// mode "resume"
+		$desc = strlen($data['descriptif']) ?
+			$data['descriptif'] : $data['content'];
+		$desc = couper(trim(textebrut($desc)), 300);
+	} else {
+		// mode "full syndication"
+		// choisir le contenu pertinent
+		// & refaire les liens relatifs
+		$desc = strlen($data['content']) ?
+			$data['content'] : $data['descriptif'];
+		$desc = liens_absolus($desc, $url_syndic);
+	}
+
+	// tags & enclosures (preparer spip_syndic_articles.tags)
+	$tags = $data['enclosures'];
+	# eviter les doublons (cle = url+titre) et passer d'un tableau a une chaine
+	if ($data['tags']) {
+		$vus = array();
+		foreach ($data['tags'] as $tag) {
+			$cle = supprimer_tags($tag).extraire_attribut($tag,'href');
+			$vus[$cle] = $tag;
+		}
+		$tags .= ($tags ? ', ' : '') . join(', ', $vus);
+	}
+
+	// Mise a jour du contenu (titre,auteurs,description,date?,source...)
+	$vals = array(
+			'titre' => $data['titre'],
+			'lesauteurs' => $data['lesauteurs'],
+			'descriptif' => $desc,
+			'lang'=> substr($data['lang'],0,10),
+			'source' => substr($data['source'],0,255),
+			'url_source' => substr($data['url_source'],0,255),
+			'tags' => $tags);
+
+	// Mettre a jour la date si lastbuilddate
+	if ($data['lastbuilddate'])
+		$vals['date']= date("Y-m-d H:i:s", $data['lastbuilddate']);
+				    
+	sql_updateq('spip_syndic_articles', $vals, "id_syndic_article=$id_syndic_article");
+
+	// Point d'entree post_syndication
+	pipeline('post_syndication',
+		array(
+			$le_lien,
+			$now_id_syndic,
+			$data
+		)
+	);
+
+	return $ajout;
+}
 ?>
diff --git a/ecrire/inc/syndic.php b/ecrire/inc/syndic.php
index c6a7156f896cba21fe62fa18a6498aa754f33a06..8b6f6befe6942c39acd1492975e3bcb28f26e29b 100644
--- a/ecrire/inc/syndic.php
+++ b/ecrire/inc/syndic.php
@@ -12,6 +12,12 @@
 
 if (!defined("_ECRIRE_INC_VERSION")) return;
 
+// ATTENTION
+// Cette inclusion charge executer_une_syndication pour compatibilite,
+// mais cette fonction ne doit plus etre invoquee directement:
+// il faut passer par cron() pour avoir un verrou portable
+// Voir un exemple dans action/editer/site
+include_spip('genie/syndic');
 
 // prend un fichier backend et retourne un tableau des items lus,
 // et une chaine en cas d'erreur
@@ -372,211 +378,4 @@ function cdata_echappe_retour(&$table, &$echappe_cdata) {
 				$e, $table[$var]);
 	}
 }
-
-
-//
-// Effectuer la syndication d'un unique site,
-// retourne 0 si aucun a faire ou echec lors de la tentative
-//
-
-// http://doc.spip.org/@executer_une_syndication
-function executer_une_syndication() {
-
-	spip_connect();
-
-	## valeurs modifiables dans mes_options
-	## attention il est tres mal vu de prendre une periode < 20 minutes
-	define('_PERIODE_SYNDICATION', 2*60);
-	define('_PERIODE_SYNDICATION_SUSPENDUE', 24*60);
-
-	// On va tenter un site 'sus' ou 'off' de plus de 24h, et le passer en 'off'
-	// s'il echoue
-	$where = "syndication IN ('sus','off')
-	AND statut='publie'
-	AND date_syndic < DATE_SUB(NOW(), INTERVAL
-	"._PERIODE_SYNDICATION_SUSPENDUE." MINUTE)";
-	$row = sql_fetch(sql_select("id_syndic", "spip_syndic", $where, '', "date_syndic", "1"));
-	if ($row) {
-		$id_syndic = $row["id_syndic"];
-		$res1 = syndic_a_jour($id_syndic, 'off');
-	} else $res1 = true;
-
-	// Et un site 'oui' de plus de 2 heures, qui passe en 'sus' s'il echoue
-	$where = "syndication='oui'
-	AND statut='publie'
-	AND date_syndic < DATE_SUB(NOW(), INTERVAL "._PERIODE_SYNDICATION." MINUTE)";
-	$row = sql_fetch(sql_select("id_syndic", "spip_syndic", $where, '', "date_syndic", "1"));
-
-	if ($row) {
-		$id_syndic = $row["id_syndic"];
-		$res2 = syndic_a_jour($id_syndic, 'sus');
-	} else $res2 = true;
-
-	return ($res1 OR $res2) ? 0 : $id_syndic;
-}
-
-
-//
-// Mettre a jour le site
-//
-// Attention, cette fonction ne doit pas etre appellee simultanement
-// sur un meme site: un verrouillage a du etre pose en amont.
-//
-
-// http://doc.spip.org/@syndic_a_jour
-function syndic_a_jour($now_id_syndic, $statut = 'off') {
-	include_spip('inc/texte');
-
-	$result = spip_query("SELECT * FROM spip_syndic WHERE id_syndic=$now_id_syndic");
-
-	if (!$row = sql_fetch($result))
-		return;
-
-	$url_syndic = $row['url_syndic'];
-	$url_site = $row['url_site'];
-
-	if ($row['moderation'] == 'oui')
-		$moderation = 'dispo';	// a valider
-	else
-		$moderation = 'publie';	// en ligne sans validation
-
-	spip_query("UPDATE spip_syndic SET syndication='$statut', date_syndic=NOW() WHERE id_syndic=$now_id_syndic");
-
-	// Aller chercher les donnees du RSS et les analyser
-	include_spip('inc/distant');
-	$rss = recuperer_page($url_syndic, true);
-	if (!$rss)
-		$articles = _T('avis_echec_syndication_02');
-	else
-		$articles = analyser_backend($rss, $url_syndic);
-
-	// Renvoyer l'erreur le cas echeant
-	if (!is_array($articles)) return $articles;
-
-	// Les enregistrer dans la base
-
-	$faits = array();
-	foreach ($articles as $data) {
-		inserer_article_syndique ($data, $now_id_syndic, $moderation, $url_site, $url_syndic, $row['resume'], $row['documents'], $faits);
-	}
-
-	// moderation automatique des liens qui sont sortis du feed
-	if (count($faits) > 0) {
-		$faits = join(",", $faits);
-		if ($row['miroir'] == 'oui') {
-			spip_query("UPDATE spip_syndic_articles	SET statut='off', maj=maj WHERE id_syndic=$now_id_syndic AND NOT (id_syndic_article IN ($faits))");
-		}
-	// suppression apres 2 mois des liens qui sont sortis du feed
-		if ($row['oubli'] == 'oui') {
-
-			sql_delete('spip_syndic_articles', "id_syndic=$now_id_syndic AND maj < DATE_SUB(NOW(), INTERVAL 2 MONTH) AND date < DATE_SUB(NOW(), INTERVAL 2 MONTH) AND NOT (id_syndic_article IN ($faits))");
-		}
-	}
-
-	// Noter que la syndication est OK
-	spip_query("UPDATE spip_syndic SET syndication='oui' WHERE id_syndic=$now_id_syndic");
-
-	return false; # c'est bon
-}
-
-
-//
-// Insere un article syndique (renvoie true si l'article est nouveau)
-//
-// http://doc.spip.org/@inserer_article_syndique
-function inserer_article_syndique ($data, $now_id_syndic, $statut, $url_site, $url_syndic, $resume, $documents, &$faits) {
-	// Creer le lien s'il est nouveau - cle=(id_syndic,url)
-	// On coupe a 255 caracteres pour eviter tout doublon
-	// sur une URL de plus de 255 qui exloserait la base de donnees
-	$le_lien = substr($data['url'], 0,255);
-
-	// Chercher les liens de meme cle
-	$s = spip_query("SELECT id_syndic_article,titre FROM spip_syndic_articles WHERE url=" . _q($le_lien) . " AND id_syndic=$now_id_syndic ORDER BY maj DESC");
-
-	// S'il y a plusieurs liens qui repondent, il faut choisir le plus proche
-	// (ie meme titre et pas deja fait), le mettre a jour et ignorer les autres
-	if (spip_num_rows($s) > 1) {
-		while ($a = sql_fetch($s))
-			if ($a['titre'] == $data['titre']
-			AND !in_array($a['id_syndic_article'], $faits)) {
-				$id_syndic_article = $a['id_syndic_article'];
-				break;
-			}
-	}
-
-	// Sinon, s'il y en a un, on verifie qu'on ne vient pas de l'ecrire avec
-	// un autre item du meme feed qui aurait le meme link
-	else if ($a = sql_fetch($s)
-	AND !in_array($a['id_syndic_article'], $faits)) {
-		$id_syndic_article = $a['id_syndic_article'];
-	} 
-
-	// Si l'article n'existe pas, on le cree
-	if (!isset($id_syndic_article)) {
-		$ajout = $id_syndic_article = sql_insertq('spip_syndic_articles',
-				array('id_syndic' => $now_id_syndic,
-				'url' => $le_lien,
-				'date' => date("Y-m-d H:i:s", $data['date']),
-				'statut'  => $statut));
-		if (!$ajout) return;
-	}
-	$faits[] = $id_syndic_article;
-
-	// Descriptif, en mode resume ou mode 'full text'
-	// on prend en priorite data['descriptif'] si on est en mode resume,
-	// et data['content'] si on est en mode "full syndication"
-	if ($resume != 'non') {
-		// mode "resume"
-		$desc = strlen($data['descriptif']) ?
-			$data['descriptif'] : $data['content'];
-		$desc = couper(trim(textebrut($desc)), 300);
-	} else {
-		// mode "full syndication"
-		// choisir le contenu pertinent
-		// & refaire les liens relatifs
-		$desc = strlen($data['content']) ?
-			$data['content'] : $data['descriptif'];
-		$desc = liens_absolus($desc, $url_syndic);
-	}
-
-	// tags & enclosures (preparer spip_syndic_articles.tags)
-	$tags = $data['enclosures'];
-	# eviter les doublons (cle = url+titre) et passer d'un tableau a une chaine
-	if ($data['tags']) {
-		$vus = array();
-		foreach ($data['tags'] as $tag) {
-			$cle = supprimer_tags($tag).extraire_attribut($tag,'href');
-			$vus[$cle] = $tag;
-		}
-		$tags .= ($tags ? ', ' : '') . join(', ', $vus);
-	}
-
-	// Mise a jour du contenu (titre,auteurs,description,date?,source...)
-	$vals = array(
-			'titre' => $data['titre'],
-			'lesauteurs' => $data['lesauteurs'],
-			'descriptif' => $desc,
-			'lang'=> substr($data['lang'],0,10),
-			'source' => substr($data['source'],0,255),
-			'url_source' => substr($data['url_source'],0,255),
-			'tags' => $tags);
-
-	// Mettre a jour la date si lastbuilddate
-	if ($data['lastbuilddate'])
-		$vals['date']= date("Y-m-d H:i:s", $data['lastbuilddate']);
-				    
-	sql_updateq('spip_syndic_articles', $vals, "id_syndic_article=$id_syndic_article");
-
-	// Point d'entree post_syndication
-	pipeline('post_syndication',
-		array(
-			$le_lien,
-			$now_id_syndic,
-			$data
-		)
-	);
-
-	return $ajout;
-}
-
 ?>
diff --git a/ecrire/inc/utils.php b/ecrire/inc/utils.php
index 8ecfb946ae226821e08e09b1665b881bf0baa3c9..f123c9fe2ca2e2af7776aad51c8ca43647a1f591 100644
--- a/ecrire/inc/utils.php
+++ b/ecrire/inc/utils.php
@@ -613,7 +613,7 @@ function spip_touch($fichier, $duree=0, $touch=true) {
 		if ((@$f=filemtime($fichier)) AND ($f >= time() - $duree))
 			return false;
 	}
-	if ($touch) {
+	if ($touch!==false) {
 		if (!@touch($fichier)) { spip_unlink($fichier); @touch($fichier); };
 		@chmod($fichier, _SPIP_CHMOD & ~0111);
 	}
@@ -632,12 +632,13 @@ function action_cron() {
 	include_spip('inc/headers');
 	http_status(204); // No Content
 	header("Connection: close");
-	cron (true);
+	cron (2);
 }
 
 // cron() : execution des taches de fond
-// quand il est appele par public.php il n'est pas gourmand;
-// quand il est appele par ?action=cron, il est gourmand
+// Le premier argument indique l'intervalle demande entre deux taches 
+// par defaut, 60 secondes (quand il est appele par public.php)
+// il vaut 2 quand il est appele par ?action=cron, voire 0 en urgence
 // On peut lui passer en 2e arg le tableau de taches attendu par inc_genie()
 // Retourne Vrai si un tache a pu etre effectuee
 
@@ -651,7 +652,7 @@ function cron ($gourmand=false, $taches= array()) {
 	// ou est trop vieux (> 60 sec), on va voir si un cron est necessaire.
 	// Au passage si on est gourmand on le dit aux autres
 	if (spip_touch(_DIR_TMP.'cron.lock-gourmand', 60, $gourmand)
-	OR $gourmand) {
+	OR ($gourmand!==false)) {
 
 	// Le fichier cron.lock indique la date de la derniere tache
 	// Il permet d'imposer qu'il n'y ait qu'une tache a la fois
@@ -659,7 +660,8 @@ function cron ($gourmand=false, $taches= array()) {
 	// ca soulage le serveur et ca evite
 	// les conflits sur la base entre taches.
 
-		if (spip_touch(_DIR_TMP.'cron.lock', 2)) {
+	if (spip_touch(_DIR_TMP.'cron.lock', 
+			(is_int($gourmand) ? $gourmand : 2))) {
 			$genie = charger_fonction('genie', 'inc', true);
 			if ($genie) {
 				$genie($taches);