Corrected the last commit's problem with file locking, which is that

there was no distinction between a locked file and a new cell
(initial state) before writing to disk.  This prevents any new cell
from being saved!  Also:  Revised the behavior of the "select short"
search, but this still has issues with long run-times on complex
layouts, so this is an ongoing effort.
This commit is contained in:
Tim Edwards 2022-01-03 16:00:31 -05:00
parent 1bb4cb92ea
commit 1fceef6acd
4 changed files with 168 additions and 150 deletions

View File

@ -1 +1 @@
8.3.249 8.3.250

View File

@ -1109,7 +1109,7 @@ CmdCellname(w, cmd)
{ {
/* Check if file is already read-write */ /* Check if file is already read-write */
#ifdef FILE_LOCKS #ifdef FILE_LOCKS
if (!(cellDef->cd_flags & CDNOEDIT) && (cellDef->cd_fd != -1)) if (!(cellDef->cd_flags & CDNOEDIT) && (cellDef->cd_fd != -2))
#else #else
if (!(cellDef->cd_flags & CDNOEDIT)) if (!(cellDef->cd_flags & CDNOEDIT))
#endif #endif
@ -1117,10 +1117,10 @@ CmdCellname(w, cmd)
/* Make file read-write */ /* Make file read-write */
#ifdef FILE_LOCKS #ifdef FILE_LOCKS
if (cellDef->cd_fd == -1) if (cellDef->cd_fd < 0)
dbReadOpen(cellDef, NULL, TRUE, NULL); dbReadOpen(cellDef, NULL, TRUE, NULL);
if (cellDef->cd_fd == -1) if (cellDef->cd_fd == -2)
{ {
TxError("An advisory lock is held on cell %s. Cell can now" TxError("An advisory lock is held on cell %s. Cell can now"
" be made editable but is not writeable.\n", " be made editable but is not writeable.\n",
@ -1147,10 +1147,10 @@ CmdCellname(w, cmd)
#ifdef FILE_LOCKS #ifdef FILE_LOCKS
/* Release any advisory lock held on this file */ /* Release any advisory lock held on this file */
if (cellDef->cd_fd != -1) if (cellDef->cd_fd >= 0)
{ {
close(cellDef->cd_fd); close(cellDef->cd_fd);
cellDef->cd_fd = -1; cellDef->cd_fd = -1; /* Set to initial state */
} }
#endif #endif

View File

@ -1205,7 +1205,7 @@ DBCellRead(cellDef, name, ignoreTech, dereference, errptr)
#ifdef FILE_LOCKS #ifdef FILE_LOCKS
/* Close files that were locked by another user */ /* Close files that were locked by another user */
if (cellDef->cd_fd == -1) fclose(f); if (cellDef->cd_fd == -2) fclose(f);
#else #else
/* When using fcntl() to enforce file locks, we can't */ /* When using fcntl() to enforce file locks, we can't */
/* close the file descriptor without losing the lock. */ /* close the file descriptor without losing the lock. */
@ -1261,10 +1261,10 @@ dbReadOpen(cellDef, name, setFileName, errptr)
bool is_locked; bool is_locked;
#ifdef FILE_LOCKS #ifdef FILE_LOCKS
if (cellDef->cd_fd != -1) if (cellDef->cd_fd >= 0)
{ {
close(cellDef->cd_fd); close(cellDef->cd_fd);
cellDef->cd_fd = -1; cellDef->cd_fd = -1; /* Set to initial state */
} }
#endif #endif
@ -1385,7 +1385,9 @@ dbReadOpen(cellDef, name, setFileName, errptr)
else else
cellDef->cd_flags &= ~CDNOEDIT; cellDef->cd_flags &= ~CDNOEDIT;
if (is_locked == FALSE) if (is_locked == TRUE)
cellDef->cd_fd = -2; /* Indicates locked file */
else
cellDef->cd_fd = fileno(f); cellDef->cd_fd = fileno(f);
cellDef->cd_flags &= ~CDNOTFOUND; cellDef->cd_flags &= ~CDNOTFOUND;
} }
@ -3235,7 +3237,7 @@ DBCellWrite(cellDef, fileName)
} }
#ifdef FILE_LOCKS #ifdef FILE_LOCKS
if (cellDef->cd_fd == -1) if (cellDef->cd_fd == -2)
{ {
TxPrintf("File %s is locked by another user and " TxPrintf("File %s is locked by another user and "
"cannot be written\n", realname); "cannot be written\n", realname);
@ -3307,10 +3309,10 @@ DBCellWrite(cellDef, fileName)
} }
#ifdef FILE_LOCKS #ifdef FILE_LOCKS
if (cellDef->cd_fd != -1) if (cellDef->cd_fd >= 0)
{ {
close(cellDef->cd_fd); close(cellDef->cd_fd);
cellDef->cd_fd = -1; cellDef->cd_fd = -1; /* Set to initial state */
} }
#endif #endif
@ -3430,8 +3432,11 @@ DBCellWrite(cellDef, fileName)
} }
#ifdef FILE_LOCKS #ifdef FILE_LOCKS
cellDef->cd_fd = -1;
if (FileLocking && (is_locked == FALSE)) if (FileLocking && (is_locked == FALSE))
cellDef->cd_fd = fd; cellDef->cd_fd = fd;
else if (FileLocking && (is_locked == TRUE))
cellDef->cd_fd = -2;
else else
#endif #endif
fclose(realf); fclose(realf);

