TOPS-20 Monitor Calls User's Guide

Chapter 6 Enqueue/Dequeue facility

6.1 Overview

Many times users are placed in situations where they must share files with other users. Each user wants to be guaranteed that while reading a file, other users are reading the same data and while writing a file, no users are also writing, or even reading, the same portion of the file.

Consider a data file used by members of an insurance company. When many agents are reading individual accounts from the data file, they can all access the file simultaneously because no one is changing any portion of the data. However, when an agent desires to modify or replace an individual account, that portion of the file should be accessed exclusively by that agent. None of the other agents wants to access accounts that are being changed until after the changes are made.

By using the ENQ/DEQ facility, cooperating users can insure that resources are shared correctly and that one user's modifications do not interfere with another user's. Examples of resources that can be controlled by this facility are devices, files, operations on files (for example, READ, WRITE), records, and memory pages. This facility can be used for dynamic resource allocation, computer networks, and internal monitor queueing. However, control of simultaneous updating of files by multiple users is its most common application.

The ENQ/DEQ facility insures data integrity among processes only when the processes cooperate in their use of both the facility and the physical resource. Use of the facility does not prevent non-cooperating processes from accessing a resource without first enqueueing it. Nor does the facility provide protection from processes using it in an incorrect manner.

A resource is defined by the processes using it and not by the system. Because there is competition among processes for use of a resource, each resource is associated with a queue. This queue is the ordering of the requests for the resource. When a request for the resource is granted, a lock occurs between the process that made the request and the resource. For the duration of the lock, that process is the owner of the resource. Other processes requesting access to the resource are placed in the queue until the owner relinquishes the lock. However, there can be more than one owner of a resource at a time; this is called shared ownership (refer to Section 6.2). Processes obtain access to a specific resource by placing a request in the queue for the resource. This request is generated by the ENQ% monitor call. When finished with the resource, the process then issues the DEQ% monitor call. This call releases the lock by removing the request from the queue and makes the resource available to the next waiting process. This cycle continues until all requests in the queue have been satisfied.

6.2 Resource ownership

Ownership for a resource can be requested as either exclusive or shared. Exclusive ownership occurs when a process requests sole use of the resource. When a process is granted exclusive ownership, no other process will be allowed to use the resource until the owner relinquishes it. This type of ownership should be requested if the process plans on modifying the resource (for example, the process is updating a record in a data file). Shared ownership occurs when a process requests a resource, specifying that it will share the use of the resource with other processes. When a process is given shared ownership, other processes also specifying shared ownership are allowed to simultaneously use the resource. Access to a resource should be shared as long as any one process is not modifying the resource.

Two conditions determine when a lock to a resource is given to a process:

  1. The position of the process's request in the queue for the resource.
  2. The type of ownership specified by the process's request.

Because each resource has only one queue associated with it, requests for both exclusive and shared ownership of the resource are placed in the same queue. Requests are placed in the queue in the order in which the ENQ facility receives them, and the first request in the queue will be the first one serviced (except in the case of single requests for multiple resources; refer to Section 6.4.1). In other words, the ENQ facility processes requests on a first in, first out basis. If this first request is for shared ownership, that request will be serviced along with all following shared ownership requests up to but not including the first exclusive ownership request. If the first request is for exclusive ownership, no other processes are allowed use of the resource until the first process has released the lock.

Consider the following queue for a particular resource.

         !=======================================================!
         !                  request 1 (shared)                   !
         !-------------------------------------------------------!
         !                  request 2 (shared)                   !
         !-------------------------------------------------------!
         !                 request 3 (exclusive)                 !
         !-------------------------------------------------------!
         !                  request 4 (shared)                   !
         !-------------------------------------------------------!
         !                  request 5 (shared)                   !
         !=======================================================!

Request 1 will be serviced first because it is the first request in the queue. However, since this request is for shared ownership, request 2 can also be serviced. Request 3 cannot be serviced until the processes with request 1 and request 2 release the lock on the resource. Eventually the lock is released by the two processes, and the first two requests are removed from the queue. The queue now has the following entries:

         !=======================================================!
         !                                                       !
         !-------------------------------------------------------!
         !                                                       !
         !-------------------------------------------------------!
         !                 request 3 (exclusive)                 !
         !-------------------------------------------------------!
         !                  request 4 (shared)                   !
         !-------------------------------------------------------!
         !                  request 4 (shared)                   !
         !=======================================================!

Request 3 is now first in the queue and is given a lock on the resource. Because the request is for exclusive ownership, no other requests will be serviced. Once the process associated with request 3 releases the lock, both request 4 and request 5 can be serviced because they both are for shared ownership.

6.3 Preparing for the ENQ/DEQ facility

Before using the ENQ/DEQ facility, the user must obtain an ENQ quota from the system administrator and must obtain the name of the resource desired, the type of protection required, and the level number associated with the resource.

The ENQ quota indicates the total number of requests that can be outstanding for the user at any given time. Any request that would cause the quota to be exceeded results in an error. The user cannot use the ENQ facility if the quota is set to zero.

The resource name has a meaning agreed upon by all users of the specific resource and serves as an identifier of the resource. The system makes no association between the resource name and the physical resource itself; it is the responsibility of the user's process to make that association. The system merely uses the resource name to process requests and handles different resource names as requests for different resources.

The resource name has two parts. In most cases, the first part is the JFN of the file being accessed. Before using the ENQ facility, the user must initialize the file using the appropriate monitor calls (refer to Section 3.1). The second part of the name is a modifier, which is either a pointer to a string or a 33-bit user code. The string uniquely identifies the resource to all users. The pointer can either be a standard byte pointer or be in the form

        -1,,ADR

where ADR is the location of the left-justified ASCIZ text string. The 33-bit user code similarly identifies the resource by representing an item such as a record number or block number. The ENQ facility considers these modifiers as logical strings and does not check for cooperation among the users. Thus, users must be careful when assigning these modifiers to prevent the occurrence of two different modifiers referring to the same resource.

The type of protection desired for the resource is indicated by the first part of the resource name. This part of the name can be one of four values. When the user specifies the JFN of the desired file, the file is subject to the standard access protection of the system. This is the most typical case. When the user specifies -1 instead of a JFN, it means that resources defined within a job are to be accessed only by processes of that job. Other jobs requesting resources of the same name are queued to a different resource. When the user specifies -2 instead of a JFN, it means that the resource can be accessed by any job on the system. A process must have bit SC%ENQ enabled in its capability word to specify this type of protection. If the user specifies -3 instead of a JFN, it means the same type of protection as that given when -2 is specified. However, this requires that the process have WHEEL or OPERATOR capability enabled. Quotas are not checked when -3 is given instead of a JFN.

In addition to specifying the resource name and type of protection, the user also assigns a level number to each resource. The use of level numbers prevents the occurrence of a deadly embrace situation: the situation where two or more processes are waiting for each to complete, but none of the processes can obtain a lock on the resource it needs for completion. This situation is represented by Figure 6-1.

         ---------------------
         | Process A is      |
         | Waiting for a     |
         | Resource Process  |--------------------------\
         | B Has.            |                          |
         ---------------------                          |
                 ^                                      v
                 |                             ---------------------
                 |                             | Process B is      |
                 |                             | Waiting for a     |
                 |                             | Resource Process  |
                 |                             | C Has.            |
                 |                             ---------------------
                 |                                      |
                 |         ---------------------        |
                 |         | Process C is      |        |
                 |         | Waiting for a     |        |
                 \---------| Resource Process  |<-------/
                           | A Has.            |
                           ---------------------
Figure 6-1: Deadly Embrace Situation

Each process is in the queue waiting for the resource it needs, but no request is being serviced because the desired resources are unavailable.

The use of level numbers forces cooperating processes to order their use of resources by requiring that processes request resources in an ascending numerical order and that all processes assign the same level number to a specific resource. This means that the order in which resources are requested is the same for all processes and therefore, requests for the first resource will always precede requests for the second one.

If both of the above requirements are not met, the process requesting the resource receives an error, unless the appropriate flag bit is set (refer to Section 6.4.1.2), and the request is not placed in the queue. Thus, instead of waiting for a resource it will never get, the process is informed immediately that the resource is not available.

6.4 Using the ENQ/DEQ facility

There are three monitor calls available for the ENQ/DEQ facility: ENQ%, to request use of a resource; DEQ%, to release a lock on a resource; and ENQC%, to obtain information about the queues and to specify access to these queues.

6.4.1 Requesting Use of a Resource