View File

@ -314,13 +314,13 @@ SelectFlat()
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* *
* selShortFindPath -- * selShortFindReverse --
* *
* Trace back through a path found by selShortFindNext from destination * Trace back through a path found by selShortFindForward from destination
* to source, picking the lowest cost return path, and adding each tile * to source, picking the lowest cost return path, and adding each tile
* found to the linked list. * found to the linked list.
* *
* Algorithm notes (for this and selShortFindNext): Note that by not * Algorithm notes (for this and selShortFindForward): Note that by not
* using one of the standard database search routines, TT_SIDE is NOT * using one of the standard database search routines, TT_SIDE is NOT
* set on any tile. To find out what side we're looking at, we keep * set on any tile. To find out what side we're looking at, we keep
* a record of what direction we were traveling from the previous * a record of what direction we were traveling from the previous
@ -335,7 +335,7 @@ SelectFlat()
*/ */
int int
selShortFindPath(rlist, tile, pnum, fdir) selShortFindReverse(rlist, tile, pnum, fdir)
ExtRectList **rlist; ExtRectList **rlist;
Tile *tile; Tile *tile;
int pnum; int pnum;
@ -518,16 +518,15 @@ donesides:
} }
} }
/* Data structure used by selShortFindNext() to store a tile and */ /* Data structure used by selShortFindForward() to store a tile and */
/* the current search parameters, including cost, direction, plane, */ /* the current search parameters, including cost, direction, plane, */
/* and the mask of connecting types. */ /* and the mask of connecting types. */
typedef struct _shortdata { typedef struct _shortdata {
int cost; int cost;
Tile *tile; Tile *tile;
TileType type;
int pnum; int pnum;
int fdir;
TileTypeBitMask *mask;
} ShortData; } ShortData;
/* /*
@ -543,12 +542,11 @@ typedef struct _shortdata {
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
ShortData *NewSD(cost, tile, pnum, fdir, mask) ShortData *NewSD(cost, tile, type, pnum)
int cost; int cost;
Tile *tile; Tile *tile;
TileType type;
int pnum; int pnum;
int fdir;
TileTypeBitMask *mask;
{ {
ShortData *sd; ShortData *sd;
@ -556,9 +554,8 @@ ShortData *NewSD(cost, tile, pnum, fdir, mask)
sd->cost = cost; sd->cost = cost;
sd->tile = tile; sd->tile = tile;
sd->type = type;
sd->pnum = pnum; sd->pnum = pnum;
sd->fdir = fdir;
sd->mask = mask;
return sd; return sd;
} }
@ -566,14 +563,81 @@ ShortData *NewSD(cost, tile, pnum, fdir, mask)
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* *
* selShortFindNext -- * selShortProcessTile --
* *
* Recursive function for finding shorts. This routine makes strong * Process a tile, finding if it extends the connection from the
* assumptions; namely, that all non-space material in the cell being * last position, and setting its cost to be one higher than the
* searched belongs to the same net. The cell searched is always * previous position.
* SelectDef. (Although rather than actually recursing, which is *
* likely to exceed the computer's stack depth, we create our own * Return value:
* stack of unprocessed tiles and process them.) * 0 if tile was updated with new cost.
* 1 if tile was unchanged.
*
* Side effects:
* Writes cost to the tile's ClientData record.
*
* ----------------------------------------------------------------------------
*/
int
selShortProcessTile(tile, cost, fdir, mask)
Tile *tile;
int cost;
int fdir;
TileTypeBitMask *mask;
{
TileType ttype;
if (IsSplit(tile))
{
switch(fdir)
{
case GEO_NORTH:
ttype = SplitBottomType(tile);
break;
case GEO_SOUTH:
ttype = SplitTopType(tile);
break;
case GEO_EAST:
ttype = SplitLeftType(tile);
break;
case GEO_WEST:
ttype = SplitRightType(tile);
break;
default:
ttype = SplitLeftType(tile);
if (ttype == TT_SPACE) ttype = SplitRightType(tile);
break;
}
}
else
ttype = TiGetTypeExact(tile);
/* Ignore space tiles */
if (ttype == TT_SPACE) return 1;
/* Ignore non-connecting tiles */
if (!TTMaskHasType(mask, ttype)) return 1;
/* If this tile is unvisited, or has a lower cost, then return and */
/* keep going. Otherwise, return 1 to stop the search this direction */
if (tile->ti_client == (ClientData)CLIENTDEFAULT)
TiSetClient(tile, cost);
else if ((int)tile->ti_client > cost)
TiSetClient(tile, cost);
else
return 1;
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* selShortFindForward --
*
* Function for finding shorts. The cell searched is always SelectDef.
* *
* Results: * Results:
* Return 0 to keep going; return 1 to stop when the tile contains * Return 0 to keep going; return 1 to stop when the tile contains
@ -587,27 +651,30 @@ ShortData *NewSD(cost, tile, pnum, fdir, mask)
*/ */
int int
selShortFindNext(tile, pnum, ldest, mask) selShortFindForward(srctile, srctype, srcpnum, desttile)
Tile *tile; Tile *srctile;
int pnum; TileType srctype;
Label *ldest; int srcpnum;
TileTypeBitMask *mask; Tile *desttile;
{ {
TileType ttype; TileType type;
TileTypeBitMask *lmask; TileTypeBitMask *lmask;
Tile *tp; Tile *tile, *tp;
int pnum;
ShortData *sd; ShortData *sd;
static Stack *ShortStack = (Stack *)NULL; static Stack *ShortStack = (Stack *)NULL;
int cost = 0; int cost = 0;
int best = INT_MAX; int best = INT_MAX;
int fdir = GEO_CENTER;
if (ShortStack == (Stack *)NULL) if (ShortStack == (Stack *)NULL)
ShortStack = StackNew(64); ShortStack = StackNew(64);
/* Set the cost of the source tile to zero */
TiSetClient(srctile, (ClientData)0);
/* Drop the first entry on the stack */ /* Drop the first entry on the stack */
sd = NewSD(cost, tile, pnum, fdir, mask); sd = NewSD(cost, srctile, srctype, srcpnum);
STACKPUSH(sd, ShortStack); STACKPUSH(sd, ShortStack);
while (!StackEmpty(ShortStack)) while (!StackEmpty(ShortStack))
@ -616,54 +683,12 @@ selShortFindNext(tile, pnum, ldest, mask)
tile = sd->tile; tile = sd->tile;
cost = sd->cost; cost = sd->cost;
pnum = sd->pnum; pnum = sd->pnum;
fdir = sd->fdir; type = sd->type;
mask = sd->mask;
freeMagic((char *)sd); freeMagic((char *)sd);
if (IsSplit(tile)) /* If this tile is the destination tile, do not search further */
{
switch(fdir)
{
case GEO_NORTH:
ttype = SplitBottomType(tile);
break;
case GEO_SOUTH:
ttype = SplitTopType(tile);
break;
case GEO_EAST:
ttype = SplitLeftType(tile);
break;
case GEO_WEST:
ttype = SplitRightType(tile);
break;
default:
ttype = SplitLeftType(tile);
if (ttype == TT_SPACE) ttype = SplitRightType(tile);
break;
}
}
else
ttype = TiGetTypeExact(tile);
/* Ignore space tiles */ if (tile == desttile)
if (ttype == TT_SPACE) continue;
/* Ignore non-connecting tiles */
if (!TTMaskHasType(mask, ttype)) continue;
/* If this tile is unvisited, or has a lower cost, then return and */
/* keep going. Otherwise, return 1 to stop the search this direction */
if (tile->ti_client == (ClientData)CLIENTDEFAULT)
TiSetClient(tile, cost);
else if ((int)tile->ti_client > cost)
TiSetClient(tile, cost);
else
continue;
/* If this tile contains the destination point, do not search further */
if ((ttype == ldest->lab_type) && EnclosePoint(tile, &ldest->lab_rect.r_ll))
{ {
if (best >= cost) best = (cost - 1); if (best >= cost) best = (cost - 1);
continue; continue;
@ -673,27 +698,18 @@ selShortFindNext(tile, pnum, ldest, mask)
/* do not search further. */ /* do not search further. */
if (cost >= best) continue; if (cost >= best) continue;
lmask = &DBConnectTbl[ttype]; lmask = &DBConnectTbl[type];
/* Search top */ /* Search top */
if (IsSplit(tile)) if (IsSplit(tile))
{ if (TiGetTopType(tile) != type)
if (fdir == GEO_NORTH) goto srchleft; goto srchleft;
else if (SplitDirection(tile) && fdir == GEO_EAST) goto srchleft;
else if (!SplitDirection(tile) && fdir == GEO_WEST) goto srchleft;
}
/* As a small optimization, check for space tiles and avoid going
* through the hoops of allocating a structure and pushing it on the
* stack. This check is not rigorous, but it saves time for the
* most common case.
*/
for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp)) for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp))
{ {
if (TiGetTypeExact(tp) != TT_SPACE) if (selShortProcessTile(tp, cost + 1, GEO_NORTH, lmask) == 0)
{ {
sd = NewSD(cost + 1, tp, pnum, GEO_NORTH, lmask); sd = NewSD(cost + 1, tp, TiGetBottomType(tp), pnum);
STACKPUSH(sd, ShortStack); STACKPUSH(sd, ShortStack);
} }
} }
@ -701,17 +717,14 @@ selShortFindNext(tile, pnum, ldest, mask)
/* Search left */ /* Search left */
srchleft: srchleft:
if (IsSplit(tile)) if (IsSplit(tile))
{ if (TiGetLeftType(tile) != type)
if (fdir == GEO_WEST) goto srchbot; goto srchbot;
else if (SplitDirection(tile) && fdir == GEO_SOUTH) goto srchbot;
else if (!SplitDirection(tile) && fdir == GEO_NORTH) goto srchbot;
}
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp)) for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
{ {
if (TiGetTypeExact(tp) != TT_SPACE) if (selShortProcessTile(tp, cost + 1, GEO_WEST, lmask) == 0)
{ {
sd = NewSD(cost + 1, tp, pnum, GEO_WEST, lmask); sd = NewSD(cost + 1, tp, TiGetRightType(tp), pnum);
STACKPUSH(sd, ShortStack); STACKPUSH(sd, ShortStack);
} }
} }
@ -719,17 +732,14 @@ srchleft:
/* Search bottom */ /* Search bottom */
srchbot: srchbot:
if (IsSplit(tile)) if (IsSplit(tile))
{ if (TiGetBottomType(tile) != type)
if (fdir == GEO_SOUTH) goto srchright; goto srchright;
else if (SplitDirection(tile) && fdir == GEO_WEST) goto srchright;
else if (!SplitDirection(tile) && fdir == GEO_EAST) goto srchright;
}
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp)) for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
{ {
if (TiGetTypeExact(tp) != TT_SPACE) if (selShortProcessTile(tp, cost + 1, GEO_SOUTH, lmask) == 0)
{ {
sd = NewSD(cost + 1, tp, pnum, GEO_SOUTH, lmask); sd = NewSD(cost + 1, tp, TiGetTopType(tp), pnum);
STACKPUSH(sd, ShortStack); STACKPUSH(sd, ShortStack);
} }
} }
@ -737,29 +747,26 @@ srchbot:
/* Search right */ /* Search right */
srchright: srchright:
if (IsSplit(tile)) if (IsSplit(tile))
{ if (TiGetRightType(tile) != type)
if (fdir == GEO_EAST) goto donesrch; goto donesrch;
else if (SplitDirection(tile) && fdir == GEO_NORTH) goto donesrch;
else if (!SplitDirection(tile) && fdir == GEO_SOUTH) goto donesrch;
}
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp)) for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
{ {
if (TiGetTypeExact(tp) != TT_SPACE) if (selShortProcessTile(tp, cost + 1, GEO_EAST, lmask) == 0)
{ {
sd = NewSD(cost + 1, tp, pnum, GEO_EAST, lmask); sd = NewSD(cost + 1, tp, TiGetLeftType(tp), pnum);
STACKPUSH(sd, ShortStack); STACKPUSH(sd, ShortStack);
} }
} }
/* Search other connecting planes */ /* Search other connecting planes */
donesrch: donesrch:
if (DBIsContact(ttype)) if ((!IsSplit(tile)) && DBIsContact(type))
{ {
PlaneMask pmask; PlaneMask pmask;
int p; int p;
pmask = DBConnPlanes[ttype]; pmask = DBConnPlanes[type];
for (p = PL_TECHDEPBASE; p < DBNumPlanes; p++) for (p = PL_TECHDEPBASE; p < DBNumPlanes; p++)
{ {
if (PlaneMaskHasPlane(pmask, p) && (p != pnum)) if (PlaneMaskHasPlane(pmask, p) && (p != pnum))
@ -767,9 +774,9 @@ donesrch:
tp = SelectDef->cd_planes[p]->pl_hint; tp = SelectDef->cd_planes[p]->pl_hint;
GOTOPOINT(tp, &tile->ti_ll); GOTOPOINT(tp, &tile->ti_ll);
SelectDef->cd_planes[p]->pl_hint = tp; SelectDef->cd_planes[p]->pl_hint = tp;
if (TiGetTypeExact(tp) != TT_SPACE) if (selShortProcessTile(tp, cost + 1, GEO_CENTER, lmask) == 0)
{ {
sd = NewSD(cost + 1, tp, p, GEO_CENTER, lmask); sd = NewSD(cost + 1, tp, TiGetLeftType(tp), p);
STACKPUSH(sd, ShortStack); STACKPUSH(sd, ShortStack);
} }
} }
@ -809,9 +816,10 @@ ExtRectList *
SelectShort(char *lab1, char *lab2) SelectShort(char *lab1, char *lab2)
{ {
Label *selLabel, *srclab = NULL, *destlab = NULL; Label *selLabel, *srclab = NULL, *destlab = NULL;
Tile *tile; Tile *srctile, *desttile;
TileType srctype, desttype;
int srcpnum, destpnum;
Plane *plane; Plane *plane;
int pnum;
PlaneMask pmask; PlaneMask pmask;
ExtRectList *rlist; ExtRectList *rlist;
@ -872,38 +880,43 @@ SelectShort(char *lab1, char *lab2)
/* Must be able to find tiles associated with each label */ /* Must be able to find tiles associated with each label */
pmask = DBTypePlaneMaskTbl[srclab->lab_type]; pmask = DBTypePlaneMaskTbl[destlab->lab_type];
for (pnum = PL_TECHDEPBASE; pnum < DBNumPlanes; pnum++) for (destpnum = PL_TECHDEPBASE; destpnum < DBNumPlanes; destpnum++)
{ {
if (PlaneMaskHasPlane(pmask, pnum)) if (PlaneMaskHasPlane(pmask, destpnum))
{ {
plane = SelectDef->cd_planes[pnum]; plane = SelectDef->cd_planes[destpnum];
tile = plane->pl_hint; desttile = plane->pl_hint;
GOTOPOINT(tile, &srclab->lab_rect.r_ll) GOTOPOINT(desttile, &destlab->lab_rect.r_ll)
if (TiGetType(tile) == srclab->lab_type) break; desttype = TiGetTopType(desttile);
if (TTMaskHasType(&DBConnectTbl[destlab->lab_type], desttype)) break;
desttype = TiGetBottomType(desttile);
if (TTMaskHasType(&DBConnectTbl[destlab->lab_type], desttype)) break;
} }
} }
selShortFindNext(tile, pnum, destlab, &DBConnectTbl[srclab->lab_type]); pmask = DBTypePlaneMaskTbl[srclab->lab_type];
for (srcpnum = PL_TECHDEPBASE; srcpnum < DBNumPlanes; srcpnum++)
{
if (PlaneMaskHasPlane(pmask, srcpnum))
{
plane = SelectDef->cd_planes[srcpnum];
srctile = plane->pl_hint;
GOTOPOINT(srctile, &srclab->lab_rect.r_ll)
srctype = TiGetTopType(srctile);
if (TTMaskHasType(&DBConnectTbl[srclab->lab_type], srctype)) break;
srctype = TiGetBottomType(srctile);
if (TTMaskHasType(&DBConnectTbl[srclab->lab_type], srctype)) break;
}
}
selShortFindForward(srctile, srctype, srcpnum, desttile, desttype);
/* Now see if destination has been counted */ /* Now see if destination has been counted */
if (desttile->ti_client == (ClientData)CLIENTDEFAULT) return NULL;
pmask = DBTypePlaneMaskTbl[destlab->lab_type];
for (pnum = PL_TECHDEPBASE; pnum < DBNumPlanes; pnum++)
{
if (PlaneMaskHasPlane(pmask, pnum))
{
plane = SelectDef->cd_planes[pnum];
tile = plane->pl_hint;
GOTOPOINT(tile, &destlab->lab_rect.r_ll)
if (TiGetType(tile) == destlab->lab_type) break;
}
}
if (tile->ti_client == (ClientData)CLIENTDEFAULT) return NULL;
/* Now find the shortest path between source and destination */ /* Now find the shortest path between source and destination */
rlist = NULL; rlist = NULL;
selShortFindPath(&rlist, tile, pnum, GEO_CENTER); selShortFindReverse(&rlist, desttile, destpnum, GEO_CENTER);
return rlist; return rlist;
} }