The user issues the ENQ% monitor call to place a request in the queue associated with the desired resource. This call is used to specify the resource name, level number, and type of protection required.

A single ENQ% monitor call can be used to request any number of resources. In fact, when desiring multiple resources, the user should request all of them in one call. This method of requesting resources guarantees that the user gets either none or all of the resources requested because the ENQ/DEQ facility never allocates only some of the resources specified in one call. Because all resources in a single call must be available at the same time, the first user requesting a resource (that is, the first user in the queue for the resource) may not be the first user obtaining it if other resources in the request are currently not available.

A single call for multiple resources is not functionally the same as a series of single calls of those resources. In a single call, the entire request is rejected if an error is returned for one of the resources specified. In a series of single calls, each request that did not return an error will be queued.

The ENQ% monitor call accepts two words of arguments in AC1 and AC2. The first word contains the code of the desired function, and the second contains the address of the argument block. Thus,

AC1: function code
AC2: address of argument block
6.4.1.1 ENQ% Functions

The functions that can be requested in the ENQ% call are described in Table 6-1.

Table 6-1: ENQ% Functions
CodeSymbolMeaning
0 .ENQBL Queue the requests and block the process until all requested locks are acquired. This function returns an error code only if the ENQ% call is not correctly specified.
1 .ENQAA Queue the requests and acquire the locks only if all requested resources are immediately available. If the resources are available, all will be allocated to the process. If any one of the resources is not available, no requests are queued, no locks are acquired, and an error code is returned in AC1.
2 .ENQSI Queue the requests for all specified resources. If all resources are available, this function is identical to the .ENQBL function. If all resources are not immediately available, the requests are queued, and a software interrupt is generated when all requested resources have been given to the process.
3 .ENQMA Change the ownership access of a previously-queued request (refer to bit EN%SHR below). The access for each lock in this request is compared with the access for each lock in the request already queued. No action is taken if the two accesses are the same. If the access in this request is shared and the access in the previous request is exclusive, the ownership access is changed to shared access. Otherwise, an error is returned if:
  1. There are processes which are locking, or waiting on the same lock, and the process tries to change the ownership access from shared to exclusive. If this is the case, the process should issue a DEQ% monitor call for the shared request and then issue another ENQ% monitor call for exclusive ownership.
  2. Any one of the specified locks does not have a pending request.
  3. Any one of the specified locks is a pooled resource (refer to Section 6.4.1.2).

Each lock specified is checked, and the access is changed for all locks that were correctly given. On receiving an error, the process should issue the ENQC% monitor call to determine the current state of each lock (refer to Section 6.4.3).

4 .ENECL Set cluster-wide ENQ/DEQ functionality for all ENQ/DEQ/ENQC JSYSes performed by this process. The contents of AC2 are ignored as this function does not require an argument block.
6.4.1.2 ENQ% Argument Block

The format of the argument block is described in Table 6-2.

Table 6-2: ENQ% Argument Block
WordSymbolMeaning
0 .ENQLN Number of locks being requested in the left half, and length of argument block (including this word) in the right half.
1 .ENQID Number of software interrupt channel in the left half, and request ID in the right half.
2 .ENQLV Flags and level number in the left half, and JFN, -1, -2 or -3 (refer to Section 6.3) in the right half.
3 .ENQUC Pointer to string or 5B2+33-bit user code (refer to Section 6.3).
4 .ENQRS Number of resources in the pool in the left half, and number of resources requested in the right half.
5 .ENQMS Address of a resource mask block.

Words .ENQLV, .ENQUC, .ENQRS, and .ENQMS (words 2 through 5) are repeated for each lock being requested. These four words are called the lock specification.

Software Interrupts

The software interrupt system is used in conjunction with the .ENQSI function (refer to Section 6.4.1.1). If all locks are not available when the user requests them, the .ENQSI function causes a software interrupt to be generated when the locks become available. The user specifies the software channel on which to receive the interrupt by placing the channel number in the left half of word .ENQID in the argument block.

When the user is waiting for more than one lock to become available, he will receive an interrupt when the last lock is available. If he desires to be informed as each lock becomes available, he can assign the locks to separate channels by issuing multiple ENQ% calls. The availability of each lock will then be indicated by the occurrence of an interrupt on each channel.

When the user requests the .ENQSI function, he must initialize the interrupt system first or else an interrupt will not be generated when the locks become available (refer to Chapter 4).

Request ID

The 18-bit request ID is currently not used by the system, but is stored for use by the process. Thus, the process can supply an ID to use as identification for the request. This ID is useful on the .DEQID function of the DEQ% monitor call (refer to Section 6.4.2.1).

Flags and Level Numbers

Table 6-3 describes the flags that can be used in the left half of the first word of each lock specification (.ENQLV).

Table 6-3: Lock Specification Flags
BitSymbolMeaning
0 EN%SHR Ownership for this resource is to be shared. If this bit is not on, ownership for this resource is to be exclusive.
1 EN%BLN Ignore the level number associated with this resource. If this bit is set, sequencing errors in level numbers are not considered fatal, and execution of the call continues.

On successful completion of the call, AC1 contains either an error code if a sequencing error occurred, or zero if a sequencing error did not occur.

WARNING

A deadly embrace situation may occur when level numbers are not used. Use of these numbers guarantees that such a situation cannot arise; for this reason bit EN%BLN should not be set.

2 EN%NST Allow ownership of this lock to be nested.
3 EN%LTL Allow a long-term lock on this resource.
4-8 Reserved for Digital.
9-17 EN%LVL Level number associated with this resource. This number is specified by the user and must be agreed upon by all users of the resource. In order to eliminate a deadly embrace situation, users must request resources in numerically increasing order.

The request is not queued, and an error is given, if EN%BLN is not set and

  1. The user requests a resource with a level number less than or equal to the highest numbered resource he has requested so far.
  2. The level number of this request does not match the level number supplied in previous requests for this resource.

Pooled Resources

Word .ENQRS of each lock specification is used to allocate multiple copies from a pool of identical resources. Bit EN%SHR, indicating shared ownership, is meaningless for pooled resources because each resource in the pool can be owned by only one process at a time. A process can own one or more resources in the pool; however, it cannot own more than there are in the pool or more than there are unowned in the pool.

The left half of word .ENQRS contains the total number of resources existing in the pool. This number is previously agreed upon by all users of the pooled resource. The first user who requests the resource sets this number, and all subsequent requests must specify the same number or an error is given.

The right half of word .ENQRS contains the number of resources being requested by this process. This number must be greater than zero if a pool of resources exists and cannot be greater than the number in the left half. This means that if a pool of resources exists, the user must request at least one resource, but cannot request more than are in the pool.

Once the number of pooled resources is determined, the resources are allocated until the pool is depleted or until a request specifies more resources than are currently available. In the latter case, the user making the request is not given any resources until his entire request can be satisfied. Subsequent requests from other users are not granted until this request is satisfied even though there may be enough resources to satisfy these subsequent requests. As users release their resources, the resources are returned to the pool. When all resources have been returned, they cease to exist, and the next request completely redefines the number of resources in the new pool.

The system assumes that the resource is in a pool if the left half of word .ENQRS of the lock specification is nonzero. Thus the user should set the left half to zero if only one resource of a specific type exists. If this is the case, then the right half of this word is a number defining the group of users who can simultaneously share the resource. This means that when the resource is allocated to a user for shared ownership, only other users in the same group will be allowed access to the resource. The use of sharer groups restricts access to a resource to a set of processes smaller than the set for shared ownership (which is sharer group 0) but larger than the set for exclusive ownership. (Refer to Section 6.5 for more information on sharer groups).

6.4.2 Releasing a Resource

The user issues the DEQ% monitor call to remove a request from the queue associated with a resource. The request is removed whether or not the user actually owns a lock on the resource or is only waiting in the queue for the resource.

The DEQ% monitor call can be used to remove any number of requests from the queues. If one of the requests cannot be removed, the dequeueing procedure continues until all lock specifications have been processed. An error code is then returned for the last request found that could not be dequeued. The process can then execute the ENQC% call (refer to Section 6.4.3) to determine the status of each lock. Thus, unlike the operation of the ENQ% call, the DEQ% call will dequeue as many resources as it can, even if an error is returned for one of the lock specifications in the argument block. However, when a user attempts to dequeue more pooled resources than he originally allocated, an error code is returned and none of the resources are dequeued.

The DEQ% monitor call accepts two words of arguments in AC1 and AC2. The first word contains the code for the desired function, and the second word contains the address of the argument block. Thus,

AC1: function code
AC2: address of argument block
6.4.2.1 DEQ% Functions

The DEQ% functions are described in Table 6-4.

Table 6-4: DEQ% Functions
CodeSymbolMeaning
0 .DEQDR Remove the specified requests from the queues. This function is the only one that requires an argument block.
1 .DEQDA Remove all requests for this process from the queues. This action is taken on a RESET monitor call. An error code is returned if this process has not requested any resources (that is, if this process has not issued an ENQ%).
2 .DEQID Remove all requests that correspond to the specified request identifier. When this function is specified, the user must place the 18-bit request ID in AC2 on the DEQ% call. This function allows the user to release a class of locks in one call without itemizing each lock in an argument block. The function should be used when dequeueing in one call the same locks that were enqueued in one call. For example, with this function the user can specify the ID to be the same as the JFN used in the ENQ% call and thus remove all locks to that file at once.
6.4.2.2 DEQ% Argument Block

The format of the argument block for function .DEQDR is described in Table 6-5.

Table 6-5: DEQ% Argument Block
WordSymbolMeaning
0 .ENQLN Number of locks being requested in the left half, and length of argument block (including this word) in the right half.
1 .ENQID Number of software interrupt channel in the left half, and request ID in the right half.
2 .ENQLV Flags and level number in the left half, and JFN, -1, -2 or -3 (refer to Section 6.3) in the right half.
3 .ENQUC Pointer to string or 5B2+33-bit user code (refer to Section 6.3).
4 .ENQRS Number of resources in the pool in the left half, and number of resources requested in the right half.
5 .ENQMS Address of a resource mask block.

Words .ENQLV, .ENQUC, .ENQRS, and .ENQMS (words 2 through 5) are repeated for each request being dequeued. These four words are called the lock specification.

6.4.3 Obtaining Information About Resources

The user issues the ENQC% monitor call to obtain information about the current status of the given resources. This call can also be used by privileged users to perform various utility functions on the queue structure. The format of the ENQC% call is different for these two uses. (Refer to the TOPS-20 Monitor Calls Reference Manual for the explanation of the privileged use of the ENQC% call.)

The ENQC% monitor call accepts three words of arguments in AC1 through AC3:

AC1: function code (.ENQCS)
AC2: address of argument block
AC3: address of area to receive status information

The format of the argument block is identical to the format of the ENQ% and DEQ% argument blocks. The area in which the status is to be returned should be three times as long as the number of locks specified in the argument block.

On successful execution of the ENQC% call, the current status of each lock specified is returned as a three-word entry. This three-word entry has the following format.


         !=======================================================!
         !        Flag bits indicating status of lock            !
         !-------------------------------------------------------!
         !                   36-bit time stamp                   !
         !-------------------------------------------------------!
         !         Reserved          !        Request ID         !
         !=======================================================!

Table 6-6 describes the flag bits that can be used in a ENQC% call.

Table 6-6: ENQC% Flag Bits
BitSymbolMeaning
0 EN%QCE An error has occurred in the corresponding lock request. Bits 18-35 contain the appropriate error code.
1 EN%QCO The process issuing the ENQC% call is the owner of this lock.
2 EN%QCQ The process issuing the ENQC% call is in the queue waiting for this resource. This bit will be on when EN%QCO is on because a request remains in the queue until a DEQ% call is given.
3 EN%QCX The lock has been allocated for exclusive ownership. When this bit is off, there is no way of determining the number of sharers of the resource.
4 EN%QCB The process issuing the ENQC% call is in the queue waiting for exclusive ownership to the resource. This bit will be off if EN%QCQ is off.
5 EN%QCC This is a cluster-wide lock/request. This bit exists in both a lock-block and a q-block.
6 EN%QCN No future vote is required for this lock. This bit exists in a lock-block.
7 EN%QCS This lock requires a scheduling pass.
8 Reserved for Digital
9-17 EN%LVL The level number of the resource.
18-35 EN%JOB The number of the job that owns the lock. This value may be a job number on another system within the cluster. For locks with shared ownership, this value will be the job number of one of the owners. However, this value will be the current job's number if the current job is one of the owners. If this lock is not owned, the value is -1. If EN%QCE is on, this field contains the appropriate error code.

The 36-bit time stamp indicates the last time a process locked the resource. The time is in the universal date-time standard. If no one currently has a lock on the resource, this word is zero.

The request ID returned in the right half of the third word is either the request ID of the current process if that process is in the queue or the request ID of the owner of the lock.

6.5 Sharer groups

Processes can specify the sharing of resources by using sharer group numbers (refer to Section 6.4.1.2). The use of sharer groups restricts the ownership for a resource to a set of processes smaller than the set for shared ownership but larger than the set for exclusive ownership.

Sharer group number 0 is used to indicate the group of all cooperating processes of the resource. This group number is assumed when no group is specified in the ENQ% call. To restrict use of the resource, a group number other than 0 must be explicitly specified in the call.

Consider the following example. The resource is the WRITE operation on a file. There are four types of uses of this resource as shown in Figure 6-2.

            -----------------------------------------------
            |\            |              |                |
            | \   Process'|              |                |
            |  \  Own Use |              |                |
            |   \ of the  |              |                |
            |    \Resource|              | Not Allowed    |
            |     \       | Write        | to Write       |
            |      \      |              |                |
            |       \     |              |                |
            | Other  \    |              |                |
            | Process'\   |              |                |
            | Use of   \  |              |                |
            | Resource  \ |              |                |
            |            \|              |                |
            |-------------|--------------|----------------|
            |             | 1            | 2              |
            | Write       |              |                |
            |             | Shared,      | No Need to Use |
            |             | Group 0      | ENQ/DEQ        |
            |-------------|--------------|----------------|
            |             | 3            | 4              |
            | Not Allowed |              |                |
            | to Write    | Exclusive    | Shared,        |
            |             |              | Group 1        |
            -----------------------------------------------
Figure 6-2: Use of Sharer Groups

In block 1 of the figure, the process owning the lock wishes to allow all cooperating processes to also lock the resource (that is, to perform the WRITE operation). Therefore, in the ENQ% call, the process specifies the resource can be locked by all cooperating processes. In block 2 of the figure, the process does not plan on locking the resource and does not care if other processes lock it. Thus, there is no need for the process to use the ENQ/DEQ facility. In block 3 of the figure, the process desires to lock the resource exclusively and does not want other processes to lock it. Thus, the process obtains exclusive ownership for the resource. In block 4 of the figure, the process does not want to lock the resource immediately but also does not want other processes to lock it because it soon plans to request a lock on the resource. If the process were the only one requesting this type of use, exclusive ownership would be sufficient, because the resource would be unavailable to others as long as the process owned the lock. However, if other processes desire this same type of use, exclusive ownership is not sufficient, because once one process releases the lock, another process with a different type of use could obtain its own lock. Thus, in this example, sharer group 1 is defined to include all processes with the same type of use (that is, all processes who do not want to lock the resource immediately but also do not want other processes to lock it). This elimates the problem of another user obtaining the resource for a different type of use.

Sharer group 0 should be sufficient for most uses of the ENQ/DEQ facility. Additional groups should only be needed in those situations where a subset of the cooperating processes must have a specific use of a resource, as in the above example.

6.6 Avoiding deadly embraces

Processes can interact in many undesirable ways if improper communication occurs among the processes or if resources are incorrectly shared. An example of one undesirable situation is the occurrence of a deadly embrace: when two processes are waiting for each other to complete but neither one can gain access to the resource it needs for completion. This situation can be avoided when processes consider the following guidelines.

  1. Processes should request resources at the time they need them. If possible, processes should request resources one at a time and release each resource before requesting the next one.
  2. Processes should request shared ownership whenever possible. However, the process should not request shared ownership if it plans on modifying the resource.
  3. When a process needs more than one resource, it should request these resources in one ENQ% call instead of multiple calls for each resource. The process should also release the entire set of resources at once with a single DEQ% call.
  4. When the use of one resource depends on the use of a second one, the process should define the two resources as one in the ENQ% and DEQ% calls. However, there is no protection of the resources if they are also requested separately.
  5. Occasionally processes use a set of resources and require a lock on the second resource while retaining the lock on the first. In this case, the order in which the locks are obtained should be the same for all users of the set of resources. The same ordering of locks is accomplished by the processes assigning level numbers to each resource. The requirements that processes request resources in ascending numerical order and that all processes use the same level number for a specific resource ensure that a deadly embrace situation will not occur